summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java
blob: 2f41fcd34778e7b345dbbad5d3cbab66a5840a3b (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
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.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;

/**
 * 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<String, ConnectionData> activeListeners = new HashMap<>();
	private static List<Integer> 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." );
			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.
	 * Tp up- or download the file in filepath.
	 * @param token The unique token
	 * @param filepath The file to up- or download
	 * @param type True if upload or false if download
	 * @return The port that was used for this connection.
	 */
	public static int addConnection(String token, String filepath, boolean type)
	{
		int port = possiblePorts.remove( 0 );	//TODO: handle if no ports are left
		Listener listener = new Listener( eventHandler, sslContext, port );
		
		listener.start();
		
		activeListeners.put( token, new ConnectionData(filepath, type, listener) );
		return port;
	}
	
	public static boolean hasConnection( String token )
	{
		return activeListeners.containsKey( token );
	}
	
	public static void removeConnection( String token )
	{
		Listener l = activeListeners.remove( token ).listenerThread;
		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
	{
		// try to read meta data
		while ( uploader.readMetaData() ) {
			String token = uploader.getToken();
			log.debug( "Got token :'" + token + "'");
			// check token to identify the client
			if ( !activeListeners.containsKey( token )) {
				uploader.sendErrorCode( "Token not accepted." );
				uploader.close();
				return;
			}
			
			// check if he was a downloading client
			if ( activeListeners.get( token ).type == ConnectionData.UPLOADING ) {
				uploader.sendErrorCode( "You can not download, if you are uploading." );
				uploader.close();
				return;
			}
			// TODO: check which range needs to be sent and send this range
			long length = ( new File( activeListeners.get( token ).filepath ) ).length();
			
			uploader.sendRange(0, (int)length);
			uploader.sendFile( activeListeners.get( token ).filepath );
		}
		uploader.close();
	}
	
	/**
	 * 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 ) ) {
				downloader.sendErrorCode( "Token not accepted." );
				downloader.close();
				return;
			}
			// check if he was a uploading client
			if ( activeListeners.get( token ).type == ConnectionData.DOWNLOADING ) {
				downloader.sendErrorCode( "You can not upload, if you are downloading." );
				downloader.close();
				return;
			}
			
			downloader.setOutputFilename( activeListeners.get( token ).filepath );
			downloader.readBinary();
		}
		downloader.close();
	}
}