KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgroups > util > Proxy


1 // $Id: Proxy.java,v 1.3 2006/12/31 14:27:58 belaban Exp $
2

3 package org.jgroups.util;
4
5
6 import javax.net.ssl.SSLServerSocket;
7 import javax.net.ssl.SSLServerSocketFactory;
8 import javax.net.ssl.SSLSocketFactory;
9 import java.io.*;
10 import java.net.*;
11 import java.nio.ByteBuffer JavaDoc;
12 import java.nio.channels.SelectionKey JavaDoc;
13 import java.nio.channels.Selector JavaDoc;
14 import java.nio.channels.ServerSocketChannel JavaDoc;
15 import java.nio.channels.SocketChannel JavaDoc;
16 import java.util.*;
17 import java.util.concurrent.Executor JavaDoc;
18 import java.util.concurrent.LinkedBlockingQueue JavaDoc;
19 import java.util.concurrent.ThreadPoolExecutor JavaDoc;
20 import java.util.concurrent.TimeUnit JavaDoc;
21
22
23 /**
24  * Redirects incoming TCP connections to other hosts/ports. All redirections are defined in a file as for example
25  * <pre>
26  * 127.0.0.1:8888=www.ibm.com:80
27  * localhost:80=pop.mail.yahoo.com:110
28  * </pre>
29  * The first line forwards all requests to port 8888 on to www.ibm.com at port 80 (it also forwards the HTTP
30  * response back to the sender. The second line essentially provides a POP-3 service on port 8110, using
31  * Yahoo's POP service. This is neat when you're behind a firewall and one of the few services in the outside
32  * world that are not blocked is port 80 (HHTP).<br/>
33  * Note that JDK 1.4 is required for this class. Also, concurrent.jar has to be on the classpath. Note that
34  * you also need to include jsse.jar/jce.jar (same location as rt.jar) if you want SSL sockets.<br>
35  * To create SSLServerSockets you'll need to do the following:
36  * Generate a certificate as follows:
37  * <pre>
38  * keytool -genkey -keystore /home/bela/.keystore -keyalg rsa -alias bela -storepass <passwd> -keypass <passwd>
39  * </pre>
40  *
41  * Start the Proxy as follows:
42  * <pre>
43  * java -Djavax.net.ssl.keyStore=/home/bela/.keystore -Djavax.net.ssl.keyStorePassword=<passwd>
44  * -Djavax.net.ssl.trustStore=/home/bela/.keystore -Djavax.net.ssl.trustStorePassword=<passwd>
45  * org.jgroups.util.Proxy -file /home/bela/map.properties
46  * </pre>
47  * Start client as follows:
48  * <pre>
49  * java -Djavax.net.ssl.trustStore=/home/bela/.keystore -Djavax.net.ssl.trustStorePassword=<passwd> sslclient
50  * </pre>
51  * <br/>
52  * To import a certificate into the keystore, use the following steps:
53  * <pre>
54  * openssl x509 -in server.crt -out server.crt.der -outform DER
55  * keytool -import -trustcacerts -alias <your alias name> -file server.crt.der
56  * </pre>
57  * This will store the server's certificate in the ${user.home}/.keystore key store.
58  * <br/>
59  * Note that an SSL client or server can be debugged by starting it as follows:
60  * <pre>-Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl</pre>
61  * <br/>
62  * If you run a web browser, simply enter https://<host>:<port> as URL to connect to an SSLServerSocket
63  * <br/>Note that we cannot use JDK 1.4's selectors for SSL sockets, as
64  * getChannel() on an SSL socket doesn't seem to work.
65  * @todo Check whether SSLSocket.getChannel() or SSLServerSocket.getChannel() works.
66  * @author Bela Ban
67  */

68 public class Proxy {
69     InetAddress local=null, remote=null;
70     int local_port=0, remote_port=0;
71     static boolean verbose=false;
72     static boolean debug=false;
73     String JavaDoc mapping_file=null; // contains a list of src and dest host:port pairs
74
final HashMap mappings=new HashMap(); // keys=MyInetSocketAddr (src), values=MyInetSocketAddr (dest)
75
Executor JavaDoc executor; // maintains a thread pool
76
static final int MIN_THREAD_POOL_SIZE=2;
77     static final int MAX_THREAD_POOL_SIZE=64; // for processing requests
78
static final int BUFSIZE=1024; // size of data transfer buffer
79

80
81
82     public Proxy(InetAddress local, int local_port, InetAddress remote, int remote_port, boolean verbose, boolean debug) {
83         this.local=local;
84         this.local_port=local_port;
85         this.remote=remote;
86         this.remote_port=remote_port;
87         Proxy.verbose=verbose;
88         Proxy.debug=debug;
89     }
90
91     public Proxy(InetAddress local, int local_port, InetAddress remote, int remote_port,
92                     boolean verbose, boolean debug, String JavaDoc mapping_file) {
93         this(local, local_port, remote, remote_port, verbose, debug);
94         this.mapping_file=mapping_file;
95     }
96
97     public void start() throws Exception JavaDoc {
98         Map.Entry entry;
99         Selector JavaDoc selector;
100         ServerSocketChannel JavaDoc sock_channel;
101         MyInetSocketAddress key, value;
102
103         if (remote !=null && local !=null)
104             mappings.put(new InetSocketAddress(local, local_port), new InetSocketAddress(remote, remote_port));
105         
106         if (mapping_file !=null) {
107             try {
108                 populateMappings(mapping_file);
109             }
110             catch (Exception JavaDoc ex) {
111                 log("Failed reading " + mapping_file);
112                 throw ex;
113             }
114         }
115
116         log("\nProxy started at " + new java.util.Date JavaDoc());
117
118         if (verbose) {
119             log("\nMappings:\n---------");
120             for (Iterator it=mappings.entrySet().iterator(); it.hasNext();) {
121                 entry=(Map.Entry) it.next();
122                 log(toString((InetSocketAddress) entry.getKey()) + " <--> "
123                     + toString((InetSocketAddress) entry.getValue()));
124             }
125             log("\n");
126         }
127
128         // 1. Create a Selector
129
selector=Selector.open();
130
131         // Create a thread pool (Executor)
132
executor=new ThreadPoolExecutor JavaDoc(MIN_THREAD_POOL_SIZE, MAX_THREAD_POOL_SIZE, 30000, TimeUnit.MILLISECONDS,
133                                         new LinkedBlockingQueue JavaDoc(1000));
134
135         for (Iterator it=mappings.keySet().iterator(); it.hasNext();) {
136             key=(MyInetSocketAddress) it.next();
137             value=(MyInetSocketAddress) mappings.get(key);
138
139             // if either source or destination are SSL, we cannot use JDK 1.4
140
// NIO selectors, but have to fall back on separate threads per connection
141

142             if (key.ssl() || value.ssl()) {
143                 // if(2 == 2) {
144
SocketAcceptor acceptor=new SocketAcceptor(key, value);
145                 executor.execute(acceptor);
146                 continue;
147             }
148
149             // 2. Create a ServerSocketChannel
150
sock_channel=ServerSocketChannel.open();
151             sock_channel.configureBlocking(false);
152             sock_channel.socket().bind(key);
153
154             // 3. Register the selector with all server sockets. 'Key' is attachment, so we get it again on
155
// select(). That way we can associate it with the mappings hashmap to find the corresponding
156
// value
157
sock_channel.register(selector, SelectionKey.OP_ACCEPT, key);
158         }
159
160         // 4. Start main loop. won't return until CTRL-C'ed
161
loop(selector);
162     }
163
164
165
166     /** We handle only non-SSL connections */
167     void loop(Selector JavaDoc selector) {
168         Set ready_keys;
169         SelectionKey JavaDoc key;
170         ServerSocketChannel JavaDoc srv_sock;
171         SocketChannel JavaDoc in_sock, out_sock;
172         InetSocketAddress src, dest;
173
174         while (true) {
175             if (verbose)
176                 log("[Proxy] ready to accept connection");
177
178             // 4. Call Selector.select()
179
try {
180                 selector.select();
181
182                 // get set of ready objects
183
ready_keys=selector.selectedKeys();
184                 for (Iterator it=ready_keys.iterator(); it.hasNext();) {
185                     key=(SelectionKey JavaDoc) it.next();
186                     it.remove();
187
188                     if (key.isAcceptable()) {
189                         srv_sock=(ServerSocketChannel JavaDoc) key.channel();
190                         // get server socket and attachment
191
SRC=(InetSocketAddress) key.attachment();
192                         in_sock=srv_sock.accept(); // accept request
193
if (verbose)
194                             log("Proxy.loop()", "accepted connection from " + toString(in_sock));
195                         dest=(InetSocketAddress) mappings.get(src);
196                         // find corresponding dest
197
if (dest == null) {
198                             in_sock.close();
199                             log("Proxy.loop()", "did not find a destination host for " + src);
200                             continue;
201                         }
202                         else {
203                             if (verbose)
204                                 log("Proxy.loop()", "relaying traffic from " + toString(src) + " to " + toString(dest));
205                         }
206
207                         // establish connection to destination host
208
try {
209                             out_sock=SocketChannel.open(dest);
210                             // uses thread pool (Executor) to handle request, closes socks at end
211
handleConnection(in_sock, out_sock);
212                         }
213                         catch (Exception JavaDoc ex) {
214                             in_sock.close();
215                             throw ex;
216                         }
217                     }
218                 }
219             }
220             catch (Exception JavaDoc ex) {
221                 log("Proxy.loop()", "exception: " + ex);
222             }
223         }
224     }
225
226     // void handleConnection(Socket in_sock, Socket out_sock) {
227
// try {
228
// Relayer r=new Relayer(in_sock, out_sock);
229
// executor.execute(r);
230
// r=new Relayer(out_sock, in_sock);
231
// executor.execute(r);
232
// }
233
// catch (Exception ex) {
234
// log("Proxy.handleConnection()", "exception: " + ex);
235
// }
236
// finally {
237
// close(in_sock, out_sock);
238
// }
239
// }
240

241     void handleConnection(SocketChannel JavaDoc in, SocketChannel JavaDoc out) {
242         try {
243             _handleConnection(in, out);
244         }
245         catch (Exception JavaDoc ex) {
246             log("Proxy.handleConnection()", "exception: " + ex);
247         }
248     }
249     
250     void _handleConnection(final SocketChannel JavaDoc in_channel, final SocketChannel JavaDoc out_channel) throws Exception JavaDoc {
251         executor.execute(new Runnable JavaDoc() {
252                 public void run() {
253                     Selector JavaDoc sel=null;
254                     SocketChannel JavaDoc tmp;
255                     Set ready_keys;
256                     SelectionKey JavaDoc key;
257                     ByteBuffer JavaDoc transfer_buf=ByteBuffer.allocate(BUFSIZE);
258
259                     try {
260                         sel=Selector.open();
261                         in_channel.configureBlocking(false);
262                         out_channel.configureBlocking(false);
263                         in_channel.register(sel, SelectionKey.OP_READ);
264                         out_channel.register(sel, SelectionKey.OP_READ);
265                         
266                         while (sel.select() > 0) {
267                             ready_keys=sel.selectedKeys();
268                             for (Iterator it=ready_keys.iterator(); it.hasNext();) {
269                                 key=(SelectionKey JavaDoc) it.next();
270                                 it.remove(); // remove current entry (why ?)
271
tmp=(SocketChannel JavaDoc) key.channel();
272                                 if (tmp == null) {
273                                     log(
274                                         "Proxy._handleConnection()",
275                                         "attachment is null, continuing");
276                                     continue;
277                                 }
278                                 if (key.isReadable()) { // data is available to be read from tmp
279
if (tmp == in_channel) {
280                                         // read all data from in_channel and forward it to out_channel (request)
281
if (relay(tmp, out_channel, transfer_buf) == false)
282                                             return;
283                                     }
284                                     if (tmp == out_channel) {
285                                         // read all data from out_channel and forward it
286
// to in_channel (response)
287
if (relay(tmp, in_channel, transfer_buf) == false)
288                                             return;
289                                     }
290                                 }
291                             }
292                         }
293                     }
294                     catch (Exception JavaDoc ex) {
295                         ex.printStackTrace();
296                     }
297                     finally {
298                         close(sel, in_channel, out_channel);
299                     }
300                 }
301             });
302     }
303     
304     void close(Selector JavaDoc sel, SocketChannel JavaDoc in_channel, SocketChannel JavaDoc out_channel) {
305         try {
306             if (sel !=null)
307                 sel.close();
308         }
309         catch (Exception JavaDoc ex) {
310         }
311         try {
312             if (in_channel !=null)
313                 in_channel.close();
314         }
315         catch (Exception JavaDoc ex) {
316         }
317         try {
318             if (out_channel !=null)
319                 out_channel.close();
320         }
321         catch (Exception JavaDoc ex) {
322         }
323     }
324
325
326     /**
327      * Read all data from <code>from</code> and write it to <code>to</code>.
328      * Returns false if channel was closed
329      */

330     boolean relay(SocketChannel JavaDoc from, SocketChannel JavaDoc to, ByteBuffer JavaDoc buf) throws Exception JavaDoc {
331         int num;
332         StringBuffer JavaDoc sb;
333
334         buf.clear();
335         while (true) {
336             num=from.read(buf);
337             if (num < 0)
338                 return false;
339             else
340                 if (num == 0)
341                     return true;
342             buf.flip();
343             if (verbose) {
344                 log(printRelayedData(toString(from), toString(to), buf.remaining()));
345             }
346             if (debug) {
347                 sb=new StringBuffer JavaDoc();
348                 sb.append(new String JavaDoc(buf.array()).trim());
349                 sb.append('\n');
350                 log(sb.toString());
351             }
352             to.write(buf);
353             buf.flip();
354         }
355     }
356
357     String JavaDoc toString(SocketChannel JavaDoc ch) {
358         StringBuilder JavaDoc sb=new StringBuilder JavaDoc();
359         Socket sock;
360
361         if (ch == null)
362             return null;
363         if ((sock=ch.socket()) == null)
364             return null;
365         sb.append(sock.getInetAddress().getHostName()).append(':').append(sock.getPort());
366         return sb.toString();
367     }
368
369     String JavaDoc toString(InetSocketAddress addr) {
370         StringBuffer JavaDoc sb;
371         sb=new StringBuffer JavaDoc();
372
373         if (addr == null)
374             return null;
375         sb.append(addr.getAddress().getHostName()).append(':').append(addr.getPort());
376         if (addr instanceof MyInetSocketAddress)
377             sb.append(" [ssl=").append(((MyInetSocketAddress) addr).ssl()).append(']');
378         return sb.toString();
379     }
380
381     
382     static String JavaDoc printRelayedData(String JavaDoc from, String JavaDoc to, int num_bytes) {
383         StringBuffer JavaDoc sb;
384         sb=new StringBuffer JavaDoc();
385         sb.append("\n[PROXY] ").append(from);
386         sb.append(" to ").append(to);
387         sb.append(" (").append(num_bytes).append(" bytes)");
388         // log("Proxy.relay()", sb.toString());
389
return sb.toString();
390     }
391     
392
393     /**
394      * Populates <code>mappings</code> hashmap. An example of a definition file is:
395      * <pre>
396      * http://localhost:8888=http://www.yahoo.com:80
397      * https://localhost:2200=https://cvs.sourceforge.net:22
398      * http://localhost:8000=https://www.ibm.com:443
399      * </pre>
400      * Mappings can be http-https, https-http, http-http or https-https
401      */

402     void populateMappings(String JavaDoc filename) throws Exception JavaDoc {
403         FileInputStream in=new FileInputStream(filename);
404         BufferedReader reader;
405         String JavaDoc line;
406         URI key, value;
407         int index;
408         boolean ssl_key, ssl_value;
409         final String JavaDoc HTTPS="https";
410
411         reader=new BufferedReader(new InputStreamReader(in));
412         while ((line=reader.readLine()) !=null) {
413             line=line.trim();
414             if (line.startsWith("//") || line.startsWith("#") || line.length() == 0)
415                 continue;
416             index=line.indexOf('=');
417             if (index == -1)
418                 throw new Exception JavaDoc("Proxy.populateMappings(): detected no '=' character in " + line);
419             key=new URI(line.substring(0, index));
420             ssl_key=key.getScheme().trim().equals(HTTPS);
421
422             value=new URI(line.substring(index + 1));
423             ssl_value=value.getScheme().trim().equals(HTTPS);
424
425             check(key);
426             check(value);
427
428             log("key: " + key + ", value: " + value);
429
430             mappings.put(new MyInetSocketAddress(key.getHost(), key.getPort(), ssl_key),
431                          new MyInetSocketAddress(value.getHost(), value.getPort(), ssl_value));
432         }
433         in.close();
434     }
435
436     /** Checks whether a URI is http(s)://<host>:<port> */
437     void check(URI u) throws Exception JavaDoc {
438         if (u.getScheme() == null)
439             throw new Exception JavaDoc(
440                 "scheme is null in " + u + ", (valid URI is \"http(s)://<host>:<port>\")");
441
442         if (u.getHost() == null)
443             throw new Exception JavaDoc(
444                 "host is null in " + u + ", (valid URI is \"http(s)://<host>:<port>\")");
445
446         if (u.getPort() <=0)
447             throw new Exception JavaDoc(
448                 "port is <=0 in " + u + ", (valid URI is \"http(s)://<host>:<port>\")");
449
450     }
451
452     /** Input is "host:port" */
453     SocketAddress strToAddr(String JavaDoc input) throws Exception JavaDoc {
454         StringTokenizer tok=new StringTokenizer(input, ":");
455         String JavaDoc host, port;
456
457         host=tok.nextToken();
458         port=tok.nextToken();
459         return new InetSocketAddress(host, Integer.parseInt(port));
460     }
461
462     String JavaDoc printSelectionOps(SelectionKey JavaDoc key) {
463         StringBuilder JavaDoc sb=new StringBuilder JavaDoc();
464         if ((key.readyOps() & SelectionKey.OP_ACCEPT) !=0)
465             sb.append("OP_ACCEPT ");
466         if ((key.readyOps() & SelectionKey.OP_CONNECT) !=0)
467             sb.append("OP_CONNECT ");
468         if ((key.readyOps() & SelectionKey.OP_READ) !=0)
469             sb.append("OP_READ ");
470         if ((key.readyOps() & SelectionKey.OP_WRITE) !=0)
471             sb.append("OP_WRITE ");
472         return sb.toString();
473     }
474
475     public static void main(String JavaDoc[] args) {
476         Proxy p;
477         InetAddress local=null, remote=null;
478         int local_port=0, remote_port=0;
479         String JavaDoc tmp, tmp_addr, tmp_port;
480         boolean verbose=false, debug=false;
481         int index;
482         String JavaDoc mapping_file=null;
483
484         try {
485             for (int i=0; i < args.length; i++) {
486                 tmp=args[i];
487                 if ("-help".equals(tmp)) {
488                     help();
489                     return;
490                 }
491                 if ("-verbose".equals(tmp)) {
492                     verbose=true;
493                     continue;
494                 }
495                 if ("-local".equals(tmp)) {
496                     tmp_addr=args[++i];
497                     index=tmp_addr.indexOf(':');
498                     if (index > -1) { // it is in the format address:port
499
tmp_port=tmp_addr.substring(index + 1);
500                         local_port=Integer.parseInt(tmp_port);
501                         tmp_addr=tmp_addr.substring(0, index);
502                         local=InetAddress.getByName(tmp_addr);
503                     }
504                     else
505                         local=InetAddress.getByName(args[++i]);
506                     continue;
507                 }
508                 if ("-local_port".equals(tmp)) {
509                     local_port=Integer.parseInt(args[++i]);
510                     continue;
511                 }
512                 if ("-remote".equals(tmp)) {
513                     tmp_addr=args[++i];
514                     index=tmp_addr.indexOf(':');
515                     if (index > -1) { // it is in the format address:port
516
tmp_port=tmp_addr.substring(index + 1);
517                         remote_port=Integer.parseInt(tmp_port);
518                         tmp_addr=tmp_addr.substring(0, index);
519                         remote=InetAddress.getByName(tmp_addr);
520                     }
521                     else
522                         remote=InetAddress.getByName(args[++i]);
523                     continue;
524                 }
525                 if ("-remote_port".equals(tmp)) {
526                     remote_port=Integer.parseInt(args[++i]);
527                     continue;
528                 }
529                 if ("-file".equals(tmp)) {
530                     mapping_file=args[++i];
531                     continue;
532                 }
533                 if ("-debug".equals(tmp)) {
534                     debug=true;
535                     continue;
536                 }
537                 help();
538                 return;
539             }
540
541             if (local == null)
542                 local=InetAddress.getLocalHost();
543
544             p=new Proxy(local, local_port, remote, remote_port, verbose, debug, mapping_file);
545             p.start();
546         }
547         catch (Throwable JavaDoc ex) {
548             ex.printStackTrace();
549         }
550     }
551
552     static void help() {
553         System.out.println("Proxy [-help] [-local <local address>] [-local_port <port>] "
554                            + "[-remote <remote address>] [-remote_port <port>] [-verbose] "
555                            + "[-file <mapping file>] [-debug]");
556     }
557
558     static void log(String JavaDoc method_name, String JavaDoc msg) {
559         System.out.println('[' + method_name + "]: " + msg);
560     }
561
562     static void log(String JavaDoc msg) {
563         System.out.println(msg);
564     }
565
566     static void close(Socket in, Socket out) {
567         if (in !=null) {
568             try {
569                 in.close();
570             }
571             catch (Exception JavaDoc ex) {
572             }
573         }
574         if (out !=null) {
575             try {
576                 out.close();
577             }
578             catch (Exception JavaDoc ex) {
579             }
580         }
581     }
582
583     static void close(Socket sock) {
584         if (sock !=null) {
585             try {
586                 sock.close();
587             }
588             catch (Exception JavaDoc ex) {
589             }
590         }
591     }
592
593     static class Relayer implements Runnable JavaDoc {
594         final Socket in_sock;
595         final Socket out_sock;
596         final InputStream in;
597         final OutputStream out;
598         Thread JavaDoc t=null;
599         final java.util.List JavaDoc listeners=new ArrayList();
600         String JavaDoc name=null;
601
602         interface Listener {
603             void connectionClosed();
604         }
605
606         public Relayer(Socket in_sock, Socket out_sock, String JavaDoc name) throws Exception JavaDoc {
607             this.in_sock=in_sock;
608             this.out_sock=out_sock;
609             this.name=name;
610             in=in_sock.getInputStream();
611             out=out_sock.getOutputStream();
612         }
613
614         public void addListener(Listener l) {
615             if(l != null && !listeners.contains(l))
616                 listeners.add(l);
617         }
618
619
620         public void run() {
621             byte[] buf=new byte[1024];
622             int num;
623             StringBuffer JavaDoc sb;
624
625             try {
626                 while(t != null) {
627                     if ((num=in.read(buf)) == -1)
628                         break;
629
630                     if (verbose) {
631                         
632                         //sb=new StringBuffer();
633

634
635                         //sb.append("forwarding ").append(num).append(" bytes from ").append(toString(in_sock));
636
//sb.append(" to ").append(toString(out_sock));
637
// log("Proxy.Relayer.run()", sb.toString());
638
log(printRelayedData(toString(in_sock), toString(out_sock), num));
639                     }
640                     if (debug) {
641                         sb=new StringBuffer JavaDoc();
642                         sb.append(new String JavaDoc(buf, 0, num).trim());
643                         log(sb.toString());
644                     }
645
646                     out.write(buf, 0, num);
647                     //if(debug)
648
// System.out.println(new String(buf));
649
}
650                 
651             }
652             catch (Exception JavaDoc ex) {
653                 log("Proxy.Relayer.run(): [" + name + "] exception=" + ex + ", in_sock=" +
654                     in_sock + ", out_sock=" + out_sock);
655             }
656             finally {
657                 stop();
658             }
659         }
660
661         public void start() {
662             if(t == null) {
663                 t=new Thread JavaDoc(this, "Proxy.Relayer");
664                 t.setDaemon(true);
665                 t.start();
666             }
667         }
668
669         public void stop() {
670             t=null;
671             close(in_sock);
672             close(out_sock);
673         }
674
675         String JavaDoc toString(Socket s) {
676             if(s == null) return null;
677             return s.getInetAddress().getHostName() + ':' + s.getPort();
678         }
679         
680
681         void notifyListeners() {
682             for(Iterator it=listeners.iterator(); it.hasNext();) {
683                 try {
684                     ((Listener)it.next()).connectionClosed();
685                 }
686                 catch(Throwable JavaDoc ex) {
687                     ;
688                 }
689             }
690         }
691     }
692
693     static class MyInetSocketAddress extends InetSocketAddress {
694         boolean is_ssl=false;
695
696         public MyInetSocketAddress(InetAddress addr, int port) {
697             super(addr, port);
698         }
699
700         public MyInetSocketAddress(InetAddress addr, int port, boolean is_ssl) {
701             super(addr, port);
702             this.is_ssl=is_ssl;
703         }
704
705         public MyInetSocketAddress(int port) {
706             super(port);
707         }
708
709         public MyInetSocketAddress(int port, boolean is_ssl) {
710             super(port);
711             this.is_ssl=is_ssl;
712         }
713
714         public MyInetSocketAddress(String JavaDoc hostname, int port) {
715             super(hostname, port);
716         }
717
718         public MyInetSocketAddress(String JavaDoc hostname, int port, boolean is_ssl) {
719             super(hostname, port);
720             this.is_ssl=is_ssl;
721         }
722
723         public boolean ssl() {
724             return is_ssl;
725         }
726
727         public String JavaDoc toString() {
728             return super.toString() + " [ssl: " + ssl() + ']';
729         }
730     }
731
732     /**
733      * Handles accepts on an SSLServerSocket or ServerSocket. Creates a {@link
734      * Connection} for each successful accept().
735      *
736      * @author bela Dec 19, 2002
737      */

738     class SocketAcceptor implements Runnable JavaDoc {
739         ServerSocket srv_sock=null;
740         MyInetSocketAddress dest=null;
741         
742
743         /**
744          * Create an SSLServerSocket or ServerSocket and continuously call
745          * accept() on it.
746          * @param sock_addr
747          */

748         public SocketAcceptor(MyInetSocketAddress sock_addr, MyInetSocketAddress dest) throws Exception JavaDoc {
749             this.dest=dest;
750             if(sock_addr.ssl()) {
751                 srv_sock=createSSLServerSocket(sock_addr);
752             }
753             else {
754                 srv_sock=createServerSocket(sock_addr);
755             }
756             executor.execute(this);
757         }
758
759         public void run() {
760             Connection conn;
761             Socket s, dest_sock;
762
763             while (srv_sock !=null) {
764                 try {
765                     s=srv_sock.accept();
766                     dest_sock=dest.ssl() ? createSSLSocket(dest) : createSocket(dest);
767                     conn=new Connection(s, dest_sock);
768                     conn.start();
769                 }
770                 catch (Exception JavaDoc e) {
771                     log("Proxy.SSLServerSocketAcceptor.run(): exception=" + e);
772                     break;
773                 }
774             }
775         }
776         
777
778         Socket createSocket(InetSocketAddress addr) throws Exception JavaDoc {
779             return new Socket(addr.getAddress(), addr.getPort());
780         }
781
782         Socket createSSLSocket(InetSocketAddress addr) throws Exception JavaDoc {
783             SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
784             return sslsocketfactory.createSocket(addr.getAddress(), addr.getPort());
785         }
786
787         ServerSocket createServerSocket(InetSocketAddress addr) throws Exception JavaDoc {
788             return new ServerSocket(addr.getPort(), 10, addr.getAddress());
789         }
790         
791         ServerSocket createSSLServerSocket(InetSocketAddress addr) throws Exception JavaDoc {
792             SSLServerSocketFactory sslserversocketfactory =
793                 (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
794             SSLServerSocket sslserversocket;
795             sslserversocket=(SSLServerSocket)sslserversocketfactory.createServerSocket(addr.getPort(), 10, addr.getAddress());
796             return sslserversocket;
797         }
798     }
799
800
801
802     /**
803      * Handles an incoming SSLSocket or Socket. Looks up the destination in the
804      * mapping hashmap, key is the incoming socket address. Creates an outgoing
805      * socket (regular or SSL, depending on settings) and relays data between
806      * incoming and outgoing sockets. Closes the connection when either incoming
807      * or outgoing socket is closed, or when stop() is called.
808      *
809      * @author bela Dec 19, 2002
810      */

811     static class Connection implements Relayer.Listener {
812         Relayer in_to_out=null;
813         Relayer out_to_in=null;
814
815         /**
816          * Creates an outgoing (regular or SSL) socket according to the mapping
817          * table. Sets both input and output stream. Caller needs to call
818          * start() after the instance has been created.
819          * @param in The Socket we got as result of accept()
820          * @throws Exception Thrown if either the input or output streams cannot
821          * be created.
822          */

823         public Connection(Socket in, Socket out) throws Exception JavaDoc {
824             in_to_out=new Relayer(in, out, "in-out");
825             in_to_out.addListener(this);
826             out_to_in=new Relayer(out, in, "out-in");
827             out_to_in.addListener(this);
828         }
829
830         /** Starts relaying between incoming and outgoing sockets.
831          * Returns immediately (thread is started).
832          *
833          */

834         public void start() {
835             in_to_out.start();
836             out_to_in.start();
837         }
838
839         public void stop() {
840             if (in_to_out !=null) {
841                 in_to_out.stop();
842             }
843             if (out_to_in !=null) {
844                 out_to_in.stop();
845             }
846         }
847
848         public void connectionClosed() {
849             stop();
850         }
851     }
852
853 }
854
Popular Tags