package com.halogen.hacks;

import java.io.*;
import java.net.*;
import java.lang.ref.*;

import java.util.Vector;

/**
 * Simple Java application that listens on a local port (LOCAL_PORT) and forwards
 * all traffic to a remote host and port (REMOTE_HOST and REMOTE_PORT).
 *
 * Copyright (c) 2001, Rasmus Sten &lt;rasmus@halogen.com&gt;
 */
class ArbProxy extends Thread {
	static int LOCAL_PORT = 4711;
	static int REMOTE_PORT = 23;
	static String REMOTE_HOST = "bigblue";

	static int counter = 0;

	static Vector threads = new Vector();

	public static void main(String[] argv) {
		ServerSocket srv = null;
		try {
			srv = new ServerSocket(LOCAL_PORT);
		} catch (IOException ex) {
			err("failed to bind port " + ex.getMessage());
			System.exit(-1);
		}
		log("now listening on port " + LOCAL_PORT);
		while (srv != null) {
			try {
				Socket c = srv.accept(); // blocks until connect
				log("accepted connection from " + c.getInetAddress());
				Socket s = new Socket(REMOTE_HOST, REMOTE_PORT);
				new ArbProxy(c, s, true).start();
				new ArbProxy(c, s, false).start();
			} catch (IOException ex) {
				err("accept() or connect failed: " + ex.getMessage());
			}

		}
	}

	int id;
	boolean clientReader;
	Socket client, server;
	public ArbProxy(Socket client, Socket server, boolean clientReader) {
		id = counter++;
		this.client = client;
		this.server = server;
		this.clientReader = clientReader;
	}

	public void run() {
		try {
			InputStream clientInput = client.getInputStream();
			OutputStream clientOutput = client.getOutputStream();
			InputStream serverInput = server.getInputStream();
			OutputStream serverOutput = server.getOutputStream();

			int b = 0;
			while ((b = (clientReader ? clientInput.read() : serverInput.read())) > -1) {
				if (clientReader) {
					serverOutput.write((char) b);
				} else {
					clientOutput.write((char) b);
				}
			}
			if (b == -1) {
				log(this +" received EOF");
				if (clientReader) server.close();
				else client.close();
			}
		} catch (IOException ex) {
			err(this +" I/O error: " + ex.getMessage());
		} finally {
			log(this +" exiting");
		}
	}

	public static synchronized void err(String s) {
		System.err.println(s);
	}
	
	public static synchronized void log(String s) {
		System.out.println(s);
	}
	
	public String toString() {
		return "ArbProxy#"
			+ id
			+ "["
			+ (clientReader ? "reading from client" : "reading from server")
			+ "]"; 
	}
}