proxy.java

来自「JGRoups源码」· Java 代码 · 共 852 行 · 第 1/2 页

JAVA
852
字号
// $Id: Proxy.java,v 1.2 2005/07/17 11:33:58 chrislott Exp $package org.jgroups.util;import EDU.oswego.cs.dl.util.concurrent.Executor;import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;import javax.net.ssl.SSLServerSocket;import javax.net.ssl.SSLServerSocketFactory;import javax.net.ssl.SSLSocket;import javax.net.ssl.SSLSocketFactory;import java.io.*;import java.net.*;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.*;/** * Redirects incoming TCP connections to other hosts/ports. All redirections are defined in a file as for example * <pre> * 127.0.0.1:8888=www.ibm.com:80 * localhost:80=pop.mail.yahoo.com:110 * </pre> * The first line forwards all requests to port 8888 on to www.ibm.com at port 80 (it also forwards the HTTP * response back to the sender. The second line essentially provides a POP-3 service on port 8110, using * Yahoo's POP service. This is neat when you're behind a firewall and one of the few services in the outside * world that are not blocked is port 80 (HHTP).<br/> * Note that JDK 1.4 is required for this class. Also, concurrent.jar has to be on the classpath. Note that * you also need to include jsse.jar/jce.jar (same location as rt.jar) if you want SSL sockets.<br> * To create SSLServerSockets you'll need to do the following: * Generate a certificate as follows: * <pre> * keytool -genkey -keystore /home/bela/.keystore -keyalg rsa -alias bela -storepass <passwd> -keypass <passwd> * </pre> * * Start the Proxy as follows: * <pre> * java -Djavax.net.ssl.keyStore=/home/bela/.keystore -Djavax.net.ssl.keyStorePassword=<passwd> *      -Djavax.net.ssl.trustStore=/home/bela/.keystore -Djavax.net.ssl.trustStorePassword=<passwd> *      org.jgroups.util.Proxy -file /home/bela/map.properties * </pre> * Start client as follows: * <pre> * java -Djavax.net.ssl.trustStore=/home/bela/.keystore -Djavax.net.ssl.trustStorePassword=<passwd> sslclient * </pre> * <br/> * To import a certificate into the keystore, use the following steps: * <pre> * openssl x509 -in server.crt -out server.crt.der -outform DER * keytool -import -trustcacerts -alias <your alias name> -file server.crt.der * </pre> * This will store the server's certificate in the ${user.home}/.keystore key store. * <br/> * Note that an SSL client or server can be debugged by starting it as follows: * <pre>-Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl</pre> * <br/> * If you run a web browser, simply enter https://<host>:<port> as URL to connect to an SSLServerSocket * <br/>Note that we cannot use JDK 1.4's selectors for SSL sockets, as * getChannel() on an SSL socket doesn't seem to work. * @todo Check whether SSLSocket.getChannel() or SSLServerSocket.getChannel() works. * @author Bela Ban */public class Proxy {    InetAddress    local=null, remote=null;    int            local_port=0, remote_port=0;    static boolean verbose=false;    static boolean debug=false;    String         mapping_file=null; // contains a list of src and dest host:port pairs    final HashMap        mappings=new HashMap(); // keys=MyInetSocketAddr (src), values=MyInetSocketAddr (dest)    Executor       executor; // maintains a thread pool    static final int      MAX_THREAD_POOL_SIZE=64; // for processing requests    static final int      BUFSIZE=1024; // size of data transfer buffer    public Proxy(InetAddress local, int local_port, InetAddress remote, int remote_port, boolean verbose, boolean debug) {        this.local=local;        this.local_port=local_port;        this.remote=remote;        this.remote_port=remote_port;        Proxy.verbose=verbose;        Proxy.debug=debug;    }    public Proxy(InetAddress local, int local_port, InetAddress remote, int remote_port,                    boolean verbose, boolean debug, String mapping_file) {        this(local, local_port, remote, remote_port, verbose, debug);        this.mapping_file=mapping_file;    }    public void start() throws Exception {        Map.Entry           entry;        Selector            selector;        ServerSocketChannel sock_channel;        MyInetSocketAddress key, value;        if (remote !=null && local !=null)            mappings.put(new InetSocketAddress(local, local_port), new InetSocketAddress(remote, remote_port));                if (mapping_file !=null) {            try {                populateMappings(mapping_file);            }            catch (Exception ex) {                log("Failed reading " + mapping_file);                throw ex;            }        }        log("\nProxy started at " + new java.util.Date());        if (verbose) {            log("\nMappings:\n---------");            for (Iterator it=mappings.entrySet().iterator(); it.hasNext();) {                entry=(Map.Entry) it.next();                log(toString((InetSocketAddress) entry.getKey()) + " <--> "                    + toString((InetSocketAddress) entry.getValue()));            }            log("\n");        }        // 1. Create a Selector        selector=Selector.open();        // Create a thread pool (Executor)        executor=new PooledExecutor(MAX_THREAD_POOL_SIZE);        for (Iterator it=mappings.keySet().iterator(); it.hasNext();) {            key=(MyInetSocketAddress) it.next();            value=(MyInetSocketAddress) mappings.get(key);            // if either source or destination are SSL, we cannot use JDK 1.4            // NIO selectors, but have to fall back on separate threads per connection            if (key.ssl() || value.ssl()) {                // if(2 == 2) {                SocketAcceptor acceptor=new SocketAcceptor(key, value);                executor.execute(acceptor);                continue;            }            // 2. Create a ServerSocketChannel            sock_channel=ServerSocketChannel.open();            sock_channel.configureBlocking(false);            sock_channel.socket().bind(key);            // 3. Register the selector with all server sockets. 'Key' is attachment, so we get it again on            //    select(). That way we can associate it with the mappings hashmap to find the corresponding            //    value            sock_channel.register(selector, SelectionKey.OP_ACCEPT, key);        }        // 4. Start main loop. won't return until CTRL-C'ed                loop(selector);    }    /** We handle only non-SSL connections */    void loop(Selector selector) {        Set                 ready_keys;        SelectionKey        key;        ServerSocketChannel srv_sock;        SocketChannel       in_sock, out_sock;        InetSocketAddress   src, dest;        while (true) {            if (verbose)                log("[Proxy] ready to accept connection");            // 4. Call Selector.select()            try {                selector.select();                // get set of ready objects                ready_keys=selector.selectedKeys();                for (Iterator it=ready_keys.iterator(); it.hasNext();) {                    key=(SelectionKey) it.next();                    it.remove();                    if (key.isAcceptable()) {                        srv_sock=(ServerSocketChannel) key.channel();                        // get server socket and attachment                        src=(InetSocketAddress) key.attachment();                        in_sock=srv_sock.accept(); // accept request                        if (verbose)                            log("Proxy.loop()", "accepted connection from " + toString(in_sock));                        dest=(InetSocketAddress) mappings.get(src);                        // find corresponding dest                        if (dest == null) {                            in_sock.close();                            log("Proxy.loop()", "did not find a destination host for " + src);                            continue;                        }                        else {                            if (verbose)                                log("Proxy.loop()", "relaying traffic from " + toString(src) + " to " + toString(dest));                        }                        // establish connection to destination host                        try {                            out_sock=SocketChannel.open(dest);                            // uses thread pool (Executor) to handle request, closes socks at end                            handleConnection(in_sock, out_sock);                        }                        catch (Exception ex) {                            in_sock.close();                            throw ex;                        }                    }                }            }            catch (Exception ex) {                log("Proxy.loop()", "exception: " + ex);            }        }    }    //    void handleConnection(Socket in_sock, Socket out_sock) {    //        try {    //            Relayer r=new Relayer(in_sock, out_sock);    //            executor.execute(r);    //            r=new Relayer(out_sock, in_sock);    //            executor.execute(r);    //        }    //        catch (Exception ex) {    //            log("Proxy.handleConnection()", "exception: " + ex);    //        }    //        finally {    //            close(in_sock, out_sock);    //        }    //    }    void handleConnection(SocketChannel in, SocketChannel out) {        try {            _handleConnection(in, out);        }        catch (Exception ex) {            log("Proxy.handleConnection()", "exception: " + ex);        }    }        void _handleConnection(final SocketChannel in_channel, final SocketChannel out_channel) throws Exception {        executor.execute(new Runnable() {                public void run() {                    Selector sel=null;                    SocketChannel tmp;                    Set ready_keys;                    SelectionKey key;                    ByteBuffer transfer_buf=ByteBuffer.allocate(BUFSIZE);                    try {                        sel=Selector.open();                        in_channel.configureBlocking(false);                        out_channel.configureBlocking(false);                        in_channel.register(sel, SelectionKey.OP_READ);                        out_channel.register(sel, SelectionKey.OP_READ);                                                while (sel.select() > 0) {                            ready_keys=sel.selectedKeys();                            for (Iterator it=ready_keys.iterator(); it.hasNext();) {                                key=(SelectionKey) it.next();                                it.remove(); // remove current entry (why ?)                                tmp=(SocketChannel) key.channel();                                if (tmp == null) {                                    log(                                        "Proxy._handleConnection()",                                        "attachment is null, continuing");                                    continue;                                }                                if (key.isReadable()) { // data is available to be read from tmp                                    if (tmp == in_channel) {                                        // read all data from in_channel and forward it to out_channel (request)                                        if (relay(tmp, out_channel, transfer_buf) == false)                                            return;                                    }                                    if (tmp == out_channel) {                                        // read all data from out_channel and forward it                                         // to in_channel (response)                                        if (relay(tmp, in_channel, transfer_buf) == false)                                            return;                                    }                                }                            }                        }                    }                    catch (Exception ex) {                        ex.printStackTrace();                        return;                    }                    finally {                        close(sel, in_channel, out_channel);                    }                }            });    }        void close(Selector sel, SocketChannel in_channel, SocketChannel out_channel) {        try {            if (sel !=null)                sel.close();        }        catch (Exception ex) {        }        try {            if (in_channel !=null)                in_channel.close();        }        catch (Exception ex) {        }        try {            if (out_channel !=null)                out_channel.close();        }        catch (Exception ex) {        }    }    /**     * Read all data from <code>from</code> and write it to <code>to</code>.     * Returns false if channel was closed     */    boolean relay(SocketChannel from, SocketChannel to, ByteBuffer buf) throws Exception {        int num;        StringBuffer sb;        buf.clear();        while (true) {            num=from.read(buf);            if (num < 0)                return false;            else                if (num == 0)                    return true;            buf.flip();            if (verbose) {                log(printRelayedData(toString(from), toString(to), buf.remaining()));            }            if (debug) {                sb=new StringBuffer();                sb.append(new String(buf.array()).trim());                sb.append('\n');                log(sb.toString());            }            to.write(buf);            buf.flip();        }    }    String toString(SocketChannel ch) {        StringBuffer sb=new StringBuffer();        Socket sock;        if (ch == null)            return null;        if ((sock=ch.socket()) == null)            return null;        sb.append(sock.getInetAddress().getHostName()).append(':').append(sock.getPort());        return sb.toString();    }    String toString(InetSocketAddress addr) {        StringBuffer sb=new StringBuffer();        if (addr == null)            return null;        sb.append(addr.getAddress().getHostName()).append(':').append(addr.getPort());        if (addr instanceof MyInetSocketAddress)            sb.append(" [ssl=").append(((MyInetSocketAddress) addr).ssl()).append(']');        return sb.toString();    }        static String printRelayedData(String from, String to, int num_bytes) {        StringBuffer sb=new StringBuffer();        sb.append("\n[PROXY] ").append(from);        sb.append(" to ").append(to);        sb.append(" (").append(num_bytes).append(" bytes)");        // log("Proxy.relay()", sb.toString());        return sb.toString();    }        /**     * Populates <code>mappings</code> hashmap. An example of a definition file is:     * <pre>     * http://localhost:8888=http://www.yahoo.com:80     * https://localhost:2200=https://cvs.sourceforge.net:22     * http://localhost:8000=https://www.ibm.com:443     * </pre>     * Mappings can be http-https, https-http, http-http or https-https     */    void populateMappings(String filename) throws Exception {        FileInputStream   in=new FileInputStream(filename);        BufferedReader    reader;        String            line;        URI               key, value;        int               index;        boolean           ssl_key, ssl_value;        final String      HTTPS="https";        reader=new BufferedReader(new InputStreamReader(in));        while ((line=reader.readLine()) !=null) {            line=line.trim();            if (line.startsWith("//") || line.startsWith("#") || line.length() == 0)                continue;            index=line.indexOf('=');            if (index == -1)                throw new Exception("Proxy.populateMappings(): detected no '=' character in " + line);            key=new URI(line.substring(0, index));            ssl_key=key.getScheme().trim().equals(HTTPS);            value=new URI(line.substring(index + 1));            ssl_value=value.getScheme().trim().equals(HTTPS);            check(key);            check(value);            log("key: " + key + ", value: " + value);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?