All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.runtime.mock.java.net.MockSocket Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
/**
 * Copyright (C) 2010-2016 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 .
 */
package org.evosuite.runtime.mock.java.net;

import org.evosuite.runtime.mock.MockFramework;
import org.evosuite.runtime.mock.OverrideMock;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImplFactory;
import java.net.SocketOptions;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;


public class MockSocket extends Socket implements OverrideMock {
	
	private Object closeLock = new Object();

	private boolean created = false;
	private boolean bound = false;
	private boolean connected = false;
	private boolean closed = false;
	private boolean shutIn = false;
	private boolean shutOut = false;

	MockSocketImpl impl;


	//-------- constructors  ---------------------------

    /**
     * TODO rollback here would be very complicated, as would need to replicate every single
     * constructor code by reflection, as they have side-effects we cannot avoid
     */

	public MockSocket() {
		super();
        if(!MockFramework.isEnabled()){
            return;
        }
		setImpl();
	}

	public MockSocket(Proxy proxy) {
		// Create a copy of Proxy as a security measure
		if (proxy == null) {
			throw new IllegalArgumentException("Invalid Proxy");
		}
		
		Proxy p =  proxy; 
		//Note: not needed as only used in EvoSuiteSocket constructor
		//  == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);
		
		if (p.type() == Proxy.Type.SOCKS) {
			
			InetSocketAddress epoint = (InetSocketAddress) p.address();
			if (epoint.getAddress() != null) {
				checkAddress (epoint.getAddress(), "Socket");
			}

			impl = new EvoSuiteSocket(p); 
			impl.setSocket(this);
		} else {
			if (p == Proxy.NO_PROXY) {
				impl = new EvoSuiteSocket();
				impl.setSocket(this);
			} else
				throw new IllegalArgumentException("Invalid Proxy");
		}
	}


	protected MockSocket(MockSocketImpl impl) throws SocketException {
		super(impl);
        if(!MockFramework.isEnabled()){
            return;
        }
        this.impl = impl;
		if (impl != null) {
			this.impl.setSocket(this);
		}
	}


	public MockSocket(String host, int port)throws UnknownHostException, IOException {
		this(host != null ? new MockInetSocketAddress(host, port) :
			new MockInetSocketAddress(MockInetAddress.getByName(null), port),
			(SocketAddress) null, true);
	}


	public MockSocket(InetAddress address, int port) throws IOException {
		this(address != null ? new MockInetSocketAddress(address, port) : null,
				(SocketAddress) null, true);
	}


	public MockSocket(String host, int port, InetAddress localAddr,
			int localPort) throws IOException {
		this(host != null ? new MockInetSocketAddress(host, port) :
			new MockInetSocketAddress(MockInetAddress.getByName(null), port),
			new MockInetSocketAddress(localAddr, localPort), true);
	}


	public MockSocket(InetAddress address, int port, InetAddress localAddr,
			int localPort) throws IOException {
		this(address != null ? new MockInetSocketAddress(address, port) : null,
				new MockInetSocketAddress(localAddr, localPort), true);
	}



	public MockSocket(String host, int port, boolean stream) throws IOException {
		this(host != null ? new MockInetSocketAddress(host, port) :
			new MockInetSocketAddress(MockInetAddress.getByName(null), port),
			(SocketAddress) null, stream);
	}



	public MockSocket(InetAddress host, int port, boolean stream) throws IOException {
		this(host != null ? new MockInetSocketAddress(host, port) : null,
				new MockInetSocketAddress(0), stream);
	}

	private MockSocket(SocketAddress address, SocketAddress localAddr,
			boolean stream) throws IOException {
		setImpl();

		// backward compatibility
		if (address == null)
			throw new NullPointerException();

		try {
			createImpl(stream);
			if (localAddr != null)
				bind(localAddr);
			if (address != null)
				connect(address);
		} catch (IOException e) {
			close();
			throw e;
		}
	}


	//---------------------------------------------------------------

	protected void createImpl(boolean stream) throws SocketException {
		if (impl == null)
			setImpl();
		try {
			impl.create(stream);
			created = true;
		} catch (IOException e) {
			throw new SocketException(e.getMessage());
		}
	}

	
	/*
	    in superclass it is package level, so it is not overriden
	 */
	protected void setImpl() {
		impl = new EvoSuiteSocket();
		impl.setSocket(this);
	}



	protected MockSocketImpl getImpl() throws SocketException {
		if (!created)
			createImpl(true);
		return impl;
	}

	/*
	 *  note: super postAccept is final.
	 *  but it is called only in ServerSocket
	 */
	protected void _postAccept() {
		connected = true;
		created = true;
		bound = true;
	}

	protected void setCreated() {
		created = true;
	}

	protected void setBound() {
		bound = true;
	}

	protected void setConnected() {
		connected = true;
	}
	
	//--------   public methods  ----------------
	
	@Override
	public void connect(SocketAddress endpoint) throws IOException {
		connect(endpoint, 0);
	}


	@Override
	public void connect(SocketAddress endpoint, int timeout) throws IOException {
		if (endpoint == null)
			throw new IllegalArgumentException("connect: The address can't be null");

		if (timeout < 0)
			throw new IllegalArgumentException("connect: timeout can't be negative");

		if (isClosed())
			throw new SocketException("Socket is closed");

		if (isConnected())
			throw new SocketException("already connected");

		if (!(endpoint instanceof InetSocketAddress))
			throw new IllegalArgumentException("Unsupported address type");

		InetSocketAddress epoint = (InetSocketAddress) endpoint;
		InetAddress addr = epoint.getAddress();
		checkAddress(addr, "connect");

		if (!created)
			createImpl(true);

        impl.connect(epoint, timeout);

        connected = true;
		/*
		 * If the socket was not bound before the connect, it is now because
		 * the kernel will have picked an ephemeral port & a local address
		 */
		bound = true;
	}


	@Override
	public void bind(SocketAddress bindpoint) throws IOException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		if (isBound())
			throw new SocketException("Already bound");

		if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress)))
			throw new IllegalArgumentException("Unsupported address type");
		InetSocketAddress epoint = (InetSocketAddress) bindpoint;
		if (epoint != null && epoint.isUnresolved())
			throw new SocketException("Unresolved address");
		if (epoint == null) {
			epoint = new MockInetSocketAddress(0);
		}
		InetAddress addr = epoint.getAddress();
		int port = epoint.getPort();
		checkAddress (addr, "bind");
		getImpl().bind (addr, port);
		bound = true;
	}

	private void checkAddress (InetAddress addr, String op) {
		if (addr == null) {
			return;
		}

		if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
			throw new IllegalArgumentException(op + ": invalid address type");
		}
	}



	@Override
	public InetAddress getInetAddress() {
		if (!isConnected())
			return null;
		try {
			return getImpl().getInetAddress();
		} catch (SocketException e) {
		}
		return null;
	}


	@Override
	public InetAddress getLocalAddress() {

		if(! MockFramework.isEnabled()){
			return super.getLocalAddress();
		}
		
		if (!isBound()){
			return MockInetAddress.anyLocalAddress();
		}
		
		InetAddress in = null;
		try {
			in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
			if (in.isAnyLocalAddress()) {
				in = MockInetAddress.anyLocalAddress();
			}
		} catch (SecurityException e) {
			in = MockInetAddress.getLoopbackAddress();
		} catch (Exception e) {			
			in = MockInetAddress.anyLocalAddress();
		}
		return in;
	}

	@Override
	public int getPort() {
		if (!isConnected())
			return 0;
		try {
			return getImpl().getPort();
		} catch (SocketException e) {
			// Shouldn't happen as we're connected
		}
		return -1;
	}


	@Override
	public int getLocalPort() {
		if (!isBound())
			return -1;
		try {
			return getImpl().getLocalPort();
		} catch(SocketException e) {
			// shouldn't happen as we're bound
		}
		return -1;
	}


	@Override
	public SocketAddress getRemoteSocketAddress() {
		if (!isConnected())
			return null;
		return new MockInetSocketAddress(getInetAddress(), getPort());
	}


	@Override
	public SocketAddress getLocalSocketAddress() {
		if (!isBound())
			return null;
		return new MockInetSocketAddress(getLocalAddress(), getLocalPort());
	}


	@Override
	public SocketChannel getChannel() {
		return null; //TODO check it
	}


	@Override
	public InputStream getInputStream() throws IOException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		if (!isConnected())
			throw new SocketException("Socket is not connected");
		if (isInputShutdown())
			throw new SocketException("Socket input is shutdown");
		return impl.getInputStream();
	}


	@Override
	public OutputStream getOutputStream() throws IOException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		if (!isConnected())
			throw new SocketException("Socket is not connected");
		if (isOutputShutdown())
			throw new SocketException("Socket output is shutdown");
		return impl.getOutputStream();
	}

	@Override
	public void setTcpNoDelay(boolean on) throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
	}


	@Override
	public boolean getTcpNoDelay() throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue();
	}


	@Override
	public void setSoLinger(boolean on, int linger) throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		if (!on) {
			getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on));
		} else {
			if (linger < 0) {
				throw new IllegalArgumentException("invalid value for SO_LINGER");
			}
			if (linger > 65535)
				linger = 65535;
			getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
		}
	}


	@Override
	public int getSoLinger() throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		Object o = getImpl().getOption(SocketOptions.SO_LINGER);
		if (o instanceof Integer) {
			return ((Integer) o).intValue();
		} else {
			return -1;
		}
	}


	@Override
	public void sendUrgentData (int data) throws IOException  {
		if (!getImpl().supportsUrgentData ()) {
			throw new SocketException ("Urgent data not supported");
		}
		getImpl().sendUrgentData (data);
	}


	@Override
	public void setOOBInline(boolean on) throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
	}


	@Override
	public boolean getOOBInline() throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue();
	}


	@Override
	public synchronized void setSoTimeout(int timeout) throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		if (timeout < 0)
			throw new IllegalArgumentException("timeout can't be negative");

		getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
	}


	@Override
	public synchronized int getSoTimeout() throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
		if (o instanceof Integer) {
			return ((Integer) o).intValue();
		} else {
			return 0;
		}
	}

	@Override
	public synchronized void setSendBufferSize(int size) throws SocketException{
		if (!(size > 0)) {
			throw new IllegalArgumentException("negative send size");
		}
		if (isClosed())
			throw new SocketException("Socket is closed");
		getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
	}

	@Override
	public synchronized int getSendBufferSize() throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		int result = 0;
		Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
		if (o instanceof Integer) {
			result = ((Integer)o).intValue();
		}
		return result;
	}


	@Override
	public synchronized void setReceiveBufferSize(int size) throws SocketException{
		if (size <= 0) {
			throw new IllegalArgumentException("invalid receive size");
		}
		if (isClosed())
			throw new SocketException("Socket is closed");
		getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
	}


	@Override
	public synchronized int getReceiveBufferSize() throws SocketException{
		if (isClosed())
			throw new SocketException("Socket is closed");
		int result = 0;
		Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
		if (o instanceof Integer) {
			result = ((Integer)o).intValue();
		}
		return result;
	}


	@Override
	public void setKeepAlive(boolean on) throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
	}


	@Override
	public boolean getKeepAlive() throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue();
	}


	@Override
	public void setTrafficClass(int tc) throws SocketException {
		if (tc < 0 || tc > 255)
			throw new IllegalArgumentException("tc is not in range 0 -- 255");

		if (isClosed())
			throw new SocketException("Socket is closed");
		getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
	}

	@Override
	public int getTrafficClass() throws SocketException {
		return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();
	}

	@Override
	public void setReuseAddress(boolean on) throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
	}

	@Override
	public boolean getReuseAddress() throws SocketException {
		if (isClosed())
			throw new SocketException("Socket is closed");
		return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
	}

	
	@Override
	public synchronized void close() throws IOException {
		synchronized(closeLock) {
			if (isClosed())
				return;
			if (created)
				impl.close();
			closed = true;
		}
	}

	@Override
	public void shutdownInput() throws IOException
	{
		if (isClosed())
			throw new SocketException("Socket is closed");
		if (!isConnected())
			throw new SocketException("Socket is not connected");
		if (isInputShutdown())
			throw new SocketException("Socket input is already shutdown");
		getImpl().shutdownInput();
		shutIn = true;
	}

	@Override
	public void shutdownOutput() throws IOException
	{
		if (isClosed())
			throw new SocketException("Socket is closed");
		if (!isConnected())
			throw new SocketException("Socket is not connected");
		if (isOutputShutdown())
			throw new SocketException("Socket output is already shutdown");
		getImpl().shutdownOutput();
		shutOut = true;
	}

	@Override
	public String toString() {
		try {
			if (isConnected())
				return "Socket[addr=" + getImpl().getInetAddress() +
						",port=" + getImpl().getPort() +
						",localport=" + getImpl().getLocalPort() + "]";
		} catch (SocketException e) {
		}
		return "Socket[unconnected]";
	}

	// -------- boolean methods --------
	
	@Override
	public boolean isConnected() {
		return connected;
	}

	@Override
	public boolean isBound() {
		return bound;
	}

	@Override
	public boolean isClosed() {
		synchronized(closeLock) {
			return closed;
		}
	}

	@Override
	public boolean isInputShutdown() {
		return shutIn;
	}

	@Override
	public boolean isOutputShutdown() {
		return shutOut;
	}

	//---------------------------------------
	
	//private static SocketImplFactory factory = null;

	public static synchronized void setSocketImplFactory(SocketImplFactory fac) throws IOException{

		/*
		 * Having a factory would be very tricky, as returned instances are not of type MockSocketImpl.
		 * Even if where to change "impl" into SocketImpl, then we wouldn't be able to call all its package
		 * level methods used in this class. We could use reflection though.
		 * Anyway, as this method is never used in SF110, we just throw a legal exception 
		 */
		throw new IOException("Setting of factory is not supported in virtual network");


		/*
		if (factory != null) {
			throw new SocketException("factory already defined");
		}
		SecurityManager security = System.getSecurityManager();
		if (security != null) {
			security.checkSetFactory();
		}
		factory = fac;
		 */
	}

	@Override
	public void setPerformancePreferences(int connectionTime,
			int latency,
			int bandwidth){
		super.setPerformancePreferences(connectionTime, latency, bandwidth);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy