tor-android/src/com/runjva/sourceforge/jsocks/protocol/SocksServerSocket.java

239 lines
5.9 KiB
Java

package com.runjva.sourceforge.jsocks.protocol;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
/**
* SocksServerSocket allows to accept connections from one particular host
* through the SOCKS4 or SOCKS5 proxy.
*/
public class SocksServerSocket extends ServerSocket {
// Data members
protected SocksProxyBase proxy;
protected String localHost;
protected InetAddress localIP;
protected int localPort;
boolean doing_direct = false;
InetAddress remoteAddr;
/**
* Creates ServerSocket capable of accepting one connection through the
* firewall, uses default Proxy.
*
* @param host
* Host from which the connection should be recieved.
*@param port
* Port number of the primary connection.
*/
public SocksServerSocket(String host, int port) throws SocksException,
UnknownHostException, IOException {
this(SocksProxyBase.defaultProxy, host, port);
}
/**
*Creates ServerSocket capable of accepting one connection through the
* firewall, uses given proxy.
*
* @param p
* Proxy object to use.
*@param host
* Host from which the connection should be recieved.
*@param port
* Port number of the primary connection.
*/
public SocksServerSocket(SocksProxyBase p, String host, int port)
throws SocksException, UnknownHostException, IOException {
super(0);
if (p == null) {
throw new SocksException(SocksProxyBase.SOCKS_NO_PROXY);
}
// proxy=p;
proxy = p.copy();
if (proxy.isDirect(host)) {
remoteAddr = InetAddress.getByName(host);
proxy = null;
doDirect();
} else {
processReply(proxy.bind(host, port));
}
}
/**
* Creates ServerSocket capable of accepting one connection through the
* firewall, uses default Proxy.
*
* @param ip
* Host from which the connection should be recieved.
*@param port
* Port number of the primary connection.
*/
public SocksServerSocket(InetAddress ip, int port) throws SocksException,
IOException {
this(SocksProxyBase.defaultProxy, ip, port);
}
/**
*Creates ServerSocket capable of accepting one connection through the
* firewall, uses given proxy.
*
* @param p
* Proxy object to use.
*@param ip
* Host from which the connection should be recieved.
*@param port
* Port number of the primary connection.
*/
public SocksServerSocket(SocksProxyBase p, InetAddress ip, int port)
throws SocksException, IOException {
super(0);
if (p == null) {
throw new SocksException(SocksProxyBase.SOCKS_NO_PROXY);
}
this.proxy = p.copy();
if (proxy.isDirect(ip)) {
remoteAddr = ip;
doDirect();
} else {
processReply(proxy.bind(ip, port));
}
}
/**
* Accepts the incoming connection.
*/
public Socket accept() throws IOException {
Socket s;
if (!doing_direct) {
if (proxy == null) {
return null;
}
final ProxyMessage msg = proxy.accept();
s = msg.ip == null ? new SocksSocket(msg.host, msg.port, proxy)
: new SocksSocket(msg.ip, msg.port, proxy);
// Set timeout back to 0
proxy.proxySocket.setSoTimeout(0);
if (ProxyServer.vpnService != null)
ProxyServer.vpnService.protect(proxy.proxySocket);
} else { // Direct Connection
// Mimic the proxy behaviour,
// only accept connections from the speciefed host.
while (true) {
s = super.accept();
if (s.getInetAddress().equals(remoteAddr)) {
// got the connection from the right host
// Close listenning socket.
break;
} else {
s.close(); // Drop all connections from other hosts
}
}
}
proxy = null;
// Return accepted socket
return s;
}
/**
* Closes the connection to proxy if socket have not been accepted, if the
* direct connection is used, closes direct ServerSocket. If the client
* socket have been allready accepted, does nothing.
*/
public void close() throws IOException {
super.close();
if (proxy != null) {
proxy.endSession();
}
proxy = null;
}
/**
* Get the name of the host proxy is using to listen for incoming
* connection.
* <P>
* Usefull when address is returned by proxy as the hostname.
*
* @return the hostname of the address proxy is using to listen for incoming
* connection.
*/
public String getHost() {
return localHost;
}
/**
* Get address assigned by proxy to listen for incomming connections, or the
* local machine address if doing direct connection.
*/
public InetAddress getInetAddress() {
if (localIP == null) {
try {
localIP = InetAddress.getByName(localHost);
} catch (final UnknownHostException e) {
return null;
}
}
return localIP;
}
/**
* Get port assigned by proxy to listen for incoming connections, or the
* port chosen by local system, if accepting directly.
*/
public int getLocalPort() {
return localPort;
}
/**
* Set Timeout.
*
* @param timeout
* Amount of time in milliseconds, accept should wait for
* incoming connection before failing with exception. Zero
* timeout implies infinity.
*/
public void setSoTimeout(int timeout) throws SocketException {
super.setSoTimeout(timeout);
if (!doing_direct) {
proxy.proxySocket.setSoTimeout(timeout);
}
}
// Private Methods
// ////////////////
private void processReply(ProxyMessage reply) throws SocksException {
localPort = reply.port;
/*
* If the server have assigned same host as it was contacted on it might
* return an address of all zeros
*/
if (reply.host.equals("0.0.0.0")) {
localIP = proxy.proxyIP;
localHost = localIP.getHostName();
} else {
localHost = reply.host;
localIP = reply.ip;
}
}
private void doDirect() {
doing_direct = true;
localPort = super.getLocalPort();
localIP = super.getInetAddress();
localHost = localIP.getHostName();
}
}