package org.openslx.imagemaster.serverconnection; import java.io.File; 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. * Also handles the authentication and the saving/delivering of images. */ 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 ); String fileName = connections.get( token ).filepath; long fileSize = new File( fileName ).length(); long actual; for ( Integer block : blocks ) { actual = block * Globals.blockSize; uploader.sendRange( actual, ( ( fileSize - actual ) < Globals.blockSize ) ? fileSize : ( block + 1 ) * Globals.blockSize ); uploader.sendFile( fileName ); } uploader.close(); } /** * Server is downloading - client is uploading! */ @Override public void incomingDownloader( Downloader downloader ) throws IOException { log.debug( "Client wants to upload" ); long startOfRange = 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; } startOfRange = downloader.getStartOfRange(); if ( downloader.getDiffOfRange() <= 0 ) { return; } // 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; } int blockNumber = (int) ( startOfRange / Globals.blockSize ); UploadingImage image = connections.get( token ).image; image.setNeedsCheck( blockNumber ); image.increaseTransmittedTimes( blockNumber ); log.debug( "Block " + blockNumber + " was transmitted " + image.getTimesTransmitted( blockNumber ) + " time(s)." ); downloader.setOutputFilename( connections.get( token ).filepath ); downloader.readBinary(); } downloader.close(); } }