--- /dev/null
+<?xml version="1.0"?>
+
+<!DOCTYPE project [
+ <!ENTITY header SYSTEM "file:../build/header.xml">
+ <!ENTITY trailer SYSTEM "file:../build/trailer.xml">
+]>
+
+<project name="socketproxy" default="jar" basedir=".">
+
+
+ <!-- =============================================================================== -->
+ <!-- Include the build header defining general properties -->
+ <!-- =============================================================================== -->
+ <property name="project.home" value=".."/>
+ <property name="module.name" value="socketproxy" />
+
+ &header;
+
+ <target name="module.build.deps"
+ depends="">
+ </target>
+
+ <!-- Set libraries to use in addition for test, a library which
+ is already mentioned in module.build.path should not be
+ mentioned below again -->
+ <target name="module.test.deps" depends="">
+ </target>
+
+ &trailer;
+
+
+</project>
--- /dev/null
+package org.wamblee.socketproxy;
+
+/**
+ * Copyright (c) 2005 UPS_SCS NL
+ *
+ */
+
+public class Barrier {
+
+ private int _countLeft;
+
+ public Barrier( int aCount ) {
+ _countLeft = aCount;
+ }
+
+ public synchronized void block( ) {
+ _countLeft--;
+ if ( _countLeft < 0 ) {
+ throw new IllegalStateException(
+ "Barrier count became negative, programming error" );
+ }
+ notifyAll( );
+ while ( _countLeft > 0 ) {
+ waitUninterruptable( );
+ }
+ }
+
+ private void waitUninterruptable( ) {
+ try {
+ wait( );
+ } catch ( InterruptedException e ) {
+ // ignore.
+ }
+ }
+
+}
--- /dev/null
+package org.wamblee.socketproxy;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Forwarder thread which handles forwarding of an input stream to
+ * an output stream.
+ */
+
+public class ForwarderThread extends Thread {
+
+ private String _prefix;
+
+ private Barrier _barrier;
+
+ private InputStream _is;
+
+ private OutputStream _os;
+
+ /**
+ * Constructs the forwarder thread.
+ * @param aPrefix Prefix to use in the output.
+ * @param aBarrier Barrier to block on before actually closing the stream.
+ * This is done to make sure that connections are only closed in th e
+ * proxy when the forwarders in both directions are ready to close.
+ * @param aIs Input stream to read from.
+ * @param aOs Output stream to forward to.
+ */
+ public ForwarderThread( String aPrefix, Barrier aBarrier,
+ InputStream aIs, OutputStream aOs ) {
+ _prefix = aPrefix;
+ _is = aIs;
+ _os = aOs;
+ _barrier = aBarrier;
+ }
+
+ public void run( ) {
+ boolean firstChar = true;
+ try {
+ int c = _is.read( );
+ while ( c > 0 ) {
+ try {
+ _os.write( c );
+ _os.flush( );
+ if ( firstChar ) {
+ System.out.print( _prefix );
+ firstChar = false;
+ }
+ System.out.print( (char) c );
+ if ( c == '\n' ) {
+ firstChar = true;
+ }
+ } catch ( IOException e ) {
+ }
+
+ c = _is.read( );
+ }
+ } catch ( IOException e ) {
+ }
+ closeStreams();
+ }
+
+ /**
+ * @param is
+ * @param os
+ */
+ private void closeStreams( ) {
+ _barrier.block( ); // wait until the other forwarder for the other direction
+ // is also closed.
+ try {
+ _is.close( );
+ } catch ( IOException e1 ) {
+ // Empty.
+ }
+ try {
+ _os.flush( );
+ _os.close( );
+ } catch ( IOException e1 ) {
+ // Empty
+ }
+ System.out.println(_prefix + " closed");
+ }
+
+}
--- /dev/null
+package org.wamblee.socketproxy;
+
+/*
+ * Created on Apr 5, 2005
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * @author erik
+ *
+ * TODO To change the template for this generated type comment go to Window -
+ * Preferences - Java - Code Style - Code Templates
+ */
+public class SocketProxy {
+
+ public static void main( final String[] args ) throws IOException {
+ for ( int i = 0; i < args.length; i++ ) {
+ // System.out.println(i + " " + args[i]);
+ String[] fields = args[i].split( ":" );
+ final int localPort = Integer.parseInt( fields[0] );
+ final String host = fields[1];
+ final int remotePort = Integer.parseInt( fields[2] );
+ runSocketProxy( localPort, host, remotePort );
+ }
+ }
+
+ /**
+ * @param localPort
+ * @param host
+ * @param remotePort
+ */
+ private static void runSocketProxy( final int localPort,
+ final String host, final int remotePort ) {
+ new Thread( new Runnable( ) {
+ public void run( ) {
+ try {
+ new SocketProxy( localPort, host, remotePort );
+ } catch ( IOException e ) {
+ System.out.println( "Problem with socket " + localPort
+ + ":" + host + ":" + remotePort );
+ e.printStackTrace( );
+ }
+ }
+ } ).start( );
+ }
+
+ public SocketProxy( int localPort, String remoteHost, int remotePort )
+ throws IOException {
+ System.out.println( "Listening on port " + localPort );
+ ServerSocket server = new ServerSocket( localPort );
+ for ( ;; ) {
+ Socket socket = server.accept( );
+ System.out.println( "Got local connection on port "
+ + localPort );
+ InputStream localIs = socket.getInputStream( );
+ OutputStream localOs = socket.getOutputStream( );
+ Socket clientSocket = new Socket( remoteHost, remotePort );
+ final String description = "Port forwarding: " + localPort
+ + " -> " + remoteHost + ":" + remotePort;
+ System.out.println( description + " established." );
+ InputStream serverIs = clientSocket.getInputStream( );
+ OutputStream serverOs = clientSocket.getOutputStream( );
+ Barrier barrier = new Barrier(2);
+ final Thread t1 = runForwarder( barrier, "> ", localIs, serverOs );
+ final Thread t2 = runForwarder( barrier, "< ", serverIs, localOs );
+ waitForConnectionClose( description, t1, t2 );
+ }
+ }
+
+ /**
+ * @param description
+ * @param t1
+ * @param t2
+ */
+ private void waitForConnectionClose( final String description,
+ final Thread t1, final Thread t2 ) {
+ new Thread( new Runnable( ) {
+ public void run( ) {
+ try {
+ t1.join( );
+ t2.join( );
+ } catch ( InterruptedException e ) {
+ e.printStackTrace( );
+ }
+ System.out.println( description + " closed" );
+ }
+ } ).start( );
+ }
+
+ private Thread runForwarder( final Barrier barrier, final String prefix,
+ final InputStream is, final OutputStream os ) {
+ Thread t = new ForwarderThread(prefix, barrier, is, os);
+ t.start( );
+ return t;
+ }
+}