/** * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite * contributors * * This file is part of EvoSuite. * * EvoSuite is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3.0 of the License, or * (at your option) any later version. * * EvoSuite is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ package org.evosuite.runtime.vnet; import java.util.ArrayDeque; import java.util.Queue; /** * Class used to simulate a bi-directional TCP socket connection between two hosts. * This class only handle the exchange of data between SUT and EvoSuite tests, and not * whether the connections are actually in place * * <p> * This class is thread-safe * * @author arcuri * */ public class NativeTcp { /* * Note: actual buffer sizes can be influenced by SO_SNDBUF and SO_RCVBUF socket options. * But those are just "hints" for the OS */ /** * The TCP buffer used locally by the SUT */ private final Queue<Byte> localBuffer; /** * The TCP buffer used by the EvoSuite tests to simulate a remote connection */ private final Queue<Byte> remoteBuffer; /** * Info on local (SUT) address/port */ private volatile EndPointInfo localEndPoint; /** * Info on remote (EvoSuite tests) address/port */ private final EndPointInfo remoteEndPoint; public NativeTcp(EndPointInfo localEndPoint, EndPointInfo remoteEndPoint){ if(remoteEndPoint==null){ throw new IllegalArgumentException("Remote end point cannot be null"); } this.localEndPoint = localEndPoint; //this can be null this.remoteEndPoint = remoteEndPoint; localBuffer = new ArrayDeque<>(); remoteBuffer = new ArrayDeque<>(); } public boolean isBound(){ return localEndPoint != null; } public void bind(EndPointInfo local) throws IllegalStateException{ if(isBound()){ throw new IllegalStateException("Connection is already bound"); } localEndPoint = local; } /** * Used by SUT to simulate sending of data to remote host */ public synchronized void writeToRemote(byte b){ //the data is directly added to remote buffer remoteBuffer.add(b); } /** * Read one byte from stream * * @return a value between 0 and 255 representing a byte, or -1 if stream is empty. * Note: in Java bytes are signed in -128,127, whereas here we need to return a unsigned * int representation */ public synchronized int readInSUTfromRemote(){ if(localBuffer.isEmpty()){ /* * Note: in TCP, a read operation on a empty buffer would be blocking */ return -1; } return localBuffer.poll() & 0xFF; } /** * Used by tests to simulate sending of data to the SUT opening a server connection * @param b */ public synchronized void writeToSUT(byte b){ localBuffer.add(b); } /** * Get the data sent by the SUT. * This would mainly be useful for assertion generation and * not the search. * * @return */ public synchronized int readInTestFromSUT(){ if(remoteBuffer.isEmpty()){ return -1; } return remoteBuffer.poll() & 0xFF; } /** * @return the amount of data sent by the remote host and that * has not been read yet by the local SUT */ public synchronized int getAmountOfDataInLocalBuffer(){ return localBuffer.size(); } /** * @return the amount of data sent by the SUT to the remote host */ public synchronized int getAmountOfDataInRemoteBuffer(){ return remoteBuffer.size(); } public EndPointInfo getLocalEndPoint() { return localEndPoint; } public EndPointInfo getRemoteEndPoint() { return remoteEndPoint; } }