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.FileRange; import org.openslx.filetransfer.IncomingEvent; import org.openslx.filetransfer.Listener; import org.openslx.filetransfer.Uploader; import org.openslx.filetransfer.WantRangeCallback; 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 { String token = uploader.getToken(); log.debug( "Got token :'" + token + "'" ); // check token to identify the client if (token == null) { uploader.sendErrorCode( "No token available." ); uploader.close(null); return; } if ( !connections.containsKey( token ) ) { uploader.sendErrorCode( "Token not accepted." ); uploader.close(null); 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(null); return; } String fileName = connections.get( token ).filepath; uploader.upload(fileName); } /** * Server is downloading - client is uploading! */ @Override public void incomingDownloader( Downloader downloader ) throws IOException { log.debug( "Client wants to upload" ); String token = downloader.getToken(); if (token == null) { downloader.sendErrorCode( "No token available." ); downloader.close(null); return; } // Check token to identify the client. if ( !connections.containsKey( token ) ) { downloader.sendErrorCode( "Token not accepted." ); downloader.close(null); 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(null); return; } String destinationFileName = connections.get( token ).filepath; final UploadingImage image = connections.get( token ).image; downloader.download( destinationFileName, new WantRangeCallback() { @Override public FileRange get() { // get start of range. int blockNumber = image.getNextMissingBlock(); if (blockNumber == -1) return null; image.setNeedsCheck( blockNumber ); image.increaseTransmittedTimes( blockNumber ); log.debug( "Block " + blockNumber + " was transmitted " + image.getTimesTransmitted( blockNumber ) + " time(s)." ); long startOfRange = image.getNextMissingBlock() * Globals.blockSize; long endOfRange = Math.min(startOfRange + Globals.blockSize, image.getImageFile().length()); FileRange range = new FileRange(startOfRange, endOfRange); return range; } }); // 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(null); // 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(null); // 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.receiveBinary(); // } downloader.close(null); } }