diff app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java @ 438:d29cce60f393

migrate from Eclipse to Android Studio
author Carl Byington <carl@five-ten-sg.com>
date Thu, 03 Dec 2015 11:23:55 -0800
parents src/net/sourceforge/jsocks/UDPRelayServer.java@205ee2873330
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/java/net/sourceforge/jsocks/UDPRelayServer.java	Thu Dec 03 11:23:55 2015 -0800
@@ -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 CProxy 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);
+       }
+    }
+}