summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java
blob: 7fa9c4e8eefff64aa74fc95fd237cdad65b398d6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
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<String, Connection> 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<Integer> 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();
	}
}