001: // $Id: Proxy.java,v 1.2 2005/07/17 11:33:58 chrislott Exp $
002:
003: package org.jgroups.util;
004:
005: import EDU.oswego.cs.dl.util.concurrent.Executor;
006: import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
007:
008: import javax.net.ssl.SSLServerSocket;
009: import javax.net.ssl.SSLServerSocketFactory;
010: import javax.net.ssl.SSLSocket;
011: import javax.net.ssl.SSLSocketFactory;
012: import java.io.*;
013: import java.net.*;
014: import java.nio.ByteBuffer;
015: import java.nio.channels.SelectionKey;
016: import java.nio.channels.Selector;
017: import java.nio.channels.ServerSocketChannel;
018: import java.nio.channels.SocketChannel;
019: import java.util.*;
020:
021: /**
022: * Redirects incoming TCP connections to other hosts/ports. All redirections are defined in a file as for example
023: * <pre>
024: * 127.0.0.1:8888=www.ibm.com:80
025: * localhost:80=pop.mail.yahoo.com:110
026: * </pre>
027: * The first line forwards all requests to port 8888 on to www.ibm.com at port 80 (it also forwards the HTTP
028: * response back to the sender. The second line essentially provides a POP-3 service on port 8110, using
029: * Yahoo's POP service. This is neat when you're behind a firewall and one of the few services in the outside
030: * world that are not blocked is port 80 (HHTP).<br/>
031: * Note that JDK 1.4 is required for this class. Also, concurrent.jar has to be on the classpath. Note that
032: * you also need to include jsse.jar/jce.jar (same location as rt.jar) if you want SSL sockets.<br>
033: * To create SSLServerSockets you'll need to do the following:
034: * Generate a certificate as follows:
035: * <pre>
036: * keytool -genkey -keystore /home/bela/.keystore -keyalg rsa -alias bela -storepass <passwd> -keypass <passwd>
037: * </pre>
038: *
039: * Start the Proxy as follows:
040: * <pre>
041: * java -Djavax.net.ssl.keyStore=/home/bela/.keystore -Djavax.net.ssl.keyStorePassword=<passwd>
042: * -Djavax.net.ssl.trustStore=/home/bela/.keystore -Djavax.net.ssl.trustStorePassword=<passwd>
043: * org.jgroups.util.Proxy -file /home/bela/map.properties
044: * </pre>
045: * Start client as follows:
046: * <pre>
047: * java -Djavax.net.ssl.trustStore=/home/bela/.keystore -Djavax.net.ssl.trustStorePassword=<passwd> sslclient
048: * </pre>
049: * <br/>
050: * To import a certificate into the keystore, use the following steps:
051: * <pre>
052: * openssl x509 -in server.crt -out server.crt.der -outform DER
053: * keytool -import -trustcacerts -alias <your alias name> -file server.crt.der
054: * </pre>
055: * This will store the server's certificate in the ${user.home}/.keystore key store.
056: * <br/>
057: * Note that an SSL client or server can be debugged by starting it as follows:
058: * <pre>-Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl</pre>
059: * <br/>
060: * If you run a web browser, simply enter https://<host>:<port> as URL to connect to an SSLServerSocket
061: * <br/>Note that we cannot use JDK 1.4's selectors for SSL sockets, as
062: * getChannel() on an SSL socket doesn't seem to work.
063: * @todo Check whether SSLSocket.getChannel() or SSLServerSocket.getChannel() works.
064: * @author Bela Ban
065: */
066: public class Proxy {
067: InetAddress local = null, remote = null;
068: int local_port = 0, remote_port = 0;
069: static boolean verbose = false;
070: static boolean debug = false;
071: String mapping_file = null; // contains a list of src and dest host:port pairs
072: final HashMap mappings = new HashMap(); // keys=MyInetSocketAddr (src), values=MyInetSocketAddr (dest)
073: Executor executor; // maintains a thread pool
074: static final int MAX_THREAD_POOL_SIZE = 64; // for processing requests
075: static final int BUFSIZE = 1024; // size of data transfer buffer
076:
077: public Proxy(InetAddress local, int local_port, InetAddress remote,
078: int remote_port, boolean verbose, boolean debug) {
079: this .local = local;
080: this .local_port = local_port;
081: this .remote = remote;
082: this .remote_port = remote_port;
083: Proxy.verbose = verbose;
084: Proxy.debug = debug;
085: }
086:
087: public Proxy(InetAddress local, int local_port, InetAddress remote,
088: int remote_port, boolean verbose, boolean debug,
089: String mapping_file) {
090: this (local, local_port, remote, remote_port, verbose, debug);
091: this .mapping_file = mapping_file;
092: }
093:
094: public void start() throws Exception {
095: Map.Entry entry;
096: Selector selector;
097: ServerSocketChannel sock_channel;
098: MyInetSocketAddress key, value;
099:
100: if (remote != null && local != null)
101: mappings.put(new InetSocketAddress(local, local_port),
102: new InetSocketAddress(remote, remote_port));
103:
104: if (mapping_file != null) {
105: try {
106: populateMappings(mapping_file);
107: } catch (Exception ex) {
108: log("Failed reading " + mapping_file);
109: throw ex;
110: }
111: }
112:
113: log("\nProxy started at " + new java.util.Date());
114:
115: if (verbose) {
116: log("\nMappings:\n---------");
117: for (Iterator it = mappings.entrySet().iterator(); it
118: .hasNext();) {
119: entry = (Map.Entry) it.next();
120: log(toString((InetSocketAddress) entry.getKey())
121: + " <--> "
122: + toString((InetSocketAddress) entry.getValue()));
123: }
124: log("\n");
125: }
126:
127: // 1. Create a Selector
128: selector = Selector.open();
129:
130: // Create a thread pool (Executor)
131: executor = new PooledExecutor(MAX_THREAD_POOL_SIZE);
132:
133: for (Iterator it = mappings.keySet().iterator(); it.hasNext();) {
134: key = (MyInetSocketAddress) it.next();
135: value = (MyInetSocketAddress) mappings.get(key);
136:
137: // if either source or destination are SSL, we cannot use JDK 1.4
138: // NIO selectors, but have to fall back on separate threads per connection
139:
140: if (key.ssl() || value.ssl()) {
141: // if(2 == 2) {
142: SocketAcceptor acceptor = new SocketAcceptor(key, value);
143: executor.execute(acceptor);
144: continue;
145: }
146:
147: // 2. Create a ServerSocketChannel
148: sock_channel = ServerSocketChannel.open();
149: sock_channel.configureBlocking(false);
150: sock_channel.socket().bind(key);
151:
152: // 3. Register the selector with all server sockets. 'Key' is attachment, so we get it again on
153: // select(). That way we can associate it with the mappings hashmap to find the corresponding
154: // value
155: sock_channel
156: .register(selector, SelectionKey.OP_ACCEPT, key);
157: }
158:
159: // 4. Start main loop. won't return until CTRL-C'ed
160: loop(selector);
161: }
162:
163: /** We handle only non-SSL connections */
164: void loop(Selector selector) {
165: Set ready_keys;
166: SelectionKey key;
167: ServerSocketChannel srv_sock;
168: SocketChannel in_sock, out_sock;
169: InetSocketAddress src, dest;
170:
171: while (true) {
172: if (verbose)
173: log("[Proxy] ready to accept connection");
174:
175: // 4. Call Selector.select()
176: try {
177: selector.select();
178:
179: // get set of ready objects
180: ready_keys = selector.selectedKeys();
181: for (Iterator it = ready_keys.iterator(); it.hasNext();) {
182: key = (SelectionKey) it.next();
183: it.remove();
184:
185: if (key.isAcceptable()) {
186: srv_sock = (ServerSocketChannel) key.channel();
187: // get server socket and attachment
188: src = (InetSocketAddress) key.attachment();
189: in_sock = srv_sock.accept(); // accept request
190: if (verbose)
191: log("Proxy.loop()",
192: "accepted connection from "
193: + toString(in_sock));
194: dest = (InetSocketAddress) mappings.get(src);
195: // find corresponding dest
196: if (dest == null) {
197: in_sock.close();
198: log("Proxy.loop()",
199: "did not find a destination host for "
200: + src);
201: continue;
202: } else {
203: if (verbose)
204: log("Proxy.loop()",
205: "relaying traffic from "
206: + toString(src)
207: + " to "
208: + toString(dest));
209: }
210:
211: // establish connection to destination host
212: try {
213: out_sock = SocketChannel.open(dest);
214: // uses thread pool (Executor) to handle request, closes socks at end
215: handleConnection(in_sock, out_sock);
216: } catch (Exception ex) {
217: in_sock.close();
218: throw ex;
219: }
220: }
221: }
222: } catch (Exception ex) {
223: log("Proxy.loop()", "exception: " + ex);
224: }
225: }
226: }
227:
228: // void handleConnection(Socket in_sock, Socket out_sock) {
229: // try {
230: // Relayer r=new Relayer(in_sock, out_sock);
231: // executor.execute(r);
232: // r=new Relayer(out_sock, in_sock);
233: // executor.execute(r);
234: // }
235: // catch (Exception ex) {
236: // log("Proxy.handleConnection()", "exception: " + ex);
237: // }
238: // finally {
239: // close(in_sock, out_sock);
240: // }
241: // }
242:
243: void handleConnection(SocketChannel in, SocketChannel out) {
244: try {
245: _handleConnection(in, out);
246: } catch (Exception ex) {
247: log("Proxy.handleConnection()", "exception: " + ex);
248: }
249: }
250:
251: void _handleConnection(final SocketChannel in_channel,
252: final SocketChannel out_channel) throws Exception {
253: executor.execute(new Runnable() {
254: public void run() {
255: Selector sel = null;
256: SocketChannel tmp;
257: Set ready_keys;
258: SelectionKey key;
259: ByteBuffer transfer_buf = ByteBuffer.allocate(BUFSIZE);
260:
261: try {
262: sel = Selector.open();
263: in_channel.configureBlocking(false);
264: out_channel.configureBlocking(false);
265: in_channel.register(sel, SelectionKey.OP_READ);
266: out_channel.register(sel, SelectionKey.OP_READ);
267:
268: while (sel.select() > 0) {
269: ready_keys = sel.selectedKeys();
270: for (Iterator it = ready_keys.iterator(); it
271: .hasNext();) {
272: key = (SelectionKey) it.next();
273: it.remove(); // remove current entry (why ?)
274: tmp = (SocketChannel) key.channel();
275: if (tmp == null) {
276: log("Proxy._handleConnection()",
277: "attachment is null, continuing");
278: continue;
279: }
280: if (key.isReadable()) { // data is available to be read from tmp
281: if (tmp == in_channel) {
282: // read all data from in_channel and forward it to out_channel (request)
283: if (relay(tmp, out_channel,
284: transfer_buf) == false)
285: return;
286: }
287: if (tmp == out_channel) {
288: // read all data from out_channel and forward it
289: // to in_channel (response)
290: if (relay(tmp, in_channel,
291: transfer_buf) == false)
292: return;
293: }
294: }
295: }
296: }
297: } catch (Exception ex) {
298: ex.printStackTrace();
299: return;
300: } finally {
301: close(sel, in_channel, out_channel);
302: }
303: }
304: });
305: }
306:
307: void close(Selector sel, SocketChannel in_channel,
308: SocketChannel out_channel) {
309: try {
310: if (sel != null)
311: sel.close();
312: } catch (Exception ex) {
313: }
314: try {
315: if (in_channel != null)
316: in_channel.close();
317: } catch (Exception ex) {
318: }
319: try {
320: if (out_channel != null)
321: out_channel.close();
322: } catch (Exception ex) {
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 from, SocketChannel to, ByteBuffer buf)
331: throws Exception {
332: int num;
333: StringBuffer sb;
334:
335: buf.clear();
336: while (true) {
337: num = from.read(buf);
338: if (num < 0)
339: return false;
340: else if (num == 0)
341: return true;
342: buf.flip();
343: if (verbose) {
344: log(printRelayedData(toString(from), toString(to), buf
345: .remaining()));
346: }
347: if (debug) {
348: sb = new StringBuffer();
349: sb.append(new String(buf.array()).trim());
350: sb.append('\n');
351: log(sb.toString());
352: }
353: to.write(buf);
354: buf.flip();
355: }
356: }
357:
358: String toString(SocketChannel ch) {
359: StringBuffer sb = new StringBuffer();
360: Socket sock;
361:
362: if (ch == null)
363: return null;
364: if ((sock = ch.socket()) == null)
365: return null;
366: sb.append(sock.getInetAddress().getHostName()).append(':')
367: .append(sock.getPort());
368: return sb.toString();
369: }
370:
371: String toString(InetSocketAddress addr) {
372: StringBuffer sb = new StringBuffer();
373:
374: if (addr == null)
375: return null;
376: sb.append(addr.getAddress().getHostName()).append(':').append(
377: addr.getPort());
378: if (addr instanceof MyInetSocketAddress)
379: sb.append(" [ssl=").append(
380: ((MyInetSocketAddress) addr).ssl()).append(']');
381: return sb.toString();
382: }
383:
384: static String printRelayedData(String from, String to, int num_bytes) {
385: StringBuffer sb = new StringBuffer();
386: sb.append("\n[PROXY] ").append(from);
387: sb.append(" to ").append(to);
388: sb.append(" (").append(num_bytes).append(" bytes)");
389: // log("Proxy.relay()", sb.toString());
390: return sb.toString();
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 filename) throws Exception {
403: FileInputStream in = new FileInputStream(filename);
404: BufferedReader reader;
405: String line;
406: URI key, value;
407: int index;
408: boolean ssl_key, ssl_value;
409: final String 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("#")
415: || line.length() == 0)
416: continue;
417: index = line.indexOf('=');
418: if (index == -1)
419: throw new Exception(
420: "Proxy.populateMappings(): detected no '=' character in "
421: + line);
422: key = new URI(line.substring(0, index));
423: ssl_key = key.getScheme().trim().equals(HTTPS);
424:
425: value = new URI(line.substring(index + 1));
426: ssl_value = value.getScheme().trim().equals(HTTPS);
427:
428: check(key);
429: check(value);
430:
431: log("key: " + key + ", value: " + value);
432:
433: mappings.put(new MyInetSocketAddress(key.getHost(), key
434: .getPort(), ssl_key), new MyInetSocketAddress(value
435: .getHost(), value.getPort(), ssl_value));
436: }
437: in.close();
438: }
439:
440: /** Checks whether a URI is http(s)://<host>:<port> */
441: void check(URI u) throws Exception {
442: if (u.getScheme() == null)
443: throw new Exception("scheme is null in " + u
444: + ", (valid URI is \"http(s)://<host>:<port>\")");
445:
446: if (u.getHost() == null)
447: throw new Exception("host is null in " + u
448: + ", (valid URI is \"http(s)://<host>:<port>\")");
449:
450: if (u.getPort() <= 0)
451: throw new Exception("port is <=0 in " + u
452: + ", (valid URI is \"http(s)://<host>:<port>\")");
453:
454: }
455:
456: /** Input is "host:port" */
457: SocketAddress strToAddr(String input) throws Exception {
458: StringTokenizer tok = new StringTokenizer(input, ":");
459: String host, port;
460:
461: host = tok.nextToken();
462: port = tok.nextToken();
463: return new InetSocketAddress(host, Integer.parseInt(port));
464: }
465:
466: String printSelectionOps(SelectionKey key) {
467: StringBuffer sb = new StringBuffer();
468: if ((key.readyOps() & SelectionKey.OP_ACCEPT) != 0)
469: sb.append("OP_ACCEPT ");
470: if ((key.readyOps() & SelectionKey.OP_CONNECT) != 0)
471: sb.append("OP_CONNECT ");
472: if ((key.readyOps() & SelectionKey.OP_READ) != 0)
473: sb.append("OP_READ ");
474: if ((key.readyOps() & SelectionKey.OP_WRITE) != 0)
475: sb.append("OP_WRITE ");
476: return sb.toString();
477: }
478:
479: public static void main(String[] args) {
480: Proxy p;
481: InetAddress local = null, remote = null;
482: int local_port = 0, remote_port = 0;
483: String tmp, tmp_addr, tmp_port;
484: boolean verbose = false, debug = false;
485: int index;
486: String mapping_file = null;
487:
488: try {
489: for (int i = 0; i < args.length; i++) {
490: tmp = args[i];
491: if ("-help".equals(tmp)) {
492: help();
493: return;
494: }
495: if ("-verbose".equals(tmp)) {
496: verbose = true;
497: continue;
498: }
499: if ("-local".equals(tmp)) {
500: tmp_addr = args[++i];
501: index = tmp_addr.indexOf(':');
502: if (index > -1) { // it is in the format address:port
503: tmp_port = tmp_addr.substring(index + 1);
504: local_port = Integer.parseInt(tmp_port);
505: tmp_addr = tmp_addr.substring(0, index);
506: local = InetAddress.getByName(tmp_addr);
507: } else
508: local = InetAddress.getByName(args[++i]);
509: continue;
510: }
511: if ("-local_port".equals(tmp)) {
512: local_port = Integer.parseInt(args[++i]);
513: continue;
514: }
515: if ("-remote".equals(tmp)) {
516: tmp_addr = args[++i];
517: index = tmp_addr.indexOf(':');
518: if (index > -1) { // it is in the format address:port
519: tmp_port = tmp_addr.substring(index + 1);
520: remote_port = Integer.parseInt(tmp_port);
521: tmp_addr = tmp_addr.substring(0, index);
522: remote = InetAddress.getByName(tmp_addr);
523: } else
524: remote = InetAddress.getByName(args[++i]);
525: continue;
526: }
527: if ("-remote_port".equals(tmp)) {
528: remote_port = Integer.parseInt(args[++i]);
529: continue;
530: }
531: if ("-file".equals(tmp)) {
532: mapping_file = args[++i];
533: continue;
534: }
535: if ("-debug".equals(tmp)) {
536: debug = true;
537: continue;
538: }
539: help();
540: return;
541: }
542:
543: if (local == null)
544: local = InetAddress.getLocalHost();
545:
546: p = new Proxy(local, local_port, remote, remote_port,
547: verbose, debug, mapping_file);
548: p.start();
549: } catch (Throwable ex) {
550: ex.printStackTrace();
551: }
552: }
553:
554: static void help() {
555: System.out
556: .println("Proxy [-help] [-local <local address>] [-local_port <port>] "
557: + "[-remote <remote address>] [-remote_port <port>] [-verbose] "
558: + "[-file <mapping file>] [-debug]");
559: }
560:
561: static void log(String method_name, String msg) {
562: System.out.println('[' + method_name + "]: " + msg);
563: }
564:
565: static void log(String msg) {
566: System.out.println(msg);
567: }
568:
569: static void close(Socket in, Socket out) {
570: if (in != null) {
571: try {
572: in.close();
573: } catch (Exception ex) {
574: }
575: }
576: if (out != null) {
577: try {
578: out.close();
579: } catch (Exception ex) {
580: }
581: }
582: }
583:
584: static void close(Socket sock) {
585: if (sock != null) {
586: try {
587: sock.close();
588: } catch (Exception ex) {
589: }
590: }
591: }
592:
593: static class Relayer implements Runnable {
594: final Socket in_sock;
595: final Socket out_sock;
596: final InputStream in;
597: final OutputStream out;
598: Thread t = null;
599: final java.util.List listeners = new ArrayList();
600: String name = null;
601:
602: interface Listener {
603: void connectionClosed();
604: }
605:
606: public Relayer(Socket in_sock, Socket out_sock, String name)
607: throws Exception {
608: this .in_sock = in_sock;
609: this .out_sock = out_sock;
610: this .name = name;
611: in = in_sock.getInputStream();
612: out = out_sock.getOutputStream();
613: }
614:
615: public void addListener(Listener l) {
616: if (l != null && !listeners.contains(l))
617: listeners.add(l);
618: }
619:
620: public void run() {
621: byte[] buf = new byte[1024];
622: int num;
623: StringBuffer 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: //sb.append("forwarding ").append(num).append(" bytes from ").append(toString(in_sock));
635: //sb.append(" to ").append(toString(out_sock));
636: // log("Proxy.Relayer.run()", sb.toString());
637: log(printRelayedData(toString(in_sock),
638: toString(out_sock), num));
639: }
640: if (debug) {
641: sb = new StringBuffer();
642: sb.append(new String(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: } catch (Exception ex) {
652: log("Proxy.Relayer.run(): [" + name + "] exception="
653: + ex + ", in_sock=" + in_sock + ", out_sock="
654: + out_sock);
655: } finally {
656: stop();
657: }
658: }
659:
660: public void start() {
661: if (t == null) {
662: t = new Thread(this , "Proxy.Relayer");
663: t.setDaemon(true);
664: t.start();
665: }
666: }
667:
668: public void stop() {
669: t = null;
670: close(in_sock);
671: close(out_sock);
672: }
673:
674: String toString(Socket s) {
675: if (s == null)
676: return null;
677: return s.getInetAddress().getHostName() + ':' + s.getPort();
678: }
679:
680: void notifyListeners() {
681: for (Iterator it = listeners.iterator(); it.hasNext();) {
682: try {
683: ((Listener) it.next()).connectionClosed();
684: } catch (Throwable ex) {
685: ;
686: }
687: }
688: }
689: }
690:
691: static class MyInetSocketAddress extends InetSocketAddress {
692: boolean is_ssl = false;
693:
694: public MyInetSocketAddress(InetAddress addr, int port) {
695: super (addr, port);
696: }
697:
698: public MyInetSocketAddress(InetAddress addr, int port,
699: boolean is_ssl) {
700: super (addr, port);
701: this .is_ssl = is_ssl;
702: }
703:
704: public MyInetSocketAddress(int port) {
705: super (port);
706: }
707:
708: public MyInetSocketAddress(int port, boolean is_ssl) {
709: super (port);
710: this .is_ssl = is_ssl;
711: }
712:
713: public MyInetSocketAddress(String hostname, int port) {
714: super (hostname, port);
715: }
716:
717: public MyInetSocketAddress(String hostname, int port,
718: 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 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 {
739: ServerSocket srv_sock = null;
740: MyInetSocketAddress dest = null;
741:
742: /**
743: * Create an SSLServerSocket or ServerSocket and continuously call
744: * accept() on it.
745: * @param sock_addr
746: */
747: public SocketAcceptor(MyInetSocketAddress sock_addr,
748: MyInetSocketAddress dest) throws Exception {
749: this .dest = dest;
750: if (sock_addr.ssl()) {
751: srv_sock = createSSLServerSocket(sock_addr);
752: } else {
753: srv_sock = createServerSocket(sock_addr);
754: }
755: executor.execute(this );
756: }
757:
758: public void run() {
759: Connection conn;
760: Socket s, dest_sock;
761:
762: while (srv_sock != null) {
763: try {
764: s = srv_sock.accept();
765: dest_sock = dest.ssl() ? createSSLSocket(dest)
766: : createSocket(dest);
767: conn = new Connection(s, dest_sock);
768: conn.start();
769: } catch (Exception e) {
770: log("Proxy.SSLServerSocketAcceptor.run(): exception="
771: + e);
772: break;
773: }
774: }
775: }
776:
777: Socket createSocket(InetSocketAddress addr) throws Exception {
778: return new Socket(addr.getAddress(), addr.getPort());
779: }
780:
781: Socket createSSLSocket(InetSocketAddress addr) throws Exception {
782: SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory
783: .getDefault();
784: SSLSocket sslsocket = (SSLSocket) sslsocketfactory
785: .createSocket(addr.getAddress(), addr.getPort());
786: return sslsocket;
787: }
788:
789: ServerSocket createServerSocket(InetSocketAddress addr)
790: throws Exception {
791: return new ServerSocket(addr.getPort(), 10, addr
792: .getAddress());
793: }
794:
795: ServerSocket createSSLServerSocket(InetSocketAddress addr)
796: throws Exception {
797: SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory
798: .getDefault();
799: SSLServerSocket sslserversocket = (SSLServerSocket) sslserversocketfactory
800: .createServerSocket(addr.getPort(), 10, addr
801: .getAddress());
802: return sslserversocket;
803: }
804: }
805:
806: /**
807: * Handles an incoming SSLSocket or Socket. Looks up the destination in the
808: * mapping hashmap, key is the incoming socket address. Creates an outgoing
809: * socket (regular or SSL, depending on settings) and relays data between
810: * incoming and outgoing sockets. Closes the connection when either incoming
811: * or outgoing socket is closed, or when stop() is called.
812: *
813: * @author bela Dec 19, 2002
814: */
815: static class Connection implements Relayer.Listener {
816: Relayer in_to_out = null;
817: Relayer out_to_in = null;
818:
819: /**
820: * Creates an outgoing (regular or SSL) socket according to the mapping
821: * table. Sets both input and output stream. Caller needs to call
822: * start() after the instance has been created.
823: * @param in The Socket we got as result of accept()
824: * @throws Exception Thrown if either the input or output streams cannot
825: * be created.
826: */
827: public Connection(Socket in, Socket out) throws Exception {
828: in_to_out = new Relayer(in, out, "in-out");
829: in_to_out.addListener(this );
830: out_to_in = new Relayer(out, in, "out-in");
831: out_to_in.addListener(this );
832: }
833:
834: /** Starts relaying between incoming and outgoing sockets.
835: * Returns immediately (thread is started).
836: *
837: */
838: public void start() {
839: in_to_out.start();
840: out_to_in.start();
841: }
842:
843: public void stop() {
844: if (in_to_out != null) {
845: in_to_out.stop();
846: }
847: if (out_to_in != null) {
848: out_to_in.stop();
849: }
850: }
851:
852: public void connectionClosed() {
853: stop();
854: }
855: }
856:
857: }
|