/*******************************************************************************
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 SVS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
/**
*
*/
package userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.mix;
import java.nio.ByteBuffer;
import java.util.Hashtable;
import java.util.concurrent.LinkedBlockingQueue;
import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.Connection;
import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.HttpInfo;
import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.HttpPartType;
import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.SynchronizedBuffer;
import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.helper.HttpParser;
/**
* @author bash
*
* This class represents the superclass for all communications from mix to the webbrowser or webserver.
* It contains methods with is used by the subclasses EntryDataFromMix and ExitDataFromMix
*
* The data chunks from the mix are added to a queue by the mix connection.
*
*/
public abstract class DataFromMix extends Thread {
/**
* Queue of connections which contains data
*/
public LinkedBlockingQueue<Connection> writeableChunks;
/**
* Constructor
*
* @param writeableChunks
*/
public DataFromMix(LinkedBlockingQueue<Connection> writeableChunks) {
this.writeableChunks = writeableChunks;
}
/**
* Method for threadhandling
* This method checks the blocking queue for connections with data from mix.
* If a connection receives data from the mix the handling by this class is started.
* The called method depends on the expected message type stored in the connection object
*/
@Override
public void run() {
while (true) {
Connection connection = null;
try {
// System.out.println("DataFromMix: Wait for Connections");
//Blocking queue
connection = writeableChunks.take();
connection.setInProgressReceive(true);
// System.out.println("DataFromMix: receive Connection "
// + connection.getId() + " Connection from Queue");
} catch (InterruptedException e) {
break;
}
// System.out.println("DataFromMix: receive Connection "
// + connection.getId() + " Buffer with Payload");
synchronized (connection) {
connection.setMixMessageIncomplete(false);
while (connection.isMixBuffer()) {
// connection.logger.logEntry(connection.getId(), "entry",
// HttpPartType.SocksAuth, 0, buffer.detemineSize(),
// buffer.getAllDataAsString());
HttpPartType type = connection.getStatusHTTPFromMix().getType();
System.out.println("DataFromMix: Connection "
+ connection.getId() + " has Type " + type.toString());
// System.out.println(connection.getMixBuffer().getAllDataAsString());
// Method call depending on message type
switch (type) {
case Header:
headerHandling(connection);
break;
case Body:
bodyHandling(connection);
break;
case BodyChunk:
bodyChunkHandling(connection);
break;
case SocksReply:
socksReplyHandling(connection);
break;
case SocksAuth:
socksAuthHandling(connection);
break;
case SocksRequest:
socksRequestHandling(connection);
break;
default:
System.out.println("Unknown Type!");
break;
}
if (connection.isMixMessageIncomplete()) {
break;
}
}
connection.setInProgressReceive(false);
}
}
}
/**
* Method for sockshandling
*
* @param message
* @param connection
*/
public SynchronizedBuffer socksRequestHandling(Connection connection) {
SynchronizedBuffer buffer = connection.getMixBuffer();
byte[] message = buffer.peekBuffer();
int length = 0;
if (message[3] == 0x01) {
length = 10;
} else if (message[3] == 0x02) {
length = 6 + message[4];
} else if (message[3] == 0x03) {
length = 22;
} else {
System.out.println("ERROR in Socks parsing!");
}
byte[] payload = buffer.removeBytes(length);
writeChunkToConnection(connection, payload);
connection.getStatusHTTPFromMix().setType(HttpPartType.Header);
return buffer;
}
/**
* Method for sockshandling Not Implemented
*
* @param connection
*/
@Deprecated
public SynchronizedBuffer socksAuthHandling(Connection connection) {
System.err.println("ERROR: Not implemented Method DataFromMix 132");
return null;
}
/**
* Method for Sockshandling
*
* @param connection
*/
public SynchronizedBuffer socksReplyHandling(Connection connection) {
int length = 0;
SynchronizedBuffer buffer = connection.getMixBuffer();
byte[] message = buffer.peekBuffer();
if (message[3] == 0x01) {
length = 10;
} else if (message[3] == 0x02) {
length = 6 + message[4];
} else if (message[3] == 0x03) {
length = 22;
} else {
System.out.println("ERROR in Socks parsing!");
}
byte[] payload = buffer.removeBytes(length);
writeChunkToConnection(connection, payload);
connection.getStatusHTTPFromMix().setType(HttpPartType.Header);
return buffer;
}
/**
* Method for Headerhandling Placeholder
*
* @param connection
*/
public abstract SynchronizedBuffer headerHandling(Connection connection);
/**
* Method for bodyhandling Placeholder for inherent class
*
* @param connection
*/
public abstract SynchronizedBuffer bodyHandling(Connection connection);
/**
* Method for bodychunkhandling Placeholder for inherent class
*
* @param connection
*/
public abstract SynchronizedBuffer bodyChunkHandling(Connection connection);
/**
* Method for Relaywriting of a body
* This method contains all neccessary steps for every body passing this class
*
* @param message
* @param connection
*/
public byte[] bodyRelayWrite(byte[] message, Connection connection, boolean writeOut) {
int bufferLength = message.length;
byte[] payload = message;
if (writeOut) {
connection.writeChunk(ByteBuffer.wrap(payload));
}
int remainingBodyLength = (connection.getStatusHTTPFromMix().getLength() - bufferLength);
connection.getStatusHTTPFromMix().setLength(remainingBodyLength);
if (remainingBodyLength <= 0 && connection.getStatusHTTPFromMix().isBody()) {
connection.setStatusHTTPFromMix(new HttpInfo(HttpPartType.Header, 0));
}
return message;
}
/**
* Methode to write a Message to a connection
*
* @param payload
*/
public void writeChunkToConnection(Connection connection, byte[] payload) {
connection.writeChunk(ByteBuffer.wrap(payload));
}
/**
* Helpermethod for header posthandling
*
* It contains all necessary steps for header handling use by exit and entry
*
* @param readableMessage
* @param connection
* @return the readable message as byte[]
*/
public byte[] postHeaderHandling(byte[] readableMessage, Connection connection, boolean writeOut) {
String headerString = new String(readableMessage);
Hashtable<String, String> headerTable = HttpParser.parseHeader(headerString);
connection.getStatusHTTPFromMix().setHeader(headerTable);
String method;
if (headerTable.containsKey("method")) {
method = headerTable.get("method");
connection.addMethodToQueue(method);
} else {
method = connection.returnMethodFromQueue();
}
int bodyType = HttpParser.determineBodyType(headerTable, method);
// connection.setBodyImproveable(false);
// int messageId = connection.peekPackageCounter();
switch (bodyType) {
case 0:
connection.getStatusHTTPFromMix().setType(HttpPartType.Header);
break;
case 1:
connection.getStatusHTTPFromMix().setType(HttpPartType.Body);
int bodyLength = HttpParser.getBodyLengthFromHeader(headerTable);
connection.getStatusHTTPFromMix().setLength(bodyLength);
break;
case 2:
connection.getStatusHTTPFromMix().setLength(-1);
connection.getStatusHTTPFromMix().setType(HttpPartType.BodyChunk);
break;
default:
break;
}
// System.out.println("DataFromMix: Message ready to write out");
if (writeOut) {
// System.out.println(new String(readableMessage));
writeChunkToConnection(connection, readableMessage);
}
// System.out.println("DataFromMix: Message written out on Connection "
// + connection.getId());
return readableMessage;
}
}