Mercurial > 510Connectbot
comparison src/net/sourceforge/jsocks/UDPRelayServer.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children | 205ee2873330 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0ce5cc452d02 |
---|---|
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 Proxy 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 client_sock = new Socks5DatagramSocket(true, auth.getUdpEncapsulation(), | |
55 clientIP, clientPort); | |
56 relayPort = client_sock.getLocalPort(); | |
57 relayIP = client_sock.getLocalAddress(); | |
58 | |
59 if (relayIP.getHostAddress().equals("0.0.0.0")) | |
60 relayIP = InetAddress.getLocalHost(); | |
61 | |
62 if (proxy == null) | |
63 remote_sock = new DatagramSocket(); | |
64 else | |
65 remote_sock = new Socks5DatagramSocket(proxy, 0, null); | |
66 } | |
67 | |
68 | |
69 //Public methods | |
70 ///////////////// | |
71 | |
72 | |
73 /** | |
74 Sets the timeout for UDPRelay server.<br> | |
75 Zero timeout implies infinity.<br> | |
76 Default timeout is 3 minutes. | |
77 */ | |
78 | |
79 static public void setTimeout(int timeout) { | |
80 iddleTimeout = timeout; | |
81 } | |
82 | |
83 | |
84 /** | |
85 Sets the size of the datagrams used in the UDPRelayServer.<br> | |
86 Default size is 64K, a bit more than maximum possible size of the | |
87 datagram. | |
88 */ | |
89 static public void setDatagramSize(int size) { | |
90 datagramSize = size; | |
91 } | |
92 | |
93 /** | |
94 Port to which client should send datagram for association. | |
95 */ | |
96 public int getRelayPort() { | |
97 return relayPort; | |
98 } | |
99 /** | |
100 IP address to which client should send datagrams for association. | |
101 */ | |
102 public InetAddress getRelayIP() { | |
103 return relayIP; | |
104 } | |
105 | |
106 /** | |
107 Starts udp relay server. | |
108 Spawns two threads of execution and returns. | |
109 */ | |
110 public void start() throws IOException { | |
111 remote_sock.setSoTimeout(iddleTimeout); | |
112 client_sock.setSoTimeout(iddleTimeout); | |
113 log("Starting UDP relay server on " + relayIP + ":" + relayPort); | |
114 log("Remote socket " + remote_sock.getLocalAddress() + ":" + | |
115 remote_sock.getLocalPort()); | |
116 pipe_thread1 = new Thread(this, "pipe1"); | |
117 pipe_thread2 = new Thread(this, "pipe2"); | |
118 lastReadTime = System.currentTimeMillis(); | |
119 pipe_thread1.start(); | |
120 pipe_thread2.start(); | |
121 } | |
122 | |
123 /** | |
124 Stops Relay server. | |
125 <p> | |
126 Does not close control connection, does not interrupt master_thread. | |
127 */ | |
128 | |
129 public synchronized void stop() { | |
130 master_thread = null; | |
131 controlConnection = null; | |
132 abort(); | |
133 } | |
134 | |
135 //Runnable interface | |
136 //////////////////// | |
137 public void run() { | |
138 try { | |
139 if (Thread.currentThread().getName().equals("pipe1")) | |
140 pipe(remote_sock, client_sock, false); | |
141 else | |
142 pipe(client_sock, remote_sock, true); | |
143 } | |
144 catch (IOException ioe) { | |
145 } | |
146 finally { | |
147 abort(); | |
148 log("UDP Pipe thread " + Thread.currentThread().getName() + " stopped."); | |
149 } | |
150 } | |
151 | |
152 //Private methods | |
153 ///////////////// | |
154 | |
155 private synchronized void abort() { | |
156 if (pipe_thread1 == null) return; | |
157 | |
158 log("Aborting UDP Relay Server"); | |
159 remote_sock.close(); | |
160 client_sock.close(); | |
161 | |
162 if (controlConnection != null) | |
163 try { controlConnection.close();} | |
164 catch (IOException ioe) {} | |
165 | |
166 if (master_thread != null) master_thread.interrupt(); | |
167 | |
168 pipe_thread1.interrupt(); | |
169 pipe_thread2.interrupt(); | |
170 pipe_thread1 = null; | |
171 } | |
172 | |
173 | |
174 static private void log(String s) { | |
175 if (log != null) { | |
176 log.println(s); | |
177 log.flush(); | |
178 } | |
179 } | |
180 | |
181 private void pipe(DatagramSocket from, DatagramSocket to, boolean out) | |
182 throws IOException { | |
183 byte[] data = new byte[datagramSize]; | |
184 DatagramPacket dp = new DatagramPacket(data, data.length); | |
185 | |
186 while (true) { | |
187 try { | |
188 from.receive(dp); | |
189 lastReadTime = System.currentTimeMillis(); | |
190 | |
191 if (auth.checkRequest(dp, out)) | |
192 to.send(dp); | |
193 } | |
194 catch (UnknownHostException uhe) { | |
195 log("Dropping datagram for unknown host"); | |
196 } | |
197 catch (InterruptedIOException iioe) { | |
198 //log("Interrupted: "+iioe); | |
199 //If we were interrupted by other thread. | |
200 if (iddleTimeout == 0) return; | |
201 | |
202 //If last datagram was received, long time ago, return. | |
203 long timeSinceRead = System.currentTimeMillis() - lastReadTime; | |
204 | |
205 if (timeSinceRead >= iddleTimeout - 100) //-100 for adjustment | |
206 return; | |
207 } | |
208 | |
209 dp.setLength(data.length); | |
210 } | |
211 } | |
212 } |