package org.openslx.imagemaster.serverconnection; import java.io.FileInputStream; import java.io.IOException; import java.security.KeyStore; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.ImagePublishData; import org.openslx.bwlp.thrift.iface.InvocationError; import org.openslx.bwlp.thrift.iface.TInvocationException; import org.openslx.bwlp.thrift.iface.TTransferRejectedException; import org.openslx.bwlp.thrift.iface.TransferInformation; 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; import org.openslx.imagemaster.crcchecker.CrcFile; import org.openslx.imagemaster.db.mappers.DbOsVirt; import org.openslx.imagemaster.db.mappers.DbUser; import org.openslx.imagemaster.util.RandomString; import org.openslx.imagemaster.util.Util; /** * 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 pendingIncomingUploads = new ConcurrentHashMap<>(); private static Map pendingIncomingDownloads = new ConcurrentHashMap<>(); private static IncomingEvent eventHandler = new ConnectionHandler(); private static ThreadPoolExecutor uploadPool = new ThreadPoolExecutor( 0, 5, 6, TimeUnit.MINUTES, new SynchronousQueue() ); private static ThreadPoolExecutor downloadPool = new ThreadPoolExecutor( 0, 5, 6, TimeUnit.MINUTES, new SynchronousQueue() ); private static Listener listener; static { log.debug( "Starting listener on port " + Globals.getFiletransferPortSsl() ); 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( "TLSv1.2" ); KeyManager[] keyManagers = kmf.getKeyManagers(); sslContext.init( keyManagers, null, null ); listener = new Listener( eventHandler, sslContext, Globals.getFiletransferPortSsl(), Globals.getFiletransferTimeout() * 1000 ); listener.start(); } catch ( Exception e ) { log.error( "Initialization failed.", e ); System.exit( 2 ); } } /** * Checks if this image is already uploading and returns a new list with missing blocks if so. * Puts the new image into processing list else. * * @param serverSessionId The uploading server * @param imageData The data of the image * @return * @throws UploadException If some error occurred during the process */ public static TransferInformation getUploadInfos( ImagePublishData imageData, List crcSums ) throws TTransferRejectedException, TInvocationException { // check image data if ( Util.isEmpty( imageData.imageName ) ) throw new TInvocationException( InvocationError.INVALID_DATA, "Image name not set" ); if ( !DbUser.exists( imageData.user ) ) throw new TInvocationException( InvocationError.INVALID_DATA, "Invalid or missing image owner" ); if ( DbOsVirt.osExists( imageData.osId ) ) throw new TInvocationException( InvocationError.INVALID_DATA, "Content operating system not set" ); if ( DbOsVirt.virtExists( imageData.virtId ) ) throw new TInvocationException( InvocationError.INVALID_DATA, "Content virtualizer system not set" ); if ( imageData.fileSize <= 0 ) throw new TInvocationException( InvocationError.INVALID_DATA, "File size is too small" ); log.debug( "A satellite is submitting " + imageData.imageVersionId ); final String uuid = imageData.imageVersionId; final String filepathRelative; final CrcFile crcFile; if ( crcSums == null ) { crcFile = null; } else { crcFile = new CrcFile( crcSums ); } ImagePublishData image; synchronized ( pendingIncomingUploads ) { /* // check if image is already uploading if ( ( image = uploadingImages.get( uuid ) ) == null ) { // TODO insert new image to DB uploadingImages.put( uuid, image ); } */ } final String token = RandomString.generate( 50, false ); // TODO addUpload( token, image ); // TODO Set crc file on image - if there is already a crc file assigned, this does nothing return new TransferInformation( token, Globals.getFiletransferPortPlain(), Globals.getFiletransferPortSsl() ); } /** * Add a new allowed incoming upload connection * for the given token and image. * * @param token The unique token * @param image Image being uploaded */ public static void addUpload( String token, AbstractTransfer image ) { pendingIncomingUploads.put( token, image ); log.debug( "Added upload" ); } /** * Add a new allowed incoming download connection * for the given token and image. * * @param token The unique token * @param image Image being uploaded */ public static void addDownload( String token, AbstractTransfer image ) { pendingIncomingDownloads.put( token, image ); log.debug( "Added download" ); } /** * Server is uploading - client is downloading! */ @Override public void incomingDownloadRequest( final Uploader uploader ) { // TODO uploader.sendErrorCode( "Too many concurrent uploads." ); uploader.cancel(); } /** * Server is downloading - client is uploading! */ @Override public void incomingUploadRequest( final Downloader downloader ) throws IOException { // TODO downloader.sendErrorCode( "Too many concurrent downloads." ); downloader.cancel(); } }