// $Id: Proxy.java,v 1.3.4.1 2008/01/22 10:01:16 belaban Exp
$
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
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.*;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
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
MIN_THREAD_POOL_SIZE=2;
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
ThreadPoolExecutor(MIN_THREAD_POOL_SIZE, MAX_THREAD_POOL_SIZE,
30000, TimeUnit.MILLISECONDS,
new
LinkedBlockingQueue(1000));
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);
}
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()
tr