import java.net.*;
import java.io.*;

/**
 * Throttle the connection between browser and server.
 *
 * Developer code - doesn't try to handle Exceptions,
 * just drops the connection.  The only Exceptions that should
 * occur are the browser/server dropping the connection,
 * so that's not a major problem.
 *
 * Throttling speed is per connection to the server, not
 * total bandwith.
 *
 *
 * By Steve Cotton - steve0001@s.cotton.clara.co.uk
 */
class Throttle
{
/* *************************************************************
 * Change these to configure the program.
 * Delays are in milliseconds.
 * *************************************************************/
	private static final int	fakeSocketNum		= 8080;
	private static final int	realSocketNum		= 80;
	private static final String realHostName		= "localhost";
	protected static final int	initDelay  			= 1000;
	protected static final int	per512BytesDelay	= 1000;
/* *************************************************************/
	

	public static void main(String argv[])
	{
		ServerSocket fakeServerSocket = null;

		/**
		 * Set up the fake server socket
		 */
		try{
			fakeServerSocket = new ServerSocket(fakeSocketNum); 
		}catch(IOException e){e.printStackTrace();}

		while (true)
		{
			try{
				Socket fakeSocket = fakeServerSocket.accept();	//blocks

				Socket realSocket = new Socket(realHostName, realSocketNum);
				InputStream  fakeIn  = fakeSocket.getInputStream ();
				InputStream  realIn  = realSocket.getInputStream ();
				OutputStream fakeOut = fakeSocket.getOutputStream();
				OutputStream realOut = realSocket.getOutputStream();

				new DataPusher(fakeIn, realOut);
				new DataPusher(realIn, fakeOut);
			}catch(IOException e){e.printStackTrace();}
		}
	}
}

/**
 * Runnable class that will pass data between two connections,
 */ 
class DataPusher extends Thread
{
	private  InputStream	in;
	private OutputStream out;

	public DataPusher(InputStream in, OutputStream out)
	{
		this. in= in;
		this.out=out;
		this.start();
	}

	/**
	 * This should simply block until there is data to read, then
	 * read it and send it to the output.
	 *
	 * But in.read() blocks the VM, not the thread, so we must do
	 * a semi-busy wait.
	 */
	public void run()
	{
		byte[] data=new byte[512];
		
		try{
			Thread.sleep(Throttle.initDelay);
		}catch(InterruptedException e){ }

		try{
			int status = 0;
			while( status != -1)
			{
				if(in.available() == 0)
				{
					yield();
				}
	
				try{
					Thread.sleep(Throttle.per512BytesDelay);
				}catch(InterruptedException e){ }
				
				status = in.read(data);
				if (status>0)
					out.write(data, 0, status);
			}
		}catch(Exception e){}

		try{
			in.close();
		}catch(Exception e){}

		try{
			out.close();
		}catch(Exception e){}
	}
}

