summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/taskmanager/tasks/DirectedRelay.java
blob: fffd707f001fa6379617900a5e9bbe93f85ef218 (plain) (tree)





























































































































































































                                                                                                                    
package org.openslx.taskmanager.tasks;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.openslx.taskmanager.api.AbstractTask;

import com.google.gson.annotations.Expose;

public class DirectedRelay extends AbstractTask 
{
	
	protected Output status = new Output();
	
	@Expose
	public String ip;
	@Expose 
	public int port;
	
	@Override
	protected boolean execute()
	{
		SSLContext ctx = getSSLContext();
		if ( ctx == null )
			return false;
		
		try ( SSLSocket dbgSock = getDbgSock( ctx );
				SSLServerSocket srvSock = getSrvSock( ctx ) ) {
			connectToDbg( dbgSock );
			bindToPort( srvSock );
			try ( SSLSocket poolSock = ( SSLSocket ) srvSock.accept() ) {
				status.addMessage( "INFO: Connection from pool client established." );
				relay( dbgSock, poolSock );
			} catch ( Exception ex ) {
				throw( ex );
			}
		} catch ( Exception e ) {
			status.addMessage( "ERROR: " + e.getMessage() );
			return false;
		}
		return true;		
	}
	
	protected void connectToDbg ( SSLSocket dbgSock ) throws IOException {
		InetSocketAddress addr = new InetSocketAddress( ip, port );
		dbgSock.connect( addr );
		status.addMessage( "INFO: Connected to debug server at " + ip + ":" + port + "." );
		status.setDbgAddr( addr );
	}
	
	protected void bindToPort ( SSLServerSocket srvSock ) throws IOException {
		srvSock.bind( null );
		status.setListenPort( srvSock.getLocalPort() );
		status.addMessage( "INFO: Listening on localhost:" + status.getListenPort() + "." );
	}
	
	protected SSLContext getSSLContext() {
		SSLContext ctx = null;
		try {
			ctx = trustAll();
			status.addMessage( "INFO: SSLContext created." );
		} catch ( Exception e ) {
			status.addMessage( "ERROR: Failed to create SSLContext." );
		}
		return ctx;
	}

	private boolean relay( SSLSocket dbgSock, SSLSocket poolSock ) {
		Relay toDbg = new Relay( poolSock, dbgSock, status );
		Relay toPool = new Relay( dbgSock, poolSock, status );
		toDbg.setName( "PoolToDebug" );
		toPool.setName( "DebugToPool" );
		toDbg.start();
		toPool.start();
		
		try {
			for ( Relay r : new Relay[]{ toDbg, toPool })
				r.join();
		} catch ( InterruptedException ix ) {
			status.addMessage( "INFO: Relay closed: " + Thread.currentThread().getName() );
		}
			
		return true;
	}
	
	protected SSLContext trustAll () throws Exception 
	{
		TrustManager[] trustAllMgr = new TrustManager[] { new X509TrustManager() {
				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;
				}
				public void checkClientTrusted( X509Certificate[] certs, String authType ) {}
				public void checkServerTrusted( X509Certificate[] certs, String authType ) {}
			}
		};
		SSLContext ctx = SSLContext.getInstance( "SSL" );
		ctx.init( null, trustAllMgr, new java.security.SecureRandom() );
		return ctx;
	}

	private SSLServerSocket getSrvSock( SSLContext ctx ) throws IOException
	{
		SSLServerSocketFactory sssf = ctx.getServerSocketFactory();
		return ( SSLServerSocket ) sssf.createServerSocket();
	}

	private SSLSocket getDbgSock( SSLContext ctx ) throws IOException
	{
		SSLSocketFactory ssf = ctx.getSocketFactory();
		return ( SSLSocket ) ssf.createSocket();
	}
	
	@Override
	protected boolean initTask() 
	{
		this.setStatusObject( this.status );
		status.addMessage( "INFO: Initiating directed relay to debug server at: " + ip + ":" + port + "." );
		return true;
	}
	
	public static class Output 
	{		
		
		protected String messages = null;
		protected Date d = null;
		protected InetSocketAddress dbgAddr = null;
		protected int listenPort;
		
		public void setListenPort ( int port ) { listenPort = port; }
		public int getListenPort ()	{ return listenPort; }
		public void setDbgAddr ( InetSocketAddress addr ) { dbgAddr = addr;	}
		
		public void addMessage( String str )
		{
			d = new Date();
			if ( messages == null ) {
				messages = d.toString() + "-" + str;
			} else {
				messages += "\n" + d.toString() + "-" + str;
			}
		}
	}
	
	private class Relay extends Thread
	{
		boolean active = true;
		private byte[] buffer = new byte[16384];
		
		private SSLSocket srcSock;
		private SSLSocket destSock;
		
		private Output status;
		
		public Relay ( SSLSocket srcSock, SSLSocket destSock, Output status ) {
			this.srcSock = srcSock;
			this.destSock = destSock;
			this.status = status;
		}
		
		@Override
		public void run() {
			boolean first = true;
			int readBytes;
			try ( InputStream in = srcSock.getInputStream();
					OutputStream out = destSock.getOutputStream() ) {
				while( active ) {
					readBytes = in.read( buffer );
					out.write( buffer, 0, readBytes );
					if ( first )
						status.addMessage( "INFO: Relay operating: " + this.getName() );
				}	
			} catch ( Exception e ) {
				active = false;
				return;
			}
		}	
	}
}