public interface Handler {
public void handle();
}
public class Proxy {
public static final int DEFAULT_PORT = 1080;
public static final int DEFAULT_VERSION = 0x05;
private Socket socket;
private ThreadPoolExecutor ioexecutor;
private int version;
private int method;
public Proxy(String host) throws IOException {
this(host, DEFAULT_PORT);
}
public Proxy(String host, int port) throws IOException {
this.socket = new Socket(host, port);
this.ioexecutor = new ThreadPoolExecutor(8, 50, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
this.version = DEFAULT_VERSION;
}
private void initConfig(Properties conf) {
String ver = conf.getProperty("ver");
if (ver != null) {
version = Integer.parseInt(ver);
}
}
public void init(Properties conf) throws IOException {
initConfig(conf);
Nego nego = new Nego(this);
String methods = conf.getProperty("methods");
if (methods != null) {
String[] ss = methods.split(" ");
for (String s : ss) {
nego.setMethod(Integer.parseInt(s));
}
}
nego.setHandler(new NegotiationReplyHandler(this));
ioexecutor.execute(nego);
}
public int version() {
return version;
}
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
public void setMethod(int method) {
this.method = method;
}
public int getMethod() {
return method;
}
/**
* negotiation reply message handler
*/
private static class NegotiationReplyHandler implements Handler {
private Proxy proxy;
public NegotiationReplyHandler(Proxy proxy) {
this.proxy = proxy;
}
@Override
public void handle() {
try {
InputStream is = proxy.getInputStream();
ByteArrayOutputStream rs = new ByteArrayOutputStream();
byte[] bytes = new byte[128];
int nbyte = -1;
while ((nbyte = is.read(bytes)) != -1) {
rs.write(bytes, 0, nbyte);
if (rs.size() == 2) {
break;
}
}
bytes = rs.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
bis.read();
int method = bis.read();
System.out.println("method selected: " + method);
proxy.setMethod(method);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class Nego extends Thread {
private Proxy proxy;
private Set<Integer> methods;
private Handler handler;
public Nego(Proxy proxy) {
this.proxy = proxy;
this.methods = new HashSet<Integer>();
}
public void setMethods(Set<Integer> newmethods) {
methods.addAll(newmethods);
}
public void setMethod(int method) {
methods.add(method);
}
public void setHandler(Handler handler) {
this.handler = handler;
}
private void write(ByteArrayOutputStream buffer) throws IOException {
OutputStream os = proxy.getOutputStream();
os.write(buffer.toByteArray());
os.flush();
}
public void run() {
if (handler == null) {
throw new NullPointerException("handler is null");
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write((proxy.version() << 24) >> 24);
if (methods.isEmpty()) {
methods.add(0x00);
}
bos.write((methods.size() << 24) >> 24);
for (Integer method : methods) {
bos.write((method << 24) >> 24);
}
try {
write(bos);
} catch (IOException e) {
e.printStackTrace();
}
handler.handle();
}
}
// private static String host = "198.41.0.4";
private static String host = "localhost";
private static int port = 1080;
private static Proxy proxy;
@BeforeClass
public static void initialize() throws IOException {
proxy = new Proxy(host, port);
Properties conf = new Properties();
// conf.setProperty("methods", "0 1 2 3 255");
proxy.init(conf);
}
@Test
public void test() throws IOException, InterruptedException {
Thread.sleep(10000);
}