KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > SocksSocketImpl


1 /*
2  * @(#)SocksSocketImpl.java 1.21 06/06/12
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package java.net;
8 import java.io.IOException JavaDoc;
9 import java.io.InputStream JavaDoc;
10 import java.io.OutputStream JavaDoc;
11 import java.io.BufferedOutputStream JavaDoc;
12 import java.security.AccessController JavaDoc;
13 import java.security.PrivilegedExceptionAction JavaDoc;
14 import java.util.prefs.Preferences JavaDoc;
15 import sun.net.www.ParseUtil;
16 /* import org.ietf.jgss.*; */
17
18 /**
19  * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
20  * This is a subclass of PlainSocketImpl.
21  * Note this class should <b>NOT</b> be public.
22  */

23
24 class SocksSocketImpl extends PlainSocketImpl JavaDoc implements SocksConsts JavaDoc {
25     private String JavaDoc server = null;
26     private int port = DEFAULT_PORT;
27     private InetSocketAddress JavaDoc external_address;
28     private boolean useV4 = false;
29     private Socket JavaDoc cmdsock = null;
30     private InputStream JavaDoc cmdIn = null;
31     private OutputStream JavaDoc cmdOut = null;
32
33     SocksSocketImpl() {
34     // Nothing needed
35
}
36
37     SocksSocketImpl(String JavaDoc server, int port) {
38     this.server = server;
39     this.port = (port == -1 ? DEFAULT_PORT : port);
40     }
41
42     SocksSocketImpl(Proxy JavaDoc proxy) {
43     SocketAddress JavaDoc a = proxy.address();
44     if (a instanceof InetSocketAddress JavaDoc) {
45         InetSocketAddress JavaDoc ad = (InetSocketAddress JavaDoc) a;
46         // Use getHostString() to avoid reverse lookups
47
server = ad.getHostString();
48         port = ad.getPort();
49     }
50     }
51
52     void setV4() {
53     useV4 = true;
54     }
55
56     private synchronized void privilegedConnect(final String JavaDoc host,
57                           final int port,
58                           final int timeout)
59      throws IOException JavaDoc
60     {
61     try {
62         AccessController.doPrivileged(
63           new java.security.PrivilegedExceptionAction JavaDoc() {
64               public Object JavaDoc run() throws IOException JavaDoc {
65                   superConnectServer(host, port, timeout);
66                   cmdIn = getInputStream();
67                   cmdOut = getOutputStream();
68                   return null;
69               }
70               });
71     } catch (java.security.PrivilegedActionException JavaDoc pae) {
72         throw (IOException JavaDoc) pae.getException();
73     }
74     }
75
76     private void superConnectServer(String JavaDoc host, int port,
77                     int timeout) throws IOException JavaDoc {
78     super.connect(new InetSocketAddress JavaDoc(host, port), timeout);
79     }
80
81     private int readSocksReply(InputStream JavaDoc in, byte[] data) throws IOException JavaDoc {
82     int len = data.length;
83     int received = 0;
84     for (int attempts = 0; received < len && attempts < 3; attempts++) {
85         int count = in.read(data, received, len - received);
86         if (count < 0)
87         throw new SocketException JavaDoc("Malformed reply from SOCKS server");
88         received += count;
89     }
90     return received;
91     }
92
93     /**
94      * Provides the authentication machanism required by the proxy.
95      */

96     private boolean authenticate(byte method, InputStream JavaDoc in,
97                  BufferedOutputStream JavaDoc out) throws IOException JavaDoc {
98     byte[] data = null;
99     int i;
100     // No Authentication required. We're done then!
101
if (method == NO_AUTH)
102         return true;
103     /**
104      * User/Password authentication. Try, in that order :
105      * - The application provided Authenticator, if any
106      * - The user preferences java.net.socks.username &
107      * java.net.socks.password
108      * - the user.name & no password (backward compatibility behavior).
109      */

110     if (method == USER_PASSW) {
111         String JavaDoc userName;
112         String JavaDoc password = null;
113         final InetAddress JavaDoc addr = InetAddress.getByName(server);
114         PasswordAuthentication JavaDoc pw = (PasswordAuthentication JavaDoc)
115         java.security.AccessController.doPrivileged(
116             new java.security.PrivilegedAction JavaDoc() {
117                 public Object JavaDoc run() {
118                 return Authenticator.requestPasswordAuthentication(
119                                        server, addr, port, "SOCKS5", "SOCKS authentication", null);
120                 }
121             });
122         if (pw != null) {
123         userName = pw.getUserName();
124         password = new String JavaDoc(pw.getPassword());
125         } else {
126         final Preferences JavaDoc prefs = Preferences.userRoot().node("/java/net/socks");
127         try {
128             userName =
129             (String JavaDoc) AccessController.doPrivileged(
130                    new java.security.PrivilegedExceptionAction JavaDoc() {
131                        public Object JavaDoc run() throws IOException JavaDoc {
132                        return prefs.get("username", null);
133                        }
134                    });
135         } catch (java.security.PrivilegedActionException JavaDoc pae) {
136             throw (IOException JavaDoc) pae.getException();
137         }
138
139         if (userName != null) {
140             try {
141             password =
142                 (String JavaDoc) AccessController.doPrivileged(
143                    new java.security.PrivilegedExceptionAction JavaDoc() {
144                        public Object JavaDoc run() throws IOException JavaDoc {
145                            return prefs.get("password", null);
146                        }
147                        });
148             } catch (java.security.PrivilegedActionException JavaDoc pae) {
149             throw (IOException JavaDoc) pae.getException();
150             }
151         } else {
152             userName =
153             (String JavaDoc) java.security.AccessController.doPrivileged(
154                                          new sun.security.action.GetPropertyAction("user.name"));
155         }
156         }
157         if (userName == null)
158         return false;
159         out.write(1);
160         out.write(userName.length());
161         try {
162         out.write(userName.getBytes("ISO-8859-1"));
163         } catch (java.io.UnsupportedEncodingException JavaDoc uee) {
164         assert false;
165         }
166         if (password != null) {
167         out.write(password.length());
168         try {
169             out.write(password.getBytes("ISO-8859-1"));
170         } catch (java.io.UnsupportedEncodingException JavaDoc uee) {
171             assert false;
172         }
173         } else
174         out.write(0);
175         out.flush();
176         data = new byte[2];
177         i = readSocksReply(in, data);
178         if (i != 2 || data[1] != 0) {
179         /* RFC 1929 specifies that the connection MUST be closed if
180            authentication fails */

181         out.close();
182         in.close();
183         return false;
184         }
185         /* Authentication succeeded */
186         return true;
187     }
188     /**
189      * GSSAPI authentication mechanism.
190      * Unfortunately the RFC seems out of sync with the Reference
191      * implementation. I'll leave this in for future completion.
192      */

193 // if (method == GSSAPI) {
194
// try {
195
// GSSManager manager = GSSManager.getInstance();
196
// GSSName name = manager.createName("SERVICE:socks@"+server,
197
// null);
198
// GSSContext context = manager.createContext(name, null, null,
199
// GSSContext.DEFAULT_LIFETIME);
200
// context.requestMutualAuth(true);
201
// context.requestReplayDet(true);
202
// context.requestSequenceDet(true);
203
// context.requestCredDeleg(true);
204
// byte []inToken = new byte[0];
205
// while (!context.isEstablished()) {
206
// byte[] outToken
207
// = context.initSecContext(inToken, 0, inToken.length);
208
// // send the output token if generated
209
// if (outToken != null) {
210
// out.write(1);
211
// out.write(1);
212
// out.writeShort(outToken.length);
213
// out.write(outToken);
214
// out.flush();
215
// data = new byte[2];
216
// i = readSocksReply(in, data);
217
// if (i != 2 || data[1] == 0xff) {
218
// in.close();
219
// out.close();
220
// return false;
221
// }
222
// i = readSocksReply(in, data);
223
// int len = 0;
224
// len = ((int)data[0] & 0xff) << 8;
225
// len += data[1];
226
// data = new byte[len];
227
// i = readSocksReply(in, data);
228
// if (i == len)
229
// return true;
230
// in.close();
231
// out.close();
232
// }
233
// }
234
// } catch (GSSException e) {
235
// /* RFC 1961 states that if Context initialisation fails the connection
236
// MUST be closed */
237
// e.printStackTrace();
238
// in.close();
239
// out.close();
240
// }
241
// }
242
return false;
243     }
244
245     private void connectV4(InputStream JavaDoc in, OutputStream JavaDoc out,
246                InetSocketAddress JavaDoc endpoint) throws IOException JavaDoc {
247     if (!(endpoint.getAddress() instanceof Inet4Address JavaDoc)) {
248         throw new SocketException JavaDoc("SOCKS V4 requires IPv4 only addresses");
249     }
250     out.write(PROTO_VERS4);
251     out.write(CONNECT);
252     out.write((endpoint.getPort() >> 8) & 0xff);
253     out.write((endpoint.getPort() >> 0) & 0xff);
254     out.write(endpoint.getAddress().getAddress());
255     String JavaDoc userName = (String JavaDoc) java.security.AccessController.doPrivileged(
256                new sun.security.action.GetPropertyAction("user.name"));
257     try {
258         out.write(userName.getBytes("ISO-8859-1"));
259     } catch (java.io.UnsupportedEncodingException JavaDoc uee) {
260         assert false;
261     }
262     out.write(0);
263     out.flush();
264     byte[] data = new byte[8];
265     int n = readSocksReply(in, data);
266     if (n != 8)
267         throw new SocketException JavaDoc("Reply from SOCKS server has bad length: " + n);
268     if (data[0] != 0 && data[0] != 4)
269         throw new SocketException JavaDoc("Reply from SOCKS server has bad version");
270     SocketException JavaDoc ex = null;
271     switch (data[1]) {
272     case 90:
273         // Success!
274
external_address = endpoint;
275         break;
276     case 91:
277         ex = new SocketException JavaDoc("SOCKS request rejected");
278         break;
279     case 92:
280         ex = new SocketException JavaDoc("SOCKS server couldn't reach destination");
281         break;
282     case 93:
283         ex = new SocketException JavaDoc("SOCKS authentication failed");
284         break;
285     default:
286         ex = new SocketException JavaDoc("Reply from SOCKS server contains bad status");
287         break;
288     }
289     if (ex != null) {
290         in.close();
291         out.close();
292         throw ex;
293     }
294     }
295
296     /**
297      * Connects the Socks Socket to the specified endpoint. It will first
298      * connect to the SOCKS proxy and negotiate the access. If the proxy
299      * grants the connections, then the connect is successful and all
300      * further traffic will go to the "real" endpoint.
301      *
302      * @param endpoint the <code>SocketAddress</code> to connect to.
303      * @param timeout the timeout value in milliseconds
304      * @throws IOException if the connection can't be established.
305      * @throws SecurityException if there is a security manager and it
306      * doesn't allow the connection
307      * @throws IllegalArgumentException if endpoint is null or a
308      * SocketAddress subclass not supported by this socket
309      */

310     protected void connect(SocketAddress JavaDoc endpoint, int timeout) throws IOException JavaDoc {
311     SecurityManager JavaDoc security = System.getSecurityManager();
312     if (endpoint == null || !(endpoint instanceof InetSocketAddress JavaDoc))
313         throw new IllegalArgumentException JavaDoc("Unsupported address type");
314     InetSocketAddress JavaDoc epoint = (InetSocketAddress JavaDoc) endpoint;
315     if (security != null) {
316         if (epoint.isUnresolved())
317         security.checkConnect(epoint.getHostName(),
318                       epoint.getPort());
319         else
320         security.checkConnect(epoint.getAddress().getHostAddress(),
321                       epoint.getPort());
322     }
323     if (server == null) {
324         // This is the general case
325
// server is not null only when the socket was created with a
326
// specified proxy in which case it does bypass the ProxySelector
327
ProxySelector JavaDoc sel = (ProxySelector JavaDoc)
328         java.security.AccessController.doPrivileged(
329             new java.security.PrivilegedAction JavaDoc() {
330             public Object JavaDoc run() {
331                 return ProxySelector.getDefault();
332             }
333             });
334         if (sel == null) {
335         /*
336          * No default proxySelector --> direct connection
337          */

338         super.connect(epoint, timeout);
339         return;
340         }
341         URI JavaDoc uri = null;
342         // Use getHostString() to avoid reverse lookups
343
String JavaDoc host = epoint.getHostString();
344         // IPv6 litteral?
345
if (epoint.getAddress() instanceof Inet6Address JavaDoc &&
346         (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
347         host = "[" + host + "]";
348         }
349         try {
350         uri = new URI JavaDoc("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort());
351         } catch (URISyntaxException JavaDoc e) {
352         // This shouldn't happen
353
assert false : e;
354         }
355         Proxy JavaDoc p = null;
356         IOException JavaDoc savedExc = null;
357         java.util.Iterator JavaDoc<Proxy JavaDoc> iProxy = null;
358         iProxy = sel.select(uri).iterator();
359         if (iProxy == null || !(iProxy.hasNext())) {
360         super.connect(epoint, timeout);
361         return;
362         }
363         while (iProxy.hasNext()) {
364         p = iProxy.next();
365         if (p == null || p == Proxy.NO_PROXY) {
366             super.connect(epoint, timeout);
367             return;
368         }
369         if (p.type() != Proxy.Type.SOCKS)
370             throw new SocketException JavaDoc("Unknown proxy type : " + p.type());
371         if (!(p.address() instanceof InetSocketAddress JavaDoc))
372             throw new SocketException JavaDoc("Unknow address type for proxy: " + p);
373         // Use getHostString() to avoid reverse lookups
374
server = ((InetSocketAddress JavaDoc) p.address()).getHostString();
375         port = ((InetSocketAddress JavaDoc) p.address()).getPort();
376         
377         // Connects to the SOCKS server
378
try {
379             privilegedConnect(server, port, timeout);
380             // Worked, let's get outta here
381
break;
382         } catch (IOException JavaDoc e) {
383             // Ooops, let's notify the ProxySelector
384
sel.connectFailed(uri,p.address(),e);
385             server = null;
386             port = -1;
387             savedExc = e;
388             // Will continue the while loop and try the next proxy
389
}
390         }
391
392         /*
393          * If server is still null at this point, none of the proxy
394          * worked
395          */

396         if (server == null) {
397         throw new SocketException JavaDoc("Can't connect to SOCKS proxy:"
398                       + savedExc.getMessage());
399         }
400     } else {
401         // Connects to the SOCKS server
402
try {
403         privilegedConnect(server, port, timeout);
404         } catch (IOException JavaDoc e) {
405         throw new SocketException JavaDoc(e.getMessage());
406         }
407     }
408
409     // cmdIn & cmdOut were intialized during the privilegedConnect() call
410
BufferedOutputStream JavaDoc out = new BufferedOutputStream JavaDoc(cmdOut, 512);
411     InputStream JavaDoc in = cmdIn;
412
413     if (useV4) {
414         // SOCKS Protocol version 4 doesn't know how to deal with
415
// DOMAIN type of addresses (unresolved addresses here)
416
if (epoint.isUnresolved())
417         throw new UnknownHostException JavaDoc(epoint.toString());
418         connectV4(in, out, epoint);
419         return;
420     }
421
422     // This is SOCKS V5
423
out.write(PROTO_VERS);
424     out.write(2);
425     out.write(NO_AUTH);
426     out.write(USER_PASSW);
427     out.flush();
428     byte[] data = new byte[2];
429     int i = readSocksReply(in, data);
430     if (i != 2 || ((int)data[0]) != PROTO_VERS) {
431         // Maybe it's not a V5 sever after all
432
// Let's try V4 before we give up
433
// SOCKS Protocol version 4 doesn't know how to deal with
434
// DOMAIN type of addresses (unresolved addresses here)
435
if (epoint.isUnresolved())
436         throw new UnknownHostException JavaDoc(epoint.toString());
437         connectV4(in, out, epoint);
438         return;
439     }
440     if (((int)data[1]) == NO_METHODS)
441         throw new SocketException JavaDoc("SOCKS : No acceptable methods");
442     if (!authenticate(data[1], in, out)) {
443         throw new SocketException JavaDoc("SOCKS : authentication failed");
444     }
445     out.write(PROTO_VERS);
446     out.write(CONNECT);
447     out.write(0);
448     /* Test for IPV4/IPV6/Unresolved */
449     if (epoint.isUnresolved()) {
450         out.write(DOMAIN_NAME);
451         out.write(epoint.getHostName().length());
452         try {
453         out.write(epoint.getHostName().getBytes("ISO-8859-1"));
454         } catch (java.io.UnsupportedEncodingException JavaDoc uee) {
455         assert false;
456         }
457         out.write((epoint.getPort() >> 8) & 0xff);
458         out.write((epoint.getPort() >> 0) & 0xff);
459     } else if (epoint.getAddress() instanceof Inet6Address JavaDoc) {
460         out.write(IPV6);
461         out.write(epoint.getAddress().getAddress());
462         out.write((epoint.getPort() >> 8) & 0xff);
463         out.write((epoint.getPort() >> 0) & 0xff);
464     } else {
465         out.write(IPV4);
466         out.write(epoint.getAddress().getAddress());
467         out.write((epoint.getPort() >> 8) & 0xff);
468         out.write((epoint.getPort() >> 0) & 0xff);
469     }
470     out.flush();
471     data = new byte[4];
472     i = readSocksReply(in, data);
473     if (i != 4)
474         throw new SocketException JavaDoc("Reply from SOCKS server has bad length");
475     SocketException JavaDoc ex = null;
476     int nport, len;
477     byte[] addr;
478     switch (data[1]) {
479     case REQUEST_OK:
480         // success!
481
switch(data[3]) {
482         case IPV4:
483         addr = new byte[4];
484         i = readSocksReply(in, addr);
485         if (i != 4)
486             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
487         data = new byte[2];
488         i = readSocksReply(in, data);
489         if (i != 2)
490             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
491         nport = ((int)data[0] & 0xff) << 8;
492         nport += ((int)data[1] & 0xff);
493         break;
494         case DOMAIN_NAME:
495         len = data[1];
496         byte[] host = new byte[len];
497         i = readSocksReply(in, host);
498         if (i != len)
499             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
500         data = new byte[2];
501         i = readSocksReply(in, data);
502         if (i != 2)
503             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
504         nport = ((int)data[0] & 0xff) << 8;
505         nport += ((int)data[1] & 0xff);
506         break;
507         case IPV6:
508         len = data[1];
509         addr = new byte[len];
510         i = readSocksReply(in, addr);
511         if (i != len)
512             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
513         data = new byte[2];
514         i = readSocksReply(in, data);
515         if (i != 2)
516             throw new SocketException JavaDoc("Reply from SOCKS server badly formatted");
517         nport = ((int)data[0] & 0xff) << 8;
518         nport += ((int)data[1] & 0xff);
519         break;
520         default:
521         ex = new SocketException JavaDoc("Reply from SOCKS server contains wrong code");
522         break;
523         }
524         break;
525     case GENERAL_FAILURE:
526         ex = new SocketException JavaDoc("SOCKS server general failure");
527         break;
528     case NOT_ALLOWED:
529         ex = new SocketException JavaDoc("SOCKS: Connection not allowed by ruleset");
530         break;
531     case NET_UNREACHABLE:
532         ex = new SocketException JavaDoc("SOCKS: Network unreachable");
533         break;
534     case HOST_UNREACHABLE:
535         ex = new SocketException JavaDoc("SOCKS: Host unreachable");
536         break;
537     case CONN_REFUSED:
538         ex = new SocketException JavaDoc("SOCKS: Connection refused");
539         break;
540     case TTL_EXPIRED:
541         ex = new SocketException JavaDoc("SOCKS: TTL expired");
542         break;
543     case CMD_NOT_SUPPORTED:
544         ex = new SocketException JavaDoc("SOCKS: Command not supported");
545         break;
546     case ADDR_TYPE_NOT_SUP:
547         ex = new SocketException JavaDoc("SOCKS: address type not supported");
548         break;
549     }
550     if (ex != null) {
551         in.close();
552         out.close();
553         throw ex;
554     }
555     external_address = epoint;
556     }
557
558     private void bindV4(InputStream JavaDoc in, OutputStream JavaDoc out,
559             InetAddress JavaDoc baddr,
560             int lport) throws IOException JavaDoc {
561     if (!(baddr instanceof Inet4Address JavaDoc)) {
562         throw new SocketException JavaDoc("SOCKS V4 requires IPv4 only addresses");
563     }
564     super.bind(baddr, lport);
565     byte[] addr1 = baddr.getAddress();
566     /* Test for AnyLocal */
567     InetAddress JavaDoc naddr = baddr;
568     if (naddr.isAnyLocalAddress()) {
569         naddr = cmdsock.getLocalAddress();
570         addr1 = naddr.getAddress();
571     }
572     out.write(PROTO_VERS4);
573     out.write(BIND);
574     out.write((super.getLocalPort() >> 8) & 0xff);
575     out.write((super.getLocalPort() >> 0) & 0xff);
576     out.write(addr1);
577     String JavaDoc userName = (String JavaDoc) java.security.AccessController.doPrivileged(
578                new sun.security.action.GetPropertyAction("user.name"));
579     try {
580         out.write(userName.getBytes("ISO-8859-1"));
581     } catch (java.io.UnsupportedEncodingException JavaDoc uee) {
582         assert false;
583     }
584     out.write(0);
585     out.flush();
586     byte[] data = new byte[8];
587     int n = readSocksReply(in, data);
588     if (n != 8)
589         throw new SocketException JavaDoc("Reply from SOCKS server has bad length: " + n);
590     if (data[0] != 0 && data[0] != 4)
591         throw new SocketException JavaDoc("Reply from SOCKS server has bad version");
592     SocketException JavaDoc ex = null;
593     switch (data[1]) {
594     case 90:
595         // Success!
596
external_address = new InetSocketAddress JavaDoc(baddr, lport);
597         break;
598     case 91:
599         ex = new SocketException JavaDoc("SOCKS request rejected");
600         break;
601     case 92:
602         ex = new SocketException JavaDoc("SOCKS server couldn't reach destination");
603         break;
604     case 93:
605         ex = new SocketException JavaDoc("SOCKS authentication failed");
606         break;
607     default:
608         ex = new SocketException JavaDoc("Reply from SOCKS server contains bad status");
609         break;
610     }
611     if (ex != null) {
612         in.close();
613         out.close();
614         throw ex;
615     }
616     
617     }
618
619     /**
620      * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
621      * means "accept incoming connection from", so the SocketAddress is the
622      * the one of the host we do accept connection from.
623      *
624      * @param addr the Socket address of the remote host.
625      * @exception IOException if an I/O error occurs when binding this socket.
626      */

627     protected synchronized void socksBind(InetSocketAddress JavaDoc saddr) throws IOException JavaDoc {
628     if (socket != null) {
629         // this is a client socket, not a server socket, don't
630
// call the SOCKS proxy for a bind!
631
return;
632     }
633
634     // Connects to the SOCKS server
635

636     if (server == null) {
637         // This is the general case
638
// server is not null only when the socket was created with a
639
// specified proxy in which case it does bypass the ProxySelector
640
ProxySelector JavaDoc sel = (ProxySelector JavaDoc)
641         java.security.AccessController.doPrivileged(
642             new java.security.PrivilegedAction JavaDoc() {
643             public Object JavaDoc run() {
644                 return ProxySelector.getDefault();
645             }
646             });
647         if (sel == null) {
648         /*
649          * No default proxySelector --> direct connection
650          */

651         return;
652         }
653         URI JavaDoc uri = null;
654         // Use getHostString() to avoid reverse lookups
655
String JavaDoc host = saddr.getHostString();
656         // IPv6 litteral?
657
if (saddr.getAddress() instanceof Inet6Address JavaDoc &&
658         (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
659         host = "[" + host + "]";
660         }
661         try {
662         uri = new URI JavaDoc("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
663         } catch (URISyntaxException JavaDoc e) {
664         // This shouldn't happen
665
assert false : e;
666         }
667         Proxy JavaDoc p = null;
668         Exception JavaDoc savedExc = null;
669         java.util.Iterator JavaDoc<Proxy JavaDoc> iProxy = null;
670         iProxy = sel.select(uri).iterator();
671         if (iProxy == null || !(iProxy.hasNext())) {
672         return;
673         }
674         while (iProxy.hasNext()) {
675         p = iProxy.next();
676         if (p == null || p == Proxy.NO_PROXY) {
677             return;
678         }
679         if (p.type() != Proxy.Type.SOCKS)
680             throw new SocketException JavaDoc("Unknown proxy type : " + p.type());
681         if (!(p.address() instanceof InetSocketAddress JavaDoc))
682             throw new SocketException JavaDoc("Unknow address type for proxy: " + p);
683         // Use getHostString() to avoid reverse lookups
684
server = ((InetSocketAddress JavaDoc) p.address()).getHostString();
685         port = ((InetSocketAddress JavaDoc) p.address()).getPort();
686         
687         // Connects to the SOCKS server
688
try {
689             AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc() {
690                 public Object JavaDoc run() throws Exception JavaDoc {
691                 cmdsock = new Socket JavaDoc(new PlainSocketImpl JavaDoc());
692                 cmdsock.connect(new InetSocketAddress JavaDoc(server, port));
693                 cmdIn = cmdsock.getInputStream();
694                 cmdOut = cmdsock.getOutputStream();
695                 return null;
696                 }
697             });
698         } catch (Exception JavaDoc e) {
699             // Ooops, let's notify the ProxySelector
700
sel.connectFailed(uri,p.address(),new SocketException JavaDoc(e.getMessage()));
701             server = null;
702             port = -1;
703             cmdsock = null;
704             savedExc = e;
705             // Will continue the while loop and try the next proxy
706
}
707         }
708
709         /*
710          * If server is still null at this point, none of the proxy
711          * worked
712          */

713         if (server == null || cmdsock == null) {
714         throw new SocketException JavaDoc("Can't connect to SOCKS proxy:"
715                       + savedExc.getMessage());
716         }
717     } else {
718         try {
719         AccessController.doPrivileged(new PrivilegedExceptionAction