1 | package nu.fw.jeti.plugins.filetransfer.socks5.jsocks; |
---|
2 | import java.io.*; |
---|
3 | import java.net.*; |
---|
4 | import java.security.MessageDigest; |
---|
5 | import java.security.NoSuchAlgorithmException; |
---|
6 | |
---|
7 | import nu.fw.jeti.plugins.filetransfer.socks5.Socks5Send; |
---|
8 | import nu.fw.jeti.util.I18N; |
---|
9 | import nu.fw.jeti.util.Popups; |
---|
10 | |
---|
11 | |
---|
12 | /** |
---|
13 | SOCKS4 and SOCKS5 proxy, handles both protocols simultaniously. |
---|
14 | Implements all SOCKS commands, including UDP relaying. |
---|
15 | <p> |
---|
16 | In order to use it you will need to implement ServerAuthenticator |
---|
17 | interface. There is an implementation of this interface which does |
---|
18 | no authentication ServerAuthenticatorNone, but it is very dangerous |
---|
19 | to use, as it will give access to your local network to anybody |
---|
20 | in the world. One should never use this authentication scheme unless |
---|
21 | one have pretty good reason to do so. |
---|
22 | There is a couple of other authentication schemes in socks.server package. |
---|
23 | @see socks.server.ServerAuthenticator |
---|
24 | */ |
---|
25 | public class ProxyServer implements Runnable{ |
---|
26 | |
---|
27 | ServerAuthenticator auth; |
---|
28 | ProxyMessage msg = null; |
---|
29 | |
---|
30 | Socket sock=null,remote_sock=null; |
---|
31 | ServerSocket ss=null; |
---|
32 | UDPRelayServer relayServer = null; |
---|
33 | InputStream in; //,remote_in; |
---|
34 | OutputStream out;//,remote_out; |
---|
35 | File file; |
---|
36 | String sha1Digest; |
---|
37 | Thread pst; |
---|
38 | Socks5Send send; |
---|
39 | |
---|
40 | int mode; |
---|
41 | static final int START_MODE = 0; |
---|
42 | static final int ACCEPT_MODE = 1; |
---|
43 | static final int PIPE_MODE = 2; |
---|
44 | static final int ABORT_MODE = 3; |
---|
45 | |
---|
46 | static final int BUF_SIZE = 8192; |
---|
47 | |
---|
48 | // Thread pipe_thread1,pipe_thread2; |
---|
49 | long lastReadTime; |
---|
50 | |
---|
51 | static int iddleTimeout = 180000; //3 minutes |
---|
52 | static int acceptTimeout = 180000; //3 minutes |
---|
53 | |
---|
54 | static PrintStream log = null; |
---|
55 | static Proxy proxy; |
---|
56 | |
---|
57 | |
---|
58 | //Public Constructors |
---|
59 | ///////////////////// |
---|
60 | |
---|
61 | |
---|
62 | /** |
---|
63 | Creates a proxy server with given Authentication scheme. |
---|
64 | @param auth Authentication scheme to be used. |
---|
65 | */ |
---|
66 | public ProxyServer(ServerAuthenticator auth){ |
---|
67 | this.auth = auth; |
---|
68 | } |
---|
69 | |
---|
70 | //Other constructors |
---|
71 | //////////////////// |
---|
72 | |
---|
73 | public ProxyServer(ServerAuthenticator auth,Socket s,File file,String digest,Socks5Send send){ |
---|
74 | this.auth = auth; |
---|
75 | this.sock = s; |
---|
76 | this.file = file; |
---|
77 | this.send = send; |
---|
78 | sha1Digest = digest; |
---|
79 | mode = START_MODE; |
---|
80 | setLog(System.out); |
---|
81 | pst = new Thread(this); |
---|
82 | pst.start(); |
---|
83 | } |
---|
84 | |
---|
85 | //Public methods |
---|
86 | ///////////////// |
---|
87 | |
---|
88 | /** |
---|
89 | Set the logging stream. Specifying null disables logging. |
---|
90 | */ |
---|
91 | public static void setLog(OutputStream out){ |
---|
92 | if(out == null){ |
---|
93 | log = null; |
---|
94 | }else{ |
---|
95 | log = new PrintStream(out,true); |
---|
96 | } |
---|
97 | |
---|
98 | UDPRelayServer.log = log; |
---|
99 | } |
---|
100 | |
---|
101 | /** |
---|
102 | Set proxy. |
---|
103 | <p> |
---|
104 | Allows Proxy chaining so that one Proxy server is connected to another |
---|
105 | and so on. If proxy supports SOCKSv4, then only some SOCKSv5 requests |
---|
106 | can be handled, UDP would not work, however CONNECT and BIND will be |
---|
107 | translated. |
---|
108 | |
---|
109 | @param p Proxy which should be used to handle user requests. |
---|
110 | */ |
---|
111 | public static void setProxy(Proxy p){ |
---|
112 | proxy =p; |
---|
113 | UDPRelayServer.proxy = proxy; |
---|
114 | } |
---|
115 | |
---|
116 | /** |
---|
117 | Get proxy. |
---|
118 | @return Proxy wich is used to handle user requests. |
---|
119 | */ |
---|
120 | public static Proxy getProxy(){ |
---|
121 | return proxy; |
---|
122 | } |
---|
123 | |
---|
124 | /** |
---|
125 | Sets the timeout for connections, how long shoud server wait |
---|
126 | for data to arrive before dropping the connection.<br> |
---|
127 | Zero timeout implies infinity.<br> |
---|
128 | Default timeout is 3 minutes. |
---|
129 | */ |
---|
130 | public static void setIddleTimeout(int timeout){ |
---|
131 | iddleTimeout = timeout; |
---|
132 | } |
---|
133 | /** |
---|
134 | Sets the timeout for BIND command, how long the server should |
---|
135 | wait for the incoming connection.<br> |
---|
136 | Zero timeout implies infinity.<br> |
---|
137 | Default timeout is 3 minutes. |
---|
138 | */ |
---|
139 | public static void setAcceptTimeout(int timeout){ |
---|
140 | acceptTimeout = timeout; |
---|
141 | } |
---|
142 | |
---|
143 | /** |
---|
144 | Sets the timeout for UDPRelay server.<br> |
---|
145 | Zero timeout implies infinity.<br> |
---|
146 | Default timeout is 3 minutes. |
---|
147 | */ |
---|
148 | public static void setUDPTimeout(int timeout){ |
---|
149 | UDPRelayServer.setTimeout(timeout); |
---|
150 | } |
---|
151 | |
---|
152 | /** |
---|
153 | Sets the size of the datagrams used in the UDPRelayServer.<br> |
---|
154 | Default size is 64K, a bit more than maximum possible size of the |
---|
155 | datagram. |
---|
156 | */ |
---|
157 | public static void setDatagramSize(int size){ |
---|
158 | UDPRelayServer.setDatagramSize(size); |
---|
159 | } |
---|
160 | |
---|
161 | |
---|
162 | /** |
---|
163 | Start the Proxy server at given port.<br> |
---|
164 | This methods blocks. |
---|
165 | */ |
---|
166 | public void start(int port){ |
---|
167 | start(port,5,null); |
---|
168 | } |
---|
169 | |
---|
170 | /** |
---|
171 | Create a server with the specified port, listen backlog, and local |
---|
172 | IP address to bind to. The localIP argument can be used on a multi-homed |
---|
173 | host for a ServerSocket that will only accept connect requests to one of |
---|
174 | its addresses. If localIP is null, it will default accepting connections |
---|
175 | on any/all local addresses. The port must be between 0 and 65535, |
---|
176 | inclusive. <br> |
---|
177 | This methods blocks. |
---|
178 | */ |
---|
179 | public void start(int port,int backlog,InetAddress localIP){ |
---|
180 | try{ |
---|
181 | ss = new ServerSocket(port,backlog,localIP); |
---|
182 | log("Starting SOCKS Proxy on:"+ss.getInetAddress().getHostAddress()+":" |
---|
183 | +ss.getLocalPort()); |
---|
184 | while(true){ |
---|
185 | Socket s = ss.accept(); |
---|
186 | log("Accepted from:"+s.getInetAddress().getHostName()+":" |
---|
187 | +s.getPort()); |
---|
188 | ProxyServer ps = new ProxyServer(auth,s,null,null,null); |
---|
189 | (new Thread(ps)).start(); |
---|
190 | } |
---|
191 | }catch(IOException ioe){ |
---|
192 | ioe.printStackTrace(); |
---|
193 | }finally{ |
---|
194 | } |
---|
195 | } |
---|
196 | |
---|
197 | /** |
---|
198 | Stop server operation.It would be wise to interrupt thread running the |
---|
199 | server afterwards. |
---|
200 | */ |
---|
201 | public void stop(){ |
---|
202 | try{ |
---|
203 | if(ss != null) ss.close(); |
---|
204 | }catch(IOException ioe){ |
---|
205 | } |
---|
206 | pst.interrupt(); |
---|
207 | } |
---|
208 | |
---|
209 | //Runnable interface |
---|
210 | //////////////////// |
---|
211 | public void run(){ |
---|
212 | switch(mode){ |
---|
213 | case START_MODE: |
---|
214 | try{ |
---|
215 | startSession(); |
---|
216 | }catch(IOException ioe){ |
---|
217 | handleException(ioe); |
---|
218 | //ioe.printStackTrace(); |
---|
219 | }finally{ |
---|
220 | abort(); |
---|
221 | if(auth!=null) auth.endSession(); |
---|
222 | log("Main thread(client->remote)stopped."); |
---|
223 | } |
---|
224 | break; |
---|
225 | case ACCEPT_MODE: |
---|
226 | try{ |
---|
227 | doAccept(); |
---|
228 | mode = PIPE_MODE; |
---|
229 | //pipe_thread1.interrupt(); //Tell other thread that connection have |
---|
230 | //been accepted. |
---|
231 | // System.out.println("accept pipe"); |
---|
232 | // pipe(remote_in,out); |
---|
233 | }catch(IOException ioe){ |
---|
234 | //log("Accept exception:"+ioe); |
---|
235 | handleException(ioe); |
---|
236 | }finally{ |
---|
237 | abort(); |
---|
238 | log("Accept thread(remote->client) stopped"); |
---|
239 | } |
---|
240 | break; |
---|
241 | case PIPE_MODE: |
---|
242 | try{ |
---|
243 | //System.out.println("pipe mode"); |
---|
244 | //pipe(remote_in,out); |
---|
245 | |
---|
246 | // }catch(IOException ioe){ |
---|
247 | }finally{ |
---|
248 | abort(); |
---|
249 | log("Support thread(remote->client) stopped"); |
---|
250 | } |
---|
251 | break; |
---|
252 | case ABORT_MODE: |
---|
253 | break; |
---|
254 | default: |
---|
255 | log("Unexpected MODE "+mode); |
---|
256 | } |
---|
257 | } |
---|
258 | |
---|
259 | //Private methods |
---|
260 | ///////////////// |
---|
261 | private void startSession() throws IOException{ |
---|
262 | sock.setSoTimeout(iddleTimeout); |
---|
263 | |
---|
264 | try{ |
---|
265 | auth = auth.startSession(sock); |
---|
266 | }catch(IOException ioe){ |
---|
267 | log("Auth throwed exception:"+ioe); |
---|
268 | auth = null; |
---|
269 | return; |
---|
270 | } |
---|
271 | |
---|
272 | if(auth == null){ //Authentication failed |
---|
273 | log("Authentication failed"); |
---|
274 | return; |
---|
275 | } |
---|
276 | |
---|
277 | in = auth.getInputStream(); |
---|
278 | out = auth.getOutputStream(); |
---|
279 | |
---|
280 | msg = readMsg(in); |
---|
281 | handleRequest(msg); |
---|
282 | } |
---|
283 | |
---|
284 | private void handleRequest(ProxyMessage msg) |
---|
285 | throws IOException{ |
---|
286 | if(!auth.checkRequest(msg)) throw new |
---|
287 | SocksException(Proxy.SOCKS_FAILURE); |
---|
288 | |
---|
289 | if(msg.ip == null){ |
---|
290 | if(msg instanceof Socks5Message){ |
---|
291 | // msg.ip = InetAddress.getByName(msg.host); |
---|
292 | }else |
---|
293 | throw new SocksException(Proxy.SOCKS_FAILURE); |
---|
294 | } |
---|
295 | log(msg); |
---|
296 | |
---|
297 | switch(msg.command){ |
---|
298 | case Proxy.SOCKS_CMD_CONNECT: |
---|
299 | onConnect(msg); |
---|
300 | break; |
---|
301 | case Proxy.SOCKS_CMD_BIND: |
---|
302 | //onBind(msg); |
---|
303 | break; |
---|
304 | case Proxy.SOCKS_CMD_UDP_ASSOCIATE: |
---|
305 | // onUDP(msg); |
---|
306 | break; |
---|
307 | default: |
---|
308 | throw new SocksException(Proxy.SOCKS_CMD_NOT_SUPPORTED); |
---|
309 | } |
---|
310 | } |
---|
311 | |
---|
312 | private void handleException(IOException ioe){ |
---|
313 | |
---|
314 | Popups.messagePopup(I18N.gettext("filetransfer.Problem_during_file_transfer,_transfer_aborted"),I18N.gettext("filetransfer.File_Transfer")); |
---|
315 | send.finished(); |
---|
316 | |
---|
317 | ioe.printStackTrace(); |
---|
318 | |
---|
319 | //If we couldn't read the request, return; |
---|
320 | if(msg == null) return; |
---|
321 | //If have been aborted by other thread |
---|
322 | if(mode == ABORT_MODE) return; |
---|
323 | //If the request was successfully completed, but exception happened later |
---|
324 | if(mode == PIPE_MODE) return; |
---|
325 | |
---|
326 | int error_code = Proxy.SOCKS_FAILURE; |
---|
327 | |
---|
328 | if(ioe instanceof SocksException) |
---|
329 | error_code = ((SocksException)ioe).errCode; |
---|
330 | else if(ioe instanceof NoRouteToHostException) |
---|
331 | error_code = Proxy.SOCKS_HOST_UNREACHABLE; |
---|
332 | else if(ioe instanceof ConnectException) |
---|
333 | error_code = Proxy.SOCKS_CONNECTION_REFUSED; |
---|
334 | else if(ioe instanceof InterruptedIOException) |
---|
335 | error_code = Proxy.SOCKS_TTL_EXPIRE; |
---|
336 | |
---|
337 | if(error_code > Proxy.SOCKS_ADDR_NOT_SUPPORTED || error_code < 0){ |
---|
338 | error_code = Proxy.SOCKS_FAILURE; |
---|
339 | } |
---|
340 | |
---|
341 | sendErrorMessage(error_code); |
---|
342 | } |
---|
343 | |
---|
344 | private void onConnect(ProxyMessage msg) throws IOException{ |
---|
345 | Socket s; |
---|
346 | ProxyMessage response = null; |
---|
347 | |
---|
348 | // if(proxy == null) |
---|
349 | // s = new Socket(msg.ip,msg.port); |
---|
350 | // else |
---|
351 | // s = new SocksSocket(proxy,msg.ip,msg.port); |
---|
352 | |
---|
353 | // System.out.println(sha1Digest); |
---|
354 | // System.out.println(msg.host); |
---|
355 | |
---|
356 | if(msg.host.equals(sha1Digest) && msg.port==0) |
---|
357 | { |
---|
358 | log("Connected to "+msg.host+":"+msg.port); |
---|
359 | |
---|
360 | if(msg instanceof Socks5Message){ |
---|
361 | response = new Socks5Message(Proxy.SOCKS_SUCCESS, |
---|
362 | msg.host, |
---|
363 | msg.port); |
---|
364 | } |
---|
365 | |
---|
366 | //response = new Socks4Message(Socks4Message.REPLY_OK, s.getLocalAddress(),s.getLocalPort()); |
---|
367 | |
---|
368 | response.write(out); |
---|
369 | startPipe(null); |
---|
370 | } |
---|
371 | else |
---|
372 | { |
---|
373 | System.out.println("invalid entry"); |
---|
374 | throw new ConnectException(); |
---|
375 | } |
---|
376 | |
---|
377 | } |
---|
378 | |
---|
379 | private void onBind(ProxyMessage msg) throws IOException{ |
---|
380 | ProxyMessage response = null; |
---|
381 | |
---|
382 | if(proxy == null) |
---|
383 | ss = new ServerSocket(0); |
---|
384 | else |
---|
385 | ss = new SocksServerSocket(proxy, msg.ip, msg.port); |
---|
386 | |
---|
387 | ss.setSoTimeout(acceptTimeout); |
---|
388 | |
---|
389 | log("Trying accept on "+ss.getInetAddress()+":"+ss.getLocalPort()); |
---|
390 | |
---|
391 | if(msg.version == 5) |
---|
392 | response = new Socks5Message(Proxy.SOCKS_SUCCESS,ss.getInetAddress(), |
---|
393 | ss.getLocalPort()); |
---|
394 | else |
---|
395 | response = new Socks4Message(Socks4Message.REPLY_OK, |
---|
396 | ss.getInetAddress(), |
---|
397 | ss.getLocalPort()); |
---|
398 | response.write(out); |
---|
399 | |
---|
400 | mode = ACCEPT_MODE; |
---|
401 | |
---|
402 | //pipe_thread1 = Thread.currentThread(); |
---|
403 | //pipe_thread2 = new Thread(this); |
---|
404 | //pipe_thread2.start(); |
---|
405 | |
---|
406 | //Make timeout infinit. |
---|
407 | sock.setSoTimeout(0); |
---|
408 | int eof=0; |
---|
409 | |
---|
410 | try{ |
---|
411 | while((eof=in.read())>=0){ |
---|
412 | if(mode != ACCEPT_MODE){ |
---|
413 | if(mode != PIPE_MODE) return;//Accept failed |
---|
414 | |
---|
415 | //remote_out.write(eof); |
---|
416 | break; |
---|
417 | } |
---|
418 | } |
---|
419 | }catch(EOFException eofe){ |
---|
420 | //System.out.println("EOF exception"); |
---|
421 | return;//Connection closed while we were trying to accept. |
---|
422 | }catch(InterruptedIOException iioe){ |
---|
423 | //Accept thread interrupted us. |
---|
424 | //System.out.println("Interrupted"); |
---|
425 | if(mode != PIPE_MODE) |
---|
426 | return;//If accept thread was not successfull return. |
---|
427 | }finally{ |
---|
428 | //System.out.println("Finnaly!"); |
---|
429 | } |
---|
430 | |
---|
431 | if(eof < 0)//Connection closed while we were trying to accept; |
---|
432 | return; |
---|
433 | |
---|
434 | //Do not restore timeout, instead timeout is set on the |
---|
435 | //remote socket. It does not make any difference. |
---|
436 | |
---|
437 | // pipe(in,remote_out); |
---|
438 | } |
---|
439 | |
---|
440 | private void onUDP(ProxyMessage msg) throws IOException{ |
---|
441 | if(msg.ip.getHostAddress().equals("0.0.0.0")) |
---|
442 | msg.ip = sock.getInetAddress(); |
---|
443 | log("Creating UDP relay server for "+msg.ip+":"+msg.port); |
---|
444 | relayServer = new UDPRelayServer(msg.ip,msg.port, |
---|
445 | Thread.currentThread(),sock,auth); |
---|
446 | |
---|
447 | ProxyMessage response; |
---|
448 | |
---|
449 | response = new Socks5Message(Proxy.SOCKS_SUCCESS, |
---|
450 | relayServer.relayIP,relayServer.relayPort); |
---|
451 | |
---|
452 | response.write(out); |
---|
453 | |
---|
454 | relayServer.start(); |
---|
455 | |
---|
456 | //Make timeout infinit. |
---|
457 | sock.setSoTimeout(0); |
---|
458 | try{ |
---|
459 | while(in.read()>=0) /*do nothing*/; |
---|
460 | }catch(EOFException eofe){ |
---|
461 | } |
---|
462 | } |
---|
463 | |
---|
464 | //Private methods |
---|
465 | ////////////////// |
---|
466 | |
---|
467 | private void doAccept() throws IOException{ |
---|
468 | // System.out.println("doaccept"); |
---|
469 | Socket s; |
---|
470 | long startTime = System.currentTimeMillis(); |
---|
471 | |
---|
472 | while(true){ |
---|
473 | s = ss.accept(); |
---|
474 | if(s.getInetAddress().equals(msg.ip)){ |
---|
475 | //got the connection from the right host |
---|
476 | //Close listenning socket. |
---|
477 | ss.close(); |
---|
478 | break; |
---|
479 | }else if(ss instanceof SocksServerSocket){ |
---|
480 | //We can't accept more then one connection |
---|
481 | s.close(); |
---|
482 | ss.close(); |
---|
483 | throw new SocksException(Proxy.SOCKS_FAILURE); |
---|
484 | }else{ |
---|
485 | if(acceptTimeout!=0){ //If timeout is not infinit |
---|
486 | int newTimeout = acceptTimeout-(int)(System.currentTimeMillis()- |
---|
487 | startTime); |
---|
488 | if(newTimeout <= 0) throw new InterruptedIOException( |
---|
489 | "In doAccept()"); |
---|
490 | ss.setSoTimeout(newTimeout); |
---|
491 | } |
---|
492 | s.close(); //Drop all connections from other hosts |
---|
493 | } |
---|
494 | } |
---|
495 | |
---|
496 | //Accepted connection |
---|
497 | remote_sock = s; |
---|
498 | // remote_in = s.getInputStream(); |
---|
499 | // remote_out = s.getOutputStream(); |
---|
500 | |
---|
501 | //Set timeout |
---|
502 | remote_sock.setSoTimeout(iddleTimeout); |
---|
503 | |
---|
504 | log("Accepted from "+s.getInetAddress()+":"+s.getPort()); |
---|
505 | |
---|
506 | ProxyMessage response; |
---|
507 | |
---|
508 | if(msg.version == 5) |
---|
509 | response = new Socks5Message(Proxy.SOCKS_SUCCESS, s.getInetAddress(), |
---|
510 | s.getPort()); |
---|
511 | else |
---|
512 | response = new Socks4Message(Socks4Message.REPLY_OK, |
---|
513 | s.getInetAddress(), s.getPort()); |
---|
514 | response.write(out); |
---|
515 | } |
---|
516 | |
---|
517 | private ProxyMessage readMsg(InputStream in) throws IOException{ |
---|
518 | PushbackInputStream push_in; |
---|
519 | if(in instanceof PushbackInputStream) |
---|
520 | push_in = (PushbackInputStream) in; |
---|
521 | else |
---|
522 | push_in = new PushbackInputStream(in); |
---|
523 | |
---|
524 | int version = push_in.read(); |
---|
525 | push_in.unread(version); |
---|
526 | |
---|
527 | |
---|
528 | ProxyMessage msg; |
---|
529 | |
---|
530 | if(version == 5){ |
---|
531 | msg = new Socks5Message(push_in,false); |
---|
532 | }else if(version == 4){ |
---|
533 | msg = new Socks4Message(push_in,false); |
---|
534 | }else{ |
---|
535 | throw new SocksException(Proxy.SOCKS_FAILURE); |
---|
536 | } |
---|
537 | return msg; |
---|
538 | } |
---|
539 | |
---|
540 | private void startPipe(Socket s){ |
---|
541 | mode = PIPE_MODE; |
---|
542 | remote_sock = s; |
---|
543 | try{ |
---|
544 | /// remote_in = s.getInputStream(); |
---|
545 | // remote_out = s.getOutputStream(); |
---|
546 | // pipe_thread1 = Thread.currentThread(); |
---|
547 | // pipe_thread2 = new Thread(this); |
---|
548 | // pipe_thread2.start(); |
---|
549 | // pipe(in,remote_out); |
---|
550 | pipe(out); |
---|
551 | }catch(IOException ioe){ |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | private void sendErrorMessage(int error_code){ |
---|
556 | ProxyMessage err_msg; |
---|
557 | if(msg instanceof Socks4Message) |
---|
558 | err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED); |
---|
559 | else |
---|
560 | err_msg = new Socks5Message(error_code); |
---|
561 | try{ |
---|
562 | err_msg.write(out); |
---|
563 | }catch(IOException ioe){} |
---|
564 | } |
---|
565 | |
---|
566 | private synchronized void abort(){ |
---|
567 | if(mode == ABORT_MODE) return; |
---|
568 | mode = ABORT_MODE; |
---|
569 | try{ |
---|
570 | log("Aborting operation"); |
---|
571 | if(remote_sock != null) remote_sock.close(); |
---|
572 | if(sock != null) sock.close(); |
---|
573 | if(relayServer!=null) relayServer.stop(); |
---|
574 | if(ss!=null) ss.close(); |
---|
575 | // if(pipe_thread1 != null) pipe_thread1.interrupt(); |
---|
576 | // if(pipe_thread2 != null) pipe_thread2.interrupt(); |
---|
577 | }catch(IOException ioe){} |
---|
578 | } |
---|
579 | |
---|
580 | static final void log(String s){ |
---|
581 | if(log != null){ |
---|
582 | log.println(s); |
---|
583 | log.flush(); |
---|
584 | } |
---|
585 | } |
---|
586 | |
---|
587 | static final void log(ProxyMessage msg){ |
---|
588 | log("Request version:"+msg.version+ |
---|
589 | "\tCommand: "+command2String(msg.command)); |
---|
590 | log("IP:"+msg.ip +"\tPort:"+msg.port+ |
---|
591 | (msg.version==4?"\tUser:"+msg.user:"")); |
---|
592 | } |
---|
593 | |
---|
594 | private void pipe(OutputStream out) throws IOException |
---|
595 | { |
---|
596 | InputStream is = new FileInputStream(file.getAbsolutePath()); |
---|
597 | byte[] buf = new byte[BUF_SIZE]; |
---|
598 | //System.out.println("begin sending"); |
---|
599 | try |
---|
600 | { |
---|
601 | int n; |
---|
602 | while ((n = is.read(buf)) > 0) |
---|
603 | { |
---|
604 | out.write(buf, 0, n); |
---|
605 | out.flush(); |
---|
606 | send.addBytes(n); |
---|
607 | if (Thread.interrupted()) { return; } |
---|
608 | Thread.yield(); |
---|
609 | } |
---|
610 | send.finished(); |
---|
611 | } finally |
---|
612 | { |
---|
613 | is.close(); |
---|
614 | } |
---|
615 | } |
---|
616 | |
---|
617 | |
---|
618 | // private void pipe(InputStream in,OutputStream out) throws IOException{ |
---|
619 | // lastReadTime = System.currentTimeMillis(); |
---|
620 | // byte[] buf = new byte[BUF_SIZE]; |
---|
621 | // int len = 0; |
---|
622 | // while(len >= 0){ |
---|
623 | // try{ |
---|
624 | // if(len!=0){ |
---|
625 | // out.write(buf,0,len); |
---|
626 | // out.flush(); |
---|
627 | // } |
---|
628 | // len= in.read(buf); |
---|
629 | // lastReadTime = System.currentTimeMillis(); |
---|
630 | // }catch(InterruptedIOException iioe){ |
---|
631 | // if(iddleTimeout == 0) return;//Other thread interrupted us. |
---|
632 | // long timeSinceRead = System.currentTimeMillis() - lastReadTime; |
---|
633 | // if(timeSinceRead >= iddleTimeout - 1000) //-1s for adjustment. |
---|
634 | // return; |
---|
635 | // len = 0; |
---|
636 | // |
---|
637 | // } |
---|
638 | // } |
---|
639 | // } |
---|
640 | static final String command_names[] = {"CONNECT","BIND","UDP_ASSOCIATE"}; |
---|
641 | |
---|
642 | static final String command2String(int cmd){ |
---|
643 | if(cmd > 0 && cmd < 4) return command_names[cmd-1]; |
---|
644 | else return "Unknown Command "+cmd; |
---|
645 | } |
---|
646 | } |
---|