summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java
blob: 12b5701f15c4e4cbcb065e16b04393b3a4e8e9a6 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                 
                     
                                              



                                                       




                                       
                                                  

                                           
                                          


                                              
                                                  
                                       
                                          


                                                         
                                                                       


                                                       
 

                                                                                
 

                                                                                                      
                                                                            

                                                                                                                                               


                                         
                
                                                                                       
                     











                                                                                                                         
                                                                
                                         

                                                                             
                                         

                                                                     
                                         

                                                            
                                         

                                                              
                                         

                                                                    
                                         

                                                                      
                                         

                 
 
           

                                                       
           
                                        
                                            
           
                                                                          
         

                                                           
         
 







                                                                     
         

                                                             





                                                       
                                                               
         
                                                   
                                                     
                                      
                                                                        
                                               

                               


                                                                               
                                                                        
                                               
                               
                 
 










                                                                                   
                 
         
 



                                                       
                                                                                        
         
                                                      
                                                     
                                    

                                                                          
                                                 

                               


                                                                                    
                                                                          
                                                 
                               
                 
















                                                                                                                       

                                                                                                  
                                                                            
                                                         








                                                                                                                                                                           
                                                         




                                                                                     
                 

         
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.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.RejectedExecutionException;
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.commons.lang.mutable.MutableInt;
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;
import org.openslx.imagemaster.db.DbImage;

/**
 * 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<String, UploadingImage> pendingIncomingUploads = new ConcurrentHashMap<>();
	private static Map<String, DbImage> pendingIncomingDownloads = new ConcurrentHashMap<>();
	private static IncomingEvent eventHandler = new ConnectionHandler();
	private static ThreadPoolExecutor uploadPool = new ThreadPoolExecutor( 0, 5, 6, TimeUnit.MINUTES, new SynchronousQueue<Runnable>() );
	private static ThreadPoolExecutor downloadPool = new ThreadPoolExecutor( 0, 5, 6, TimeUnit.MINUTES, new SynchronousQueue<Runnable>() );

	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 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, UploadingImage 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, DbImage image )
	{
		pendingIncomingDownloads.put( token, image );
		log.debug( "Added download" );
	}

	/**
	 * Server is uploading - client is downloading!
	 */
	@Override
	public void incomingUploader( final Uploader uploader )
	{
		String token = uploader.getToken();
		// check token to identify the client
		if ( token == null ) {
			uploader.sendErrorCode( "No token available." );
			uploader.close( null );
			return;
		}

		final DbImage image = pendingIncomingDownloads.remove( token );
		if ( image == null ) {
			uploader.sendErrorCode( "Token not accepted." );
			uploader.close( null );
			return;
		}

		try {
			uploadPool.execute( new Runnable() {
				@Override
				public void run()
				{
					uploader.upload( image.getAbsolutePath() );
				}
			} );
		} catch ( RejectedExecutionException e ) {
			uploader.sendErrorCode( "Too many concurrent uploads." );
			uploader.close( null );
		}
	}

	/**
	 * Server is downloading - client is uploading!
	 */
	@Override
	public void incomingDownloader( final 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;
		}

		final UploadingImage image = pendingIncomingUploads.remove( token );
		if ( image == null ) {
			downloader.sendErrorCode( "Token not accepted." );
			downloader.close( null );
			return;
		}
		final MutableInt lastBlock = new MutableInt( -1 );

		try {
			downloadPool.execute( new Runnable() {
				@Override
				public void run()
				{
					downloader.download( image.getAbsolutePath(), new WantRangeCallback() {
						@Override
						public FileRange get()
						{
							if ( lastBlock.intValue() != -1 ) {
								image.setNeedsCheck( lastBlock.intValue() );
								image.increaseTransmittedTimes( lastBlock.intValue() );
							}
							// get start of range.
							int blockNumber = image.getNextMissingBlock();
							if ( blockNumber == -1 ) {
								log.debug( "Download complete." );
								return null;
							}
							lastBlock.setValue( 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.getFileSize() );
							FileRange range = new FileRange( startOfRange, endOfRange );
							return range;
						}
					} );
					image.updateDb();
				}
			} );
		} catch ( RejectedExecutionException e ) {
			downloader.sendErrorCode( "Too many concurrent downloads." );
			downloader.close( null );
		}
	}
}