comparison 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
comparison
equal deleted inserted replaced
437:208b31032318 438:d29cce60f393
1 package net.sourceforge.jsocks;
2 import net.sourceforge.jsocks.server.*;
3 import java.net.*;
4 import java.io.*;
5
6 /**
7 UDP Relay server, used by ProxyServer to perform udp forwarding.
8 */
9 class UDPRelayServer implements Runnable{
10
11
12 DatagramSocket client_sock;
13 DatagramSocket remote_sock;
14
15 Socket controlConnection;
16
17 int relayPort;
18 InetAddress relayIP;
19
20 Thread pipe_thread1,pipe_thread2;
21 Thread master_thread;
22
23 ServerAuthenticator auth;
24
25 long lastReadTime;
26
27 static PrintStream log = null;
28 static CProxy proxy = null;
29 static int datagramSize = 0xFFFF;//64K, a bit more than max udp size
30 static int iddleTimeout = 180000;//3 minutes
31
32
33 /**
34 Constructs UDP relay server to communicate with client
35 on given ip and port.
36 @param clientIP Address of the client from whom datagrams
37 will be recieved and to whom they will be forwarded.
38 @param clientPort Clients port.
39 @param master_thread Thread which will be interrupted, when
40 UDP relay server stoppes for some reason.
41 @param controlConnection Socket which will be closed, before
42 interrupting the master thread, it is introduced due to a bug
43 in windows JVM which does not throw InterruptedIOException in
44 threads which block in I/O operation.
45 */
46 public UDPRelayServer(InetAddress clientIP,int clientPort,
47 Thread master_thread,
48 Socket controlConnection,
49 ServerAuthenticator auth)
50 throws IOException{
51 this.master_thread = master_thread;
52 this.controlConnection = controlConnection;
53 this.auth = auth;
54
55 client_sock = new Socks5DatagramSocket(true,auth.getUdpEncapsulation(),
56 clientIP,clientPort);
57 relayPort = client_sock.getLocalPort();
58 relayIP = client_sock.getLocalAddress();
59
60 if(relayIP.getHostAddress().equals("0.0.0.0"))
61 relayIP = InetAddress.getLocalHost();
62
63 if(proxy == null)
64 remote_sock = new DatagramSocket();
65 else
66 remote_sock = new Socks5DatagramSocket(proxy,0,null);
67 }
68
69
70 //Public methods
71 /////////////////
72
73
74 /**
75 Sets the timeout for UDPRelay server.<br>
76 Zero timeout implies infinity.<br>
77 Default timeout is 3 minutes.
78 */
79
80 static public void setTimeout(int timeout){
81 iddleTimeout = timeout;
82 }
83
84
85 /**
86 Sets the size of the datagrams used in the UDPRelayServer.<br>
87 Default size is 64K, a bit more than maximum possible size of the
88 datagram.
89 */
90 static public void setDatagramSize(int size){
91 datagramSize = size;
92 }
93
94 /**
95 Port to which client should send datagram for association.
96 */
97 public int getRelayPort(){
98 return relayPort;
99 }
100 /**
101 IP address to which client should send datagrams for association.
102 */
103 public InetAddress getRelayIP(){
104 return relayIP;
105 }
106
107 /**
108 Starts udp relay server.
109 Spawns two threads of execution and returns.
110 */
111 public void start() throws IOException{
112 remote_sock.setSoTimeout(iddleTimeout);
113 client_sock.setSoTimeout(iddleTimeout);
114
115 log("Starting UDP relay server on "+relayIP+":"+relayPort);
116 log("Remote socket "+remote_sock.getLocalAddress()+":"+
117 remote_sock.getLocalPort());
118
119 pipe_thread1 = new Thread(this,"pipe1");
120 pipe_thread2 = new Thread(this,"pipe2");
121
122 lastReadTime = System.currentTimeMillis();
123
124 pipe_thread1.start();
125 pipe_thread2.start();
126 }
127
128 /**
129 Stops Relay server.
130 <p>
131 Does not close control connection, does not interrupt master_thread.
132 */
133 public synchronized void stop(){
134 master_thread = null;
135 controlConnection = null;
136 abort();
137 }
138
139 //Runnable interface
140 ////////////////////
141 public void run(){
142 try{
143 if(Thread.currentThread().getName().equals("pipe1"))
144 pipe(remote_sock,client_sock,false);
145 else
146 pipe(client_sock,remote_sock,true);
147 }catch(IOException ioe){
148 }finally{
149 abort();
150 log("UDP Pipe thread "+Thread.currentThread().getName()+" stopped.");
151 }
152
153 }
154
155 //Private methods
156 /////////////////
157 private synchronized void abort(){
158 if(pipe_thread1 == null) return;
159
160 log("Aborting UDP Relay Server");
161
162 remote_sock.close();
163 client_sock.close();
164
165 if(controlConnection != null)
166 try{ controlConnection.close();} catch(IOException ioe){}
167
168 if(master_thread!=null) master_thread.interrupt();
169
170 pipe_thread1.interrupt();
171 pipe_thread2.interrupt();
172
173 pipe_thread1 = null;
174 }
175
176
177 static private void log(String s){
178 if(log != null){
179 log.println(s);
180 log.flush();
181 }
182 }
183
184 private void pipe(DatagramSocket from,DatagramSocket to,boolean out)
185 throws IOException{
186 byte[] data = new byte[datagramSize];
187 DatagramPacket dp = new DatagramPacket(data,data.length);
188
189 while(true){
190 try{
191 from.receive(dp);
192 lastReadTime = System.currentTimeMillis();
193
194 if(auth.checkRequest(dp,out))
195 to.send(dp);
196
197 }catch(UnknownHostException uhe){
198 log("Dropping datagram for unknown host");
199 }catch(InterruptedIOException iioe){
200 //log("Interrupted: "+iioe);
201 //If we were interrupted by other thread.
202 if(iddleTimeout == 0) return;
203
204 //If last datagram was received, long time ago, return.
205 long timeSinceRead = System.currentTimeMillis() - lastReadTime;
206 if(timeSinceRead >= iddleTimeout -100) //-100 for adjustment
207 return;
208 }
209 dp.setLength(data.length);
210 }
211 }
212 }