view src/net/sourceforge/jsocks/UDPRelayServer.java @ 412:057854c77217
wait for monitor socket to be created
author
Carl Byington <carl@five-ten-sg.com>
date
Fri, 24 Oct 2014 17:49:50 -0700 (2014-10-25)
parents
205ee2873330
children
line source
+ − 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);
+ − }
+ − }
+ − }