📄 sockssocketimpl.java
字号:
package com.jeeva.chatclient;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.Socket;
import java.net.SocketImpl;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Properties;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.io.FileDescriptor;
import java.net.SocketAddress;
/**
*
* SocksSocketImpl: A Socket implementation class support SOCKS4A & SOCKS5
*
* @version 1.1a,
*
* @author Jeeva S (vavjeeva@yahoo.com)
*
*
*/
/**
* SocksSocketImpl: A Socket Implementation class support SOCKS4A & SOCKS5
*
* <A HREF="http://www.socks.nec.com/socksprot.html">SOCKS References:</A><BR>
* <DD>[1] <A HREF="http://www.socks.nec.com/protocol/socks4.protocol">SOCKS 4 Protocol</A><BR>
* <DD>[2] <A HREF="http://www.socks.nec.com/protocol/socks4a.protocol">SOCKS 4A: A Simple Extension to SOCKS 4 Protocol</A><BR>
* <DD>[3] <A HREF="//http://www.socks.nec.com/rfc/rfc1928.txt">RFC1928 SOCKS Protocol Version 5</A><BR>
* <DD>[4] <A HREF="//http://www.socks.nec.com/rfc/rfc1929.txt">RFC1929 Username/Password Authentication for SOCKS V5</A></DL></DD>
* <DD>[5] <A HREF="//http://www.socks.nec.com/draft/draft-ietf-aft-socks-pro-v5-04.txt">SOCKS Protocol Version 5 (22 Feb 1999)</A></DL></DD>
*/
class SocksSocketImpl extends SocketImpl implements SocksSocketConstants
{
/*
* a boolean indicating whether this is a stream socket or a datagram socket.
* If the stream argument is true, this creates a stream socket. If the stream argument is
* false, it creates a datagram socket.
*/
private boolean stream=true;
/*
* The Socket between local host and SOCKS proxy server when there is a proxy server.
* The Socket between local host and remote host when there isn't a proxy server.
*/
private Socket clientSocket=null;
/*
* the direct DatagramSocket communication between local host and remote host.
*/
private DatagramSocket clientDatagramSocket=null;
/*
* The IP address of the SOCKS proxy server.
*/
private InetAddress proxyAddress=null;
/**
* Returns the value of this socket's <code>proxy address</code> field.
*
* @return the value of this socket's <code>proxy address</code> field.
* @see java.net.SocketImpl#address
*/
protected InetAddress getProxyAddress()
{
return proxyAddress;
}
/*
* The port number on the SOCKS proxy serer.
*/
private int proxyPort=SOCKS_PORT;
/**
* Returns the value of this socket's <code>proxy port</code> field.
*
* @return the value of this socket's <code>proxy port</code> field.
*/
protected int getProxyPort()
{
return proxyPort;
}
/*
* The IP address of the local end of this socket.
* instance variable for SO_BINDADDR
*/
/*
*/
private InetAddress localAddress=null;
/**
* Returns the value of this socket's <code>proxy address</code> field.
*
* @return the value of this socket's <code>proxy address</code> field.
* @see java.net.SocketImpl#address
*/
protected InetAddress getLocalAddress()
{
return localAddress;
}
/**
* Returns the value of this socket's <code>localport</code> field.
*
* @return the value of this socket's <code>localport</code> field.
* @see java.net.SocketImpl#localport
*/
protected int getLocalPort()
{
return localport;
}
/**
* Returns the value of this socket's <code>address</code> field.
*
* @return the value of this socket's <code>address</code> field.
* @see java.net.SocketImpl#address
*/
protected InetAddress getInetAddress()
{
return address;
}
/**
* Returns the value of this socket's <code>port</code> field.
*
* @return the value of this socket's <code>port</code> field.
* @see java.net.SocketImpl#port
*/
protected int getPort()
{
return port;
}
/*
* An ojbect for output buffer
*/
private ByteArrayOutputStream outputBuffer;
protected SocksSocketImpl(){}
protected SocksSocketImpl(boolean stream)
{
this.stream=stream;
}
protected void sendUrgentData(int data)
{
/*********Do Nothing ********/
}
protected SocksSocketImpl(String proxyHost,int proxyPort)throws java.net.UnknownHostException
{
this(InetAddress.getByName(proxyHost),proxyPort,null,true);
}
protected SocksSocketImpl(InetAddress proxyAddress,int proxyPort,Properties properties)
{
this(proxyAddress,proxyPort,properties,true);
}
protected SocksSocketImpl(InetAddress proxyAddress,int proxyPort,Properties properties,boolean stream)
{
this.proxyAddress=proxyAddress;
this.proxyPort=proxyPort;
this.stream=stream;
if(proxyAddress!=null)
outputBuffer= new ByteArrayOutputStream(1024);
if(properties!=null)
initProperties(properties);
if(!stream)//Set version to SOCKS_VERSION_5 since SOCKS_VERSION_4A cann't support datagram socket
version=SOCKS_VERSION_5;
}
private void initProperties(Properties properties)
{
String value=properties.getProperty(SocksSocket.USERNAME);
if(value!=null)username=value.getBytes();
value=properties.getProperty(SocksSocket.PASSWORD);
if(value!=null)password=value.getBytes();
value=properties.getProperty(SocksSocket.VERSION);
if(value!=null)
{
try
{
version=Integer.parseInt(value)==SOCKS_VERSION_5?SOCKS_VERSION_5:SOCKS_VERSION_4A;
}
catch(NumberFormatException nfe){}
}
}
/**
* Creates either a stream or a datagram socket.
* Creates a socket with a boolean that specifies whether this
* is a stream socket (true) or an unconnected UDP socket (false).
*
* @param stream if <code>true</code>, create a stream socket;
* otherwise, create a datagram socket.
* @exception IOException if an I/O error occurs while creating the
* socket.
*/
protected void create(boolean stream) throws IOException
{
//Nothing since it's always a socket connection between local host and proxy server.
}
/**
* Binds this socket to the specified port number flag the specified host.
*
* @param address the IP address of the specified host.
* @param port the port number.
* @exception IOException if an I/O error occurs when binding this socket.
*/
protected void bind(InetAddress address, int port)throws IOException
{
this.localAddress=address;
this.localport=port;
}
/**
* Connects this stream socket to the specified port flag the named host.
*
* @param host the name of the remote host.
* @param port the port number.
* @exception IOException if an I/O error occurs when connecting to the
* remote host.
*/
protected void connect(String host, int port)throws UnknownHostException, IOException
{
try
{
if(proxyAddress==null)//Direct Socket Connection
{
clientSocket=new Socket(InetAddress.getByName(host),port,localAddress,localport);
localAddress=clientSocket.getLocalAddress();
}
else//SOCKS Connection
{
initRemoteHost(host,port);
doSOCKSConnect();
}
}
catch (IOException e)
{
close();
throw e;
}
}
/**
* Connects this stream or datagram socket to the specified port number flag the specified host.
*
* @param address the IP address of the remote host.
* @param port the port number.
* @exception IOException if an I/O error occurs when attempting a
* connection.
*/
protected void connect(InetAddress address, int port) throws IOException
{
try
{
if(stream)// Stream socket connection
{
boolean isConnected=clientSocket!=null;
if(isConnected)return;
if(proxyAddress==null)// Direct Stream Socket Connection
{
clientSocket=new Socket(address,port,localAddress,localport);
localAddress=clientSocket.getLocalAddress();
localport=clientSocket.getLocalPort();
}
else//SOCKS Connection
{
initRemoteHost(address,port);
doSOCKSConnect();
}
}
else//datagram socket connection
{
this.address=address;
this.port=port;
boolean isConnected=clientDatagramSocket!=null;
if(!isConnected)
{
clientDatagramSocket=new DatagramSocket(localport,localAddress);
localAddress=clientDatagramSocket.getLocalAddress();
localport=clientDatagramSocket.getLocalPort();
}
if(proxyAddress==null)// Direct datagram socket connection
{
clientDatagramSocket.connect(address,port);
}
else//SOCKS Connection
{
initRemoteHost(address,port);
if(!isConnected)
doSOCKSConnect();
}
}
}
catch (IOException e)
{
close();
throw e;
}
}
protected void connect(SocketAddress address, int port) throws IOException
{
/**********Do Nothing **********/
}
/**
* Returns an input stream for this socket.
*
* @return a stream for reading from this socket.
* @exception IOException if an I/O error occurs when creating the
* input stream.
*/
protected synchronized InputStream getInputStream() throws IOException
{
if(clientSocket!=null)
return clientSocket.getInputStream();
else
throw new IOException("Error: Try to access an unconnected or closed Socks connection.");
}
/**
* Returns an output stream for this socket.
*
* @return an output stream for writing to this socket.
* @exception IOException if an I/O error occurs when creating the
* output stream.
*/
protected synchronized OutputStream getOutputStream() throws IOException
{
if(clientSocket!=null)
return clientSocket.getOutputStream();
else
throw new IOException("Error: Try to access an unconnected or closed Socks connection.");
}
/**
* Returns the number of bytes that can be read from this socket
* without blocking.
*
* @return the number of bytes that can be read from this socket
* without blocking.
* @exception IOException if an I/O error occurs when determining the
* number of bytes available.
*/
protected synchronized int available() throws IOException
{
return getInputStream().available();
}
/**
* Set the appropriate SOCKS version for the specific SOCKS proxy serer.
*/
private int version=SOCKS_VERSION_5;
/**
* Set username for the specific SOCKS proxy serer.
*/
private byte[] username=null;
/**
* Set password for the specific SOCKS proxy serer.
*/
private byte[] password=null;
/**
* Set the IP address and port number of the remote end of this socket.
*/private byte[] remoteHost=null;
private byte[] remotePort=null;
private byte[] remoteAddress=null;
private int remoteAddressType;
private void initRemoteHost(String host,int port)throws UnknownHostException
{
try
{
this.port = port;
remotePort=getPort(port);
remoteAddressType=IP_V4;
remoteHost=host.getBytes();
this.address= InetAddress.getByName(host);
remoteAddress=getAddress(address);
}
catch(Exception uhe)//Use it to catch security exception
// catch(UnknownHostException uhe)
{
switch(version)
{
case SOCKS_VERSION_4A:
remoteAddress=new byte[4];
//Such a destination IP address is inadmissible
// remoteAddress[0]=remoteAddress[1]=remoteAddress[2]=0;
remoteAddress[3]=(byte)0xFF;
break;
case SOCKS_VERSION_5:
remoteAddress=remoteHost;
remoteAddressType=DOMAINNAME;
break;
}
}
}
private void initRemoteHost(InetAddress address,int port)
{
this.address= address;
this.port = port;
remoteAddress=getAddress(address);
remotePort=getPort(port);
remoteAddressType=IP_V4;
}
private static final byte[] getAddress(InetAddress ia)
{
if(ia==null)
return new byte[4];
else
return ia.getAddress();
/* int addressIntegerValue=ia.hashCode();
byte[] address=new byte[4];
for(int i=3;i>=0;i--)
{
address[i]=(byte)(addressIntegerValue&0xFF);
addressIntegerValue>>>=8;
}
return address;*/
}
private static final byte[] getAddress(int addressType, byte[] b, int offset)
{
int length;
switch(addressType)
{
case DOMAINNAME:
length=b[offset];
offset++;
break;
case IP_V4:
length=4;
break;
// case IP_V6:
default://
length=16;
break;
}
byte[] address=new byte[length];
for(int i=0;i<length;i++,offset++)
address[i]=b[offset];
return address;
}
private static final byte[] getPort(int p)
{
byte[] port=new byte[2];
port[0]=(byte)((p>>>8)&0xFF);
port[1]=(byte)(p&0xFF);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -