package de.tudarmstadt.informatik.hostage;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import de.tudarmstadt.informatik.hostage.handler.AbstractHandler;
import de.tudarmstadt.informatik.hostage.handler.ByteArrayHandler;
import de.tudarmstadt.informatik.hostage.handler.StringHandler;
import de.tudarmstadt.informatik.hostage.net.MyServerSocketFactory;
import de.tudarmstadt.informatik.hostage.protocol.Protocol;
import de.tudarmstadt.informatik.hostage.protocol.SSLProtocol;
import de.tudarmstadt.informatik.hostage.ui.MainActivity;
import de.tudarmstadt.informatik.hostage.wrapper.ByteArray;
/**
* Protocol listener class:
* Creates a Socket on the port of a given protocol and listens for incoming connections.
* For each connection creates a Socket and instantiate an {@link AbstractHandler}.
* @author Mihai Plasoianu
*
*/
public class HoneyListener implements Runnable {
private ArrayList handlers = new ArrayList();
/**
* Determines the amount of active handlers.
* @return The number of active handlers.
*/
public int getHandlerCount() {
return handlers.size();
}
private Protocol> protocol;
private ServerSocket server;
private Thread thread;
private HoneyService service;
// Shared Preferences
private SharedPreferences pref;
private ConnectionRegister conReg;
// Editor for Shared preferences
private Editor editor;
private boolean running = false;
/**
* Determines if the service is running.
* @return True if the service is running, else false.
*/
public boolean isRunning() {
return running;
}
/**
* Constructor for the class. Instantiate class variables.
* @param service The Background service that started the listener.
* @param protocol The Protocol on which the listener is running.
*/
public HoneyListener(HoneyService service, Protocol> protocol) {
this.service = service;
this.protocol = protocol;
pref = service.getApplicationContext().getSharedPreferences(
MainActivity.SESSION_DATA, Context.MODE_PRIVATE);
editor = pref.edit();
conReg = new ConnectionRegister(service);
}
@Override
public void run() {
while (!thread.isInterrupted()) {
addHandler();
}
for (AbstractHandler handler : handlers) {
handler.kill();
}
}
/**
* Starts the listener. Creates a server socket runs itself in a new Thread and notifies the background service.
*/
public void start() {
try {
server = new MyServerSocketFactory().createServerSocket(protocol
.getPort());
(this.thread = new Thread(this)).start();
editor.putBoolean(protocol + MainActivity.LISTENER, true);
editor.commit();
service.notifyUI(protocol.toString(), MainActivity.LISTENER);
running = true;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Stops the listener. Closes the server socket, interrupts the Thread its running in and notifies the background service.
*/
public void stop() {
try {
server.close();
thread.interrupt();
editor.putBoolean(protocol + MainActivity.LISTENER, false);
editor.commit();
service.notifyUI(protocol.toString(), MainActivity.LISTENER);
running = false;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Determine the name of the protocol the listener is running on.
* @return Name of the protocol
*/
public String getProtocolName() {
return protocol.toString();
}
/**
* Remove all terminated handlers from its internal ArrayList.
*/
public void refreshHandlers() {
for (Iterator iterator = handlers.iterator(); iterator
.hasNext();) {
AbstractHandler handler = iterator.next();
if (handler.isTerminated()) {
conReg.closeConnection();
iterator.remove();
}
}
}
/**
* Waits for an incoming connection, accepts it and starts a {@link AbstractHandler}
*/
private void addHandler() {
if(conReg.isConnectionFree()) {
try {
Socket client = server.accept();
conReg.newOpenConnection();
if (protocol.isSecure()) {
startSecureHandler(client);
} else {
startHandler(client);
}
int handlerCount = pref.getInt(protocol
+ MainActivity.HANDLER_COUNT, 0);
editor.putInt(protocol + MainActivity.HANDLER_COUNT,
handlerCount + 1);
editor.commit();
service.notifyUI(protocol.toString(), MainActivity.HANDLER_COUNT);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Creates a SSLSocket out of the given socket and starts a {@link AbstractHandler}.
* @param client The socket with the accepted connection.
* @throws Exception
*/
private void startSecureHandler(Socket client) throws Exception {
SSLContext sslContext = ((SSLProtocol>) protocol).getSSLContext();
SSLSocketFactory factory = sslContext.getSocketFactory();
SSLSocket sslClient = (SSLSocket) factory.createSocket(client, null,
client.getPort(), false);
sslClient.setUseClientMode(false);
handlers.add(newInstance(service, this, protocol.getClass()
.newInstance(), sslClient));
}
/**
* Starts a {@link AbstractHandler} with the given socket.
* @param client The socket with the accepted connection.
* @throws Exception
*/
private void startHandler(Socket client) throws Exception {
handlers.add(newInstance(service, this, protocol.getClass()
.newInstance(), client));
}
/**
* Creates a new instance of an {@link AbstractHandler}.
* @param service The background service
* @param listener The listener that created the handler
* @param protocol The Protocol the handler will run on
* @param client The Socket the handler uses
* @return A Instance of a {@link AbstractHandler} with the specified parameter.
*/
private AbstractHandler newInstance(HoneyService service,
HoneyListener listener, Protocol> protocol, Socket client) {
if (protocol.getType().equals(String.class)) {
return new StringHandler(service, listener, protocol, client);
} else if (protocol.getType().equals(ByteArray.class)) {
return new ByteArrayHandler(service, listener, protocol, client);
} else {
return null;
}
}
}