aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java')
-rw-r--r--app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java212
1 files changed, 212 insertions, 0 deletions
diff --git a/app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java b/app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java
new file mode 100644
index 0000000..dfa6016
--- /dev/null
+++ b/app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java
@@ -0,0 +1,212 @@
+package net.sourceforge.jsocks;
+import net.sourceforge.jsocks.server.*;
+import java.net.*;
+import java.io.*;
+
+/**
+ UDP Relay server, used by ProxyServer to perform udp forwarding.
+*/
+class UDPRelayServer implements Runnable{
+
+
+ DatagramSocket client_sock;
+ DatagramSocket remote_sock;
+
+ Socket controlConnection;
+
+ int relayPort;
+ InetAddress relayIP;
+
+ Thread pipe_thread1,pipe_thread2;
+ Thread master_thread;
+
+ ServerAuthenticator auth;
+
+ long lastReadTime;
+
+ static PrintStream log = null;
+ static Proxy proxy = null;
+ static int datagramSize = 0xFFFF;//64K, a bit more than max udp size
+ static int iddleTimeout = 180000;//3 minutes
+
+
+ /**
+ Constructs UDP relay server to communicate with client
+ on given ip and port.
+ @param clientIP Address of the client from whom datagrams
+ will be recieved and to whom they will be forwarded.
+ @param clientPort Clients port.
+ @param master_thread Thread which will be interrupted, when
+ UDP relay server stoppes for some reason.
+ @param controlConnection Socket which will be closed, before
+ interrupting the master thread, it is introduced due to a bug
+ in windows JVM which does not throw InterruptedIOException in
+ threads which block in I/O operation.
+ */
+ public UDPRelayServer(InetAddress clientIP,int clientPort,
+ Thread master_thread,
+ Socket controlConnection,
+ ServerAuthenticator auth)
+ throws IOException{
+ this.master_thread = master_thread;
+ this.controlConnection = controlConnection;
+ this.auth = auth;
+
+ client_sock = new Socks5DatagramSocket(true,auth.getUdpEncapsulation(),
+ clientIP,clientPort);
+ relayPort = client_sock.getLocalPort();
+ relayIP = client_sock.getLocalAddress();
+
+ if(relayIP.getHostAddress().equals("0.0.0.0"))
+ relayIP = InetAddress.getLocalHost();
+
+ if(proxy == null)
+ remote_sock = new DatagramSocket();
+ else
+ remote_sock = new Socks5DatagramSocket(proxy,0,null);
+ }
+
+
+//Public methods
+/////////////////
+
+
+ /**
+ Sets the timeout for UDPRelay server.<br>
+ Zero timeout implies infinity.<br>
+ Default timeout is 3 minutes.
+ */
+
+ static public void setTimeout(int timeout){
+ iddleTimeout = timeout;
+ }
+
+
+ /**
+ Sets the size of the datagrams used in the UDPRelayServer.<br>
+ Default size is 64K, a bit more than maximum possible size of the
+ datagram.
+ */
+ static public void setDatagramSize(int size){
+ datagramSize = size;
+ }
+
+ /**
+ Port to which client should send datagram for association.
+ */
+ public int getRelayPort(){
+ return relayPort;
+ }
+ /**
+ IP address to which client should send datagrams for association.
+ */
+ public InetAddress getRelayIP(){
+ return relayIP;
+ }
+
+ /**
+ Starts udp relay server.
+ Spawns two threads of execution and returns.
+ */
+ public void start() throws IOException{
+ remote_sock.setSoTimeout(iddleTimeout);
+ client_sock.setSoTimeout(iddleTimeout);
+
+ log("Starting UDP relay server on "+relayIP+":"+relayPort);
+ log("Remote socket "+remote_sock.getLocalAddress()+":"+
+ remote_sock.getLocalPort());
+
+ pipe_thread1 = new Thread(this,"pipe1");
+ pipe_thread2 = new Thread(this,"pipe2");
+
+ lastReadTime = System.currentTimeMillis();
+
+ pipe_thread1.start();
+ pipe_thread2.start();
+ }
+
+ /**
+ Stops Relay server.
+ <p>
+ Does not close control connection, does not interrupt master_thread.
+ */
+ public synchronized void stop(){
+ master_thread = null;
+ controlConnection = null;
+ abort();
+ }
+
+//Runnable interface
+////////////////////
+ public void run(){
+ try{
+ if(Thread.currentThread().getName().equals("pipe1"))
+ pipe(remote_sock,client_sock,false);
+ else
+ pipe(client_sock,remote_sock,true);
+ }catch(IOException ioe){
+ }finally{
+ abort();
+ log("UDP Pipe thread "+Thread.currentThread().getName()+" stopped.");
+ }
+
+ }
+
+//Private methods
+/////////////////
+ private synchronized void abort(){
+ if(pipe_thread1 == null) return;
+
+ log("Aborting UDP Relay Server");
+
+ remote_sock.close();
+ client_sock.close();
+
+ if(controlConnection != null)
+ try{ controlConnection.close();} catch(IOException ioe){}
+
+ if(master_thread!=null) master_thread.interrupt();
+
+ pipe_thread1.interrupt();
+ pipe_thread2.interrupt();
+
+ pipe_thread1 = null;
+ }
+
+
+ static private void log(String s){
+ if(log != null){
+ log.println(s);
+ log.flush();
+ }
+ }
+
+ private void pipe(DatagramSocket from,DatagramSocket to,boolean out)
+ throws IOException{
+ byte[] data = new byte[datagramSize];
+ DatagramPacket dp = new DatagramPacket(data,data.length);
+
+ while(true){
+ try{
+ from.receive(dp);
+ lastReadTime = System.currentTimeMillis();
+
+ if(auth.checkRequest(dp,out))
+ to.send(dp);
+
+ }catch(UnknownHostException uhe){
+ log("Dropping datagram for unknown host");
+ }catch(InterruptedIOException iioe){
+ //log("Interrupted: "+iioe);
+ //If we were interrupted by other thread.
+ if(iddleTimeout == 0) return;
+
+ //If last datagram was received, long time ago, return.
+ long timeSinceRead = System.currentTimeMillis() - lastReadTime;
+ if(timeSinceRead >= iddleTimeout -100) //-100 for adjustment
+ return;
+ }
+ dp.setLength(data.length);
+ }
+ }
+}