From 63af3084df7d6ea17defe104844a7298cda7b459 Mon Sep 17 00:00:00 2001 From: Nils Schwabe Date: Fri, 4 Jul 2014 10:20:04 +0200 Subject: Make use of the filetransfer classes --- src/main/java/org/openslx/imagemaster/App.java | 1 + src/main/java/org/openslx/imagemaster/Globals.java | 49 +++----- .../java/org/openslx/imagemaster/db/DbImage.java | 4 +- .../org/openslx/imagemaster/server/ApiServer.java | 4 +- .../serverconnection/ConnectionHandler.java | 135 +++++++++++++++++++++ .../serverconnection/ImageProcessor.java | 68 ++++++----- .../java/org/openslx/imagemaster/util/Tuple.java | 14 +++ 7 files changed, 211 insertions(+), 64 deletions(-) create mode 100644 src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java create mode 100644 src/main/java/org/openslx/imagemaster/util/Tuple.java (limited to 'src') diff --git a/src/main/java/org/openslx/imagemaster/App.java b/src/main/java/org/openslx/imagemaster/App.java index c2b36c0..2a70644 100644 --- a/src/main/java/org/openslx/imagemaster/App.java +++ b/src/main/java/org/openslx/imagemaster/App.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; +import org.openslx.imagemaster.serverconnection.ConnectionHandler; import org.openslx.imagemaster.serverconnection.ImageProcessor; import org.openslx.imagemaster.thrift.server.BinaryListener; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/openslx/imagemaster/Globals.java b/src/main/java/org/openslx/imagemaster/Globals.java index 3eca269..8fff2d2 100644 --- a/src/main/java/org/openslx/imagemaster/Globals.java +++ b/src/main/java/org/openslx/imagemaster/Globals.java @@ -47,20 +47,18 @@ public class Globals || getLdapKeystorePassword().isEmpty() || getLdapKeystorePath() == null || getLdapKeystorePath().isEmpty() - || getFtpBaseDir() == null - || getFtpBaseDir().isEmpty() - || getFtpKeystoreFile() == null - || getFtpKeystoreFile().isEmpty() - || getFtpKeystoreAlias() == null - || getFtpKeystoreAlias().isEmpty() - || getFtpKeystorePassword() == null - || getFtpKeystorePassword().isEmpty() + || getSslKeystoreFile() == null + || getSslKeystoreFile().isEmpty() + || getSslKeystoreAlias() == null + || getSslKeystoreAlias().isEmpty() + || getSslKeystorePassword() == null + || getSslKeystorePassword().isEmpty() || getLdapPort() == 0 || getSessionTimeoutUser() == 0 || getSessionTimeoutServer() == 0 - || getFtpPort() == 0 - || getFtpTimeout() == 0 ) { + || getSslPort() == 0 + || getSslTimeout() == 0 ) { return false; } @@ -77,17 +75,12 @@ public class Globals } // check keystore - if ( !getFtpKeystoreFile().endsWith( ".jks" )) { + if ( !getSslKeystoreFile().endsWith( ".jks" )) { log.error( "Keystore is not in jks format." ); return false; } // remove "/" at the end of the paths - String ftp = getFtpBaseDir(); - if ( ftp.endsWith( "/" ) ) { - Globals.properties.put( "ftp_base_dir", ftp.substring( 0, ftp.length() - 1 ) ); - } - String image = getImageDir(); if ( image.endsWith( "/" ) ) { Globals.properties.put( "image_dir", image.substring( 0, image.length() - 1 ) ); @@ -110,12 +103,12 @@ public class Globals return Integer.valueOf( properties.getProperty( "session_timeout_user" ) ); } - public static int getFtpPort() { - return Integer.valueOf( properties.getProperty( "ftp_port" ) ); + public static int getSslPort() { + return Integer.valueOf( properties.getProperty( "ssl_port" ) ); } - public static int getFtpTimeout() { - return Integer.valueOf( properties.getProperty( "ftp_timeout" ) ); + public static int getSslTimeout() { + return Integer.valueOf( properties.getProperty( "ssl_timeout" ) ); } /* STRINGS */ @@ -124,16 +117,16 @@ public class Globals return properties.getProperty( "image_dir" ); } - public static String getFtpKeystoreFile() { - return properties.getProperty( "ftp_keystore_file" ); + public static String getSslKeystoreFile() { + return properties.getProperty( "ssl_keystore_file" ); } - public static String getFtpKeystoreAlias() { - return properties.getProperty( "ftp_keystore_alias" ); + public static String getSslKeystoreAlias() { + return properties.getProperty( "ssl_keystore_alias" ); } - public static String getFtpKeystorePassword() { - return properties.getProperty( "ftp_keystore_password" ); + public static String getSslKeystorePassword() { + return properties.getProperty( "ssl_keystore_password" ); } public static String getLdapHost() { @@ -160,10 +153,6 @@ public class Globals return properties.getProperty( "ldap_keystore_path" ); } - public static String getFtpBaseDir() { - return properties.getProperty( "ftp_base_dir" ); - } - /* BOOLEANS */ public static boolean getLdapSsl() { diff --git a/src/main/java/org/openslx/imagemaster/db/DbImage.java b/src/main/java/org/openslx/imagemaster/db/DbImage.java index e3a8888..d34fdb3 100644 --- a/src/main/java/org/openslx/imagemaster/db/DbImage.java +++ b/src/main/java/org/openslx/imagemaster/db/DbImage.java @@ -105,7 +105,7 @@ public class DbImage * @param serverSessionId The server that is uploading this image * @return Affected rows */ - public static int insert( ImageData imageData, long ts, String token, List missingBlocks, String serverSessionId) + public static int insert( ImageData imageData, long ts, String token, List missingBlocks, String serverSessionId, String filepath) { Date createTime = new Date( imageData.imageCreateTime ); Date updateTime = new Date( imageData.imageUpdateTime ); @@ -122,7 +122,7 @@ public class DbImage return MySQL .update( "INSERT INTO images (UUID, image_version, image_name, image_path, image_createTime, image_updateTime, image_owner, content_operatingSystem, status_isValid, status_isDeleted, image_shortDescription, image_longDescription, timestamp, fileSize, token, missingBlocks, serverSessionId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - imageData.uuid, imageData.imageVersion, imageData.imageName, "!uploading!", + imageData.uuid, imageData.imageVersion, imageData.imageName, filepath, sdf.format( createTime ), sdf.format( updateTime ), imageData.imageOwner, imageData.conentOperatingSystem, imageData.statusIsValid, imageData.statusIsDeleted, imageData.imageShortDescription, diff --git a/src/main/java/org/openslx/imagemaster/server/ApiServer.java b/src/main/java/org/openslx/imagemaster/server/ApiServer.java index 9c3dfb4..206cda9 100644 --- a/src/main/java/org/openslx/imagemaster/server/ApiServer.java +++ b/src/main/java/org/openslx/imagemaster/server/ApiServer.java @@ -46,8 +46,6 @@ import org.openslx.imagemaster.util.RandomString; */ public class ApiServer { - private static Logger log = Logger.getLogger( ApiServer.class ); - /** * Request for authentication * @@ -151,7 +149,7 @@ public class ApiServer String path = DbImage.getImageByUUID( uuid ).imagePath; - // TODO: get token form downloader class + // TODO: init the updownloader class return new DownloadInfos( RandomString.generate( 100, false ) ); } diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java b/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java new file mode 100644 index 0000000..498e058 --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java @@ -0,0 +1,135 @@ +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.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +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; +import org.openslx.imagemaster.db.DbImage; +import org.openslx.imagemaster.util.Tuple; + +/** + * 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; + /** + * Key: token, + * Value: Tuple of the listener and the filepath. + */ + private static Map> activeListeners = new HashMap<>(); + private static List possiblePorts = new LinkedList<>(); + private static IncomingEvent eventHandler = new ConnectionHandler(); + + static { + possiblePorts.add( 1234 ); + possiblePorts.add( 1235 ); + possiblePorts.add( 1236 ); + possiblePorts.add( 1237 ); + possiblePorts.add( 1238 ); + possiblePorts.add( 1239 ); + possiblePorts.add( 1240 ); + possiblePorts.add( 1241 ); + possiblePorts.add( 1242 ); + possiblePorts.add( 1243 ); + possiblePorts.add( 1244 ); + + 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); + } catch (FileNotFoundException e) { + log.error( "Could not find keystore." ); + } catch ( KeyStoreException e ) { + log.error( "KeyStore implemenation not supported." ); + } catch ( NoSuchAlgorithmException e ) { + log.error( "Could not find such Algorithm" ); + } catch ( CertificateException e ) { + log.error( "Certificate unvalid." ); + } catch ( IOException e ) { + log.error( "Could not read keyfile" ); + } catch ( UnrecoverableKeyException e ) { + log.error( "Key in keystore is not valid" ); + } catch ( KeyManagementException e ) { + log.error( "Context initialization failed." ); + } + } + + public static void addConnection(String token, String filepath) + { + int port = possiblePorts.remove( 0 ); + Listener listener = new Listener( eventHandler, sslContext, port ); + + listener.start(); + + activeListeners.put( token, new Tuple(listener, filepath) ); + } + + public static boolean hasConnection( String token ) + { + return activeListeners.containsKey( token ); + } + + public static void removeConnection( String token ) + { + Listener l = (Listener)activeListeners.remove( token ).x; + l.interrupt(); + possiblePorts.add(l.getPort()); // add port back to possible's list + } + + /** + * Server is uploading - client is downloading! + */ + @Override + public void incomingUploader( Uploader uploader ) throws IOException + { + // TODO: Handle incoming uploads (client download requests) + } + + /** + * Server is downloading - client is uploading! + */ + @Override + public void incomingDownloader( Downloader downloader ) throws IOException + { + // try to read meta data + while (downloader.readMetaData()) { + // check token to identify the client + String token = downloader.getToken(); + if (!activeListeners.containsKey( token )) { + return; + } + downloader.setOutputFilename( activeListeners.get( token ).y ); + downloader.readBinary(); + downloader.close(); + } + } +} diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java b/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java index d4ae717..c7ee973 100644 --- a/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java +++ b/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java @@ -14,6 +14,7 @@ import org.openslx.imagemaster.util.RandomString; public class ImageProcessor { + private static Logger log = Logger.getLogger( ImageProcessor.class ); /** @@ -22,14 +23,15 @@ public class ImageProcessor private static final int AMOUNT = 20; /** * The uploading images. - * Key: imageUUID, - * Value: imageInfos + * Key: imageUUID, + * Value: imageInfos */ private static HashMap uploadingImages = new HashMap<>(); /** * 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 @@ -38,9 +40,9 @@ public class ImageProcessor { // check image data // TODO: do security checks - + String uuid = imageData.uuid; - + // check if image is already uploading if ( uploadingImages.containsKey( uuid ) ) { List missing = getMissingBlocks( uuid, AMOUNT ); @@ -52,19 +54,20 @@ public class ImageProcessor uploadingImages.get( uuid ).setLastSentBlocks( missing ); return new UploadInfos( uploadingImages.get( uuid ).getToken(), missing ); } - + // insert new image and generate token - synchronized (uploadingImages) { - int nBlocks = (int)Math.ceil(imageData.fileSize / Globals.blockSize); + synchronized ( uploadingImages ) { + int nBlocks = (int)Math.ceil( imageData.fileSize / Globals.blockSize ); List allBlocks = new LinkedList<>(); - for (int i = 0; i < nBlocks; i++) { // fill empty list with all block numbers + for ( int i = 0; i < nBlocks; i++ ) { // fill empty list with all block numbers allBlocks.add( i ); } String token = RandomString.generate( 100, false ); - // TODO: init updownloader class - uploadingImages.put( uuid, new ImageInfos(token, allBlocks, serverSessionId, new Timestamp(System.currentTimeMillis())) ); - DbImage.insert( imageData, System.currentTimeMillis(), token, allBlocks, serverSessionId ); - + String filepath = Globals.getImageDir() + "/" + uuid + ".vmdk"; + ConnectionHandler.addConnection( token, filepath ); + uploadingImages.put( uuid, new ImageInfos( token, allBlocks, serverSessionId, new Timestamp( System.currentTimeMillis() ) ) ); + DbImage.insert( imageData, System.currentTimeMillis(), token, allBlocks, serverSessionId, filepath ); + List missing = getMissingBlocks( uuid, AMOUNT ); if ( missing.isEmpty() ) { uploadDone( uuid ); @@ -73,51 +76,58 @@ public class ImageProcessor return new UploadInfos( token, missing ); } } - + /** * Returns a specified number of missing blocks. + * * @param imageUUID The image of which you want to get the missing blocks from * @param amount The amount of blocks that you want to get - * @return The missing blocksht + * @return The missing blocks */ private static List getMissingBlocks( String imageUUID, int amount ) { List list = uploadingImages.get( imageUUID ).getMissingBlocks(); List result = new LinkedList<>(); - + if ( amount > list.size() ) amount = list.size(); - + for ( int i = 0; i < amount; i++ ) { result.add( list.get( i ) ); } return result; } - + /** * Is triggered when an upload of an image is done. * Removes image from process list, updates db entry and moves file on hard drive. + * * @param uuid */ - private static void uploadDone( String uuid ) { - synchronized(uploadingImages) { - uploadingImages.remove( uuid ); - DbImage.updateMissingBlocks( uuid, null ); + private static void uploadDone( String uuid ) + { + String token; + synchronized ( uploadingImages ) { + token = uploadingImages.remove( uuid ).getToken(); } + DbImage.updateMissingBlocks( uuid, null ); // file was already downloaded in the right location by the updownloader class. + // remove the connection so that it can be used by a new client + ConnectionHandler.removeConnection( token ); } - + /** * Checks pending uploads in database and adds them to process list again. */ - public static void checkUploading() { + public static void checkUploading() + { List list = DbImage.getUploadingImages(); - for (DbImage image : list) { - // TODO: init updownloader class - String token = RandomString.generate( 100, false ); - ImageInfos infos = new ImageInfos(token, image.missingBlocks, image.serverSessionId, image.timestamp); - uploadingImages.put( image.UUID, infos); + for ( DbImage image : list ) { + String token = image.token; + ConnectionHandler.addConnection( token, image.imagePath ); + ImageInfos infos = new ImageInfos( token, image.missingBlocks, image.serverSessionId, image.timestamp ); + uploadingImages.put( image.UUID, infos ); } - log.info("Added " + list.size() + " pending upload(s) to process list again."); + log.info( "Added " + list.size() + " pending upload(s) to process list again." ); } } diff --git a/src/main/java/org/openslx/imagemaster/util/Tuple.java b/src/main/java/org/openslx/imagemaster/util/Tuple.java new file mode 100644 index 0000000..7c7f326 --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/util/Tuple.java @@ -0,0 +1,14 @@ +package org.openslx.imagemaster.util; + + +public class Tuple { + public final X x; + public final Y y; + public Tuple(X x, Y y) { + this.x = x; + this.y = y; + } + public X getX() { + return x; + } +} \ No newline at end of file -- cgit v1.2.3-55-g7522