package org.openslx.imagemaster.serverconnection; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import org.apache.log4j.Logger; import org.openslx.filetransfer.Downloader; import org.openslx.filetransfer.IncomingEvent; import org.openslx.filetransfer.Listener; import org.openslx.filetransfer.Uploader; import org.openslx.imagemaster.Globals; /** * Class to handle all incoming and outgoing connections. */ public class ConnectionHandler implements IncomingEvent { private static Logger log = Logger.getLogger( ConnectionHandler.class ); private static SSLContext sslContext; private static Map connections = new ConcurrentHashMap<>(); private static IncomingEvent eventHandler = new ConnectionHandler(); private static Listener listener; static { log.debug( "Starting listener on port " + Globals.getSslSocketPort() ); try { String pathToKeyStore = Globals.getSslKeystoreFile(); char[] passphrase = Globals.getSslKeystorePassword().toCharArray(); KeyStore keystore = KeyStore.getInstance( "JKS" ); keystore.load( new FileInputStream( pathToKeyStore ), passphrase ); KeyManagerFactory kmf = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() ); kmf.init( keystore, passphrase ); sslContext = SSLContext.getInstance( "SSLv3" ); KeyManager[] keyManagers = kmf.getKeyManagers(); sslContext.init( keyManagers, null, null ); listener = new Listener( eventHandler, sslContext, Globals.getSslSocketPort() ); listener.start(); } catch ( FileNotFoundException e ) { log.error( "Could not find keystore." ); System.exit( 2 ); } catch ( KeyStoreException e ) { log.error( "KeyStore implemenation not supported." ); System.exit( 2 ); } catch ( NoSuchAlgorithmException e ) { log.error( "Could not find such Algorithm" ); System.exit( 2 ); } catch ( CertificateException e ) { log.error( "Certificate unvalid." ); System.exit( 2 ); } catch ( IOException e ) { log.error( "Could not read keyfile" ); System.exit( 2 ); } catch ( UnrecoverableKeyException e ) { log.error( "Key in keystore is not valid" ); System.exit( 2 ); } catch ( KeyManagementException e ) { log.error( "Context initialization failed." ); System.exit( 2 ); } } /** * Add a new connection with a unique token. * To up- or download the file in file path. * * @param token The unique token * @param filepath The file to up- or download * @param type True if upload or false if download * @return The created connection */ public static Connection addConnection( String token, String filepath, boolean type ) { log.debug( "Added connection (" + ( ( type ) ? "uploading" : "downloading" ) + ") with token: '" + token + "'" ); Connection connection = new Connection( filepath, type ); synchronized ( connections ) { connections.put( token, connection ); } return connection; } public static boolean hasConnection( String token ) { return connections.containsKey( token ); } public static void removeConnection( String token ) { synchronized ( connections ) { connections.remove( token ); // token is remove, so connections are rejected } } /** * Server is uploading - client is downloading! */ @Override public void incomingUploader( Uploader uploader ) throws IOException { // try to read meta data if ( !uploader.readMetaData() ) return; String token = uploader.getToken(); log.debug( "Got token :'" + token + "'" ); // check token to identify the client if ( !connections.containsKey( token ) ) { uploader.sendErrorCode( "Token not accepted." ); uploader.close(); return; } // check if he was a downloading client if ( connections.get( token ).type == Connection.UPLOADING ) { uploader.sendErrorCode( "You can not download, if you are uploading." ); uploader.close(); return; } List blocks = connections.get( token ).client.getLastRequestedBlocks( token ); for ( Integer block : blocks ) { uploader.sendRange( block*Globals.blockSize, (block+1)*Globals.blockSize - 1 ); uploader.sendFile( connections.get( token ).filepath ); uploader.close(); } } /** * Server is downloading - client is uploading! */ @Override public void incomingDownloader( Downloader downloader ) throws IOException { int startOfRange = 0; int endOfRange = 0; int diffOfRange = 0; String token = ""; // try to read meta data while ( downloader.readMetaData() ) { // check token to identify the client token = downloader.getToken(); if ( !connections.containsKey( token ) ) { downloader.sendErrorCode( "Token not accepted." ); downloader.close(); return; } // get range startOfRange = downloader.getStartOfRange(); endOfRange = downloader.getEndOfRange(); diffOfRange = downloader.getDiffOfRange(); // check if he was a uploading client if ( connections.get( token ).type == Connection.DOWNLOADING ) { downloader.sendErrorCode( "You can not upload, if you are downloading." ); downloader.close(); return; } downloader.setOutputFilename( connections.get( token ).filepath ); downloader.readBinary(); // calculate and register the incoming blocks if ( diffOfRange == 0 ) return; for ( int i = startOfRange / Globals.blockSize; i < endOfRange / Globals.blockSize; i += Globals.blockSize ) { connections.get( token ).image.setNeedsCheck( i ); } } downloader.close(); } }