// java forwarder class
// waits for an inbound connection A on port INPORT
// when it is received, it launches a connection B to <OUTHOST,OUTPORT>
// and creates threads to read-B-write-A and read-A-write-B.

import java.net.*;
import java.io.*;
import java.util.*;
import java.text.*;

class forwarder {

public static String OUTHOST;
public static InetAddress OUTDEST;
public static short  OUTPORT = 22;
public static short  INPORT  = 2345;
public static boolean DEBUG  = true;

public static void main(String[] v) {

	// get command-line parameters

	if (v.length < 3) {
		System.err.println("args: inport outhost outport");
		return;
	}
	INPORT  = (short)(new Integer(v[0])).intValue();
	OUTHOST = v[1];
	OUTPORT = (short)(new Integer(v[2])).intValue();

	// DNS lookup, done just once!

	System.err.print("Looking up address of " + OUTHOST + "...");
	try {
		OUTDEST = InetAddress.getByName(OUTHOST);
	}
	catch (UnknownHostException uhe) {
		System.err.println("unknown host: " + OUTHOST);
		return;
	}
	System.err.println(" got it!");

	// initialize LISTENER socket
	// wait for connection

    	ServerSocket ss = null;
        ss = new ServerSocket(INPORT);		// needs try-catch

    	Socket s1;
    	while(true) { // accept loop
		s1 = ss.accept();		// needs try-catch
		// now set up the second connection from here to <OUTDEST,OUTPORT>,
		// represented by a second socket s2
		// Then create the two Copier instances, as described in the
		// project description, and start() the two threads.
		// At that point, this main loop simply continues
		// by going back to the ss.accept() call.
    	} // accept loop
}	// main


    /**
     * The Copier class handles unidirectional copying from one socket to another.
     * You will need to create two of these in the main loop above,
     * one for each direction. You create the Copier object, and then
     * create and start a Thread object that runs that Copier.
     * If c is your Copier instance (created with Copier c = new Copier(sock1, sock2)),
     * then the thread is Thread t = new Thread(c), and you start the thread
     * with t.start(). Or, in one step, (new Thread(c)).start()
     */

    static class Copier implements Runnable {
	private Socket _from;
	private Socket _to;

	public Copier (Socket from, Socket to) {
		_from = from;
		_to = to;
	}

	public void run() {
		InputStream  fis;
		OutputStream tos;
		try {
			fis = _from.getInputStream();
			tos = _to.getOutputStream();
		} catch (IOException ioe) {
			System.err.println("can't get IO streams from sockets");
			return;
		}

		byte[] buf = new byte[2048];

		int readsize;

		while (true) {

			try {
				readsize = fis.read(buf);
			} catch (IOException ioe) {
				break;
			}

			if (readsize <= 0) break;

			try {
				tos.write(buf, 0, readsize);
			} catch (IOException ioe) {
				break;
			}
		}

		// these should be safe close() calls!!
		try {
			fis.close();
			tos.close();

			_from.close();
			_to.close();
		} catch (IOException ioe) {
			System.err.println("can't close sockets or streams");
			return;
		}
	}
    }  // class Copier

} // class forwarder
