/*******************************************************************************
* 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 staticContent.framework;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import staticContent.evaluation.testbed.statistic.sensor.StatisticsSensor;
import staticContent.framework.clock.Clock;
import staticContent.framework.config.Settings;
import staticContent.framework.controller.Controller;
import staticContent.framework.controller.Layer1NetworkClientController;
import staticContent.framework.controller.Layer1NetworkMixController;
import staticContent.framework.controller.Layer2RecodingSchemeClientController;
import staticContent.framework.controller.Layer2RecodingSchemeMixController;
import staticContent.framework.controller.Layer3OutputStrategyClientController;
import staticContent.framework.controller.Layer3OutputStrategyMixController;
import staticContent.framework.controller.Layer4TransportClientController;
import staticContent.framework.controller.Layer4TransportMixController;
import staticContent.framework.controller.Layer5ApplicationClientController;
import staticContent.framework.controller.Layer5ApplicationMixController;
import staticContent.framework.controller.routing.DynamicRoutingClientController;
import staticContent.framework.controller.routing.DynamicRoutingMixController;
import staticContent.framework.controller.routing.GlobalRoutingClientController;
import staticContent.framework.controller.routing.RoutingModeInfoServiceController;
import staticContent.framework.controller.routing.SourceRoutingClientController;
import staticContent.framework.infoService.InfoServiceClient;
import staticContent.framework.launcher.CommandLineParameters;
import staticContent.framework.launcher.GMixTool;
import staticContent.framework.launcher.ToolName;
import staticContent.framework.message.MixMessage;
import staticContent.framework.message.Reply;
import staticContent.framework.message.Request;
import staticContent.framework.message.ExternalMessage.DummyStatus;
import staticContent.framework.routing.MixList;
import staticContent.framework.routing.RoutingMode;
import staticContent.framework.socket.connectedDatagram.ConnectedDatagramAnonServerSocketImpl;
import staticContent.framework.socket.connectedDatagram.ConnectedDatagramAnonSocketClientImpl;
import staticContent.framework.socket.datagram.DatagramAnonServerSocketImpl;
import staticContent.framework.socket.datagram.DatagramAnonSocketClientImpl;
import staticContent.framework.socket.socketInterfaces.AdaptiveAnonServerSocket;
import staticContent.framework.socket.socketInterfaces.AnonServerSocket;
import staticContent.framework.socket.socketInterfaces.ConnectedDatagramAnonServerSocket;
import staticContent.framework.socket.socketInterfaces.ConnectedDatagramAnonSocket;
import staticContent.framework.socket.socketInterfaces.DatagramAnonServerSocket;
import staticContent.framework.socket.socketInterfaces.DatagramAnonSocket;
import staticContent.framework.socket.socketInterfaces.IO_EventObserver;
import staticContent.framework.socket.socketInterfaces.StreamAnonServerSocket;
import staticContent.framework.socket.socketInterfaces.StreamAnonSocket;
import staticContent.framework.socket.socketInterfaces.AnonSocketOptions.CommunicationDirection;
import staticContent.framework.socket.socketInterfaces.NoneBlockingAnonSocketOptions.IO_Mode;
import staticContent.framework.socket.stream.StreamAnonServerSocketImpl;
import staticContent.framework.socket.stream.StreamAnonSocketClientImpl;
import staticContent.framework.userDatabase.User;
import staticContent.framework.userDatabase.UserDatabase;
import staticContent.framework.util.Util;
import userGeneratedContent.testbedPlugIns.staticFunctionPlugIns.layer5application.statisticsRecorder_v0_001.StatisticsRecorder;
public class AnonNode extends GMixTool {
// helper components
protected Settings settings;
protected UserDatabase userDatabase;
protected Clock clock;
protected InfoServiceClient infoService;
// references to controllers
protected Layer1NetworkMixController networkLayerMix;
protected Layer1NetworkClientController networkLayerClient;
protected Layer2RecodingSchemeMixController recodingLayerMix;
protected Layer2RecodingSchemeClientController recodingLayerClient;
protected Layer3OutputStrategyMixController outputStrategyLayerMix;
protected Layer3OutputStrategyClientController outputStrategyLayerClient;
protected Layer4TransportMixController transportLayerMix;
protected Layer4TransportClientController transportLayerClient;
protected Layer5ApplicationMixController applicationLayerMix;
protected Layer5ApplicationClientController applicationLayerClient;
protected RoutingModeInfoServiceController infoServiceRoutingPlugInClient;
protected DynamicRoutingClientController dynamicRoutingPlugInClient;
protected DynamicRoutingMixController dynamicRoutingPlugInMix;
protected GlobalRoutingClientController globalRoutingPlugInClient;
protected SourceRoutingClientController sourceRoutingPlugInClient;
// some settings
public int PUBLIC_PSEUDONYM; // this anon node will be registered under this pseudonym at the info-service; the pseudonym can be used by other anon nodes for addressing
public boolean IS_CLIENT;
public boolean IS_MIX;
public boolean IS_P2P;
public boolean IS_LAST_MIX; // exit node
public boolean IS_FIRST_MIX;
public boolean RECORD_STATISTICS_ON;
public boolean DISPLAY_ROUTE_INFO;
public boolean DEBUG_MODE_ON;
public boolean LOCAL_MODE_ON;
public boolean REPLY_DETECTION_ON;
public boolean RS_DEBUG_OUTPUT_ON;
public RoutingMode ROUTING_MODE;
public int NUMBER_OF_MIXES;
public int FREE_ROUTE_LENGTH;
public int EXPECTED_NUMBER_OF_USERS;
public String CRYPTO_PROVIDER;
public int NUMBER_OF_THREADS;
public int MAX_PAYLOAD;
public boolean LAYER_1_LINKS_MESSAGES; // when true, layer one will tag messages of the same user with a pseudonym (this is required by some plug-ins; e.g. some recoding schemes will transmit symmetrically encrypted messages after an initial hybridly encrypted message; the recoder plug-in needs the pseudonym to choose the right decryption key in that example)
public int QUEUE_BLOCK_SIZE;
public int SOCKET_MIX_BACKEND_QUEUE_SIZE;
public int SERVER_SOCKET_QUEUE_SIZE;
public int SERVER_SOCKET_BACKLOG;
public int TIME_TO_WAIT_FOR_FURTHER_DATA;
public String LAYER_4_CLIENT_INPUT_STREAM_REPLY_BUFFER_SIZE;
public String LAYER_4_MIX_INPUT_STREAM_REQUEST_BUFFER_SIZE;
// socket options
public boolean IS_DUPLEX;
public boolean IS_RELIABLE;
public boolean IS_CONNECTION_BASED;
public boolean IS_ORDER_PRESERVING;
// other
private Vector<Controller> components = new Vector<Controller>(); // instantiated controllers
private HashMap<Integer, AdaptiveAnonServerSocket> sockets; // TODO: maybe we should only use the hashmap, if at least two server sockets are opened (hash overhead for each message)
private ArrayBlockingQueue<Request[]> requestInputQueue;
private ArrayBlockingQueue<Request[]> requestOutputQueue;
private ArrayBlockingQueue<Reply[]> replyInputQueue;
private ArrayBlockingQueue<Reply[]> replyOutputQueue;
public MixList mixList;
public ToolName gMixTool;
public AnonNode(CommandLineParameters commandLineParameters) {
System.out.println("AnonNode initializing... (" +commandLineParameters.gMixTool +")");
initAndRegisterAtInfoService(commandLineParameters);
generateComponents();
setReferencesBetweenComponents();
loadImplementations(); // loads the plug-ins
if (IS_MIX)
infoService.waitForEndOfAddressExchangePhase();
else
infoService.waitTillMixesAreUp();
this.mixList = infoService.getMixList();
if (DISPLAY_ROUTE_INFO && ROUTING_MODE != RoutingMode.GLOBAL_ROUTING)
System.out.println("" +this +" received " +mixList);
callConstructors();
if (IS_MIX)
infoService.waitForEndOfRegistrationPhase();
initializeComponents(); // calls "initialize()" for each implementation
if (IS_MIX)
infoService.waitForEndOfInitializationPhase();
// TODO write config to disk
beginMixing(); // calls "begin()" for each implementation
if (IS_MIX)
infoService.waitForEndOfBeginPhase();
System.out.println("AnonNode up (" +commandLineParameters.gMixTool +": " +this.PUBLIC_PSEUDONYM +")");
}
private void callConstructors() {
for (Controller c:components)
if (c.implementation != null)
c.implementation.constructor();
}
private void loadImplementations() {
for (Controller c:components)
c.instantiateSubclass();
}
private void initializeComponents() {
for (Controller c:components)
c.initialize();
}
private void beginMixing() {
for (Controller c:components)
c.begin();
}
private void initAndRegisterAtInfoService(CommandLineParameters commandLineParameters) {
this.settings = commandLineParameters.generateSettingsObject();
this.userDatabase = new UserDatabase();
Util.removeCryptographyRestrictions();
this.gMixTool = commandLineParameters.gMixTool;
this.infoService = new InfoServiceClient(settings.getPropertyAsInetAddress("GLOBAL_INFO_SERVICE_ADDRESS"), settings.getPropertyAsInt("GLOBAL_INFO_SERVICE_PORT"));
this.infoServiceRoutingPlugInClient = new RoutingModeInfoServiceController(settings, clock);
if (commandLineParameters.gMixTool == ToolName.MIX || commandLineParameters.gMixTool == ToolName.P2P)
this.PUBLIC_PSEUDONYM = infoService.registerAsMix(infoServiceRoutingPlugInClient);
else
this.PUBLIC_PSEUDONYM = infoService.registerAsClient();
this.LOCAL_MODE_ON = infoService.getIsLocalModeOn();
if (!LOCAL_MODE_ON) {
System.err.println("WARNING: LOCAL_MODE is set to FALSE; Mixes and Information Service will be available via Network; Only safe for trusted networks!");
if (settings.getProperty("GLOBAL_MIX_BIND_ADDRESS").equalsIgnoreCase("AUTO"))
try {
settings.setProperty("GLOBAL_MIX_BIND_ADDRESS", InetAddress.getLocalHost().getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
throw new RuntimeException("could not detect ip address!");
}
} else {
settings.setProperty("GLOBAL_MIX_BIND_ADDRESS", "localhost");
}
if (settings.getProperty("GLOBAL_MIX_BIND_PORT").equalsIgnoreCase("AUTO")) {
int port = infoService.getSuggestedPort();
settings.setProperty("GLOBAL_MIX_BIND_PORT", ""+port);
}
this.IS_DUPLEX = settings.getPropertyAsBoolean("GLOBAL_IS_DUPLEX");
this.IS_RELIABLE = settings.getPropertyAsBoolean("GLOBAL_IS_RELIABLE");
this.IS_CONNECTION_BASED = settings.getPropertyAsBoolean("GLOBAL_IS_CONNECTION_BASED");
this.IS_ORDER_PRESERVING = settings.getPropertyAsBoolean("GLOBAL_IS_ORDER_PRESERVING");
this.REPLY_DETECTION_ON = settings.getPropertyAsBoolean("GLOBAL_REPLY_DETECTION_ON");
this.RS_DEBUG_OUTPUT_ON = settings.getPropertyAsBoolean("GLOBAL_RS_DEBUG_OUTPUT_ON");
this.ROUTING_MODE = RoutingMode.getMode(settings);
this.EXPECTED_NUMBER_OF_USERS = settings.getPropertyAsInt("GLOBAL_EXPECTED_NUMBER_OF_USERS");
this.CRYPTO_PROVIDER = settings.getProperty("GLOBAL_CRYPTO_PROVIDER");
this.NUMBER_OF_THREADS = settings.getPropertyAsInt("GLOBAL_NUMBER_OF_THREADS");
this.MAX_PAYLOAD = settings.getPropertyAsInt("GLOBAL_MAX_PAYLOAD");
this.QUEUE_BLOCK_SIZE = settings.getPropertyAsInt("GLOBAL_QUEUE_BLOCK_SIZE");
this.RECORD_STATISTICS_ON = settings.getPropertyAsBoolean("GLOBAL_RECORD_STATISTICS_ON");
MixMessage.recordStatistics = RECORD_STATISTICS_ON;
this.DISPLAY_ROUTE_INFO = settings.getPropertyAsBoolean("GLOBAL_DISPLAY_ROUTE_INFO");
this.LAYER_1_LINKS_MESSAGES = settings.getPropertyAsBoolean("GLOBAL_LAYER_1_LINKS_MESSAGES");
this.SOCKET_MIX_BACKEND_QUEUE_SIZE = settings.getPropertyAsInt("GLOBAL_SOCKET_MIX_BACKEND_QUEUE_SIZE");
this.SERVER_SOCKET_QUEUE_SIZE = settings.getPropertyAsInt("GLOBAL_SERVER_SOCKET_QUEUE_SIZE");
this.SERVER_SOCKET_BACKLOG = settings.getPropertyAsInt("GLOBAL_SERVER_SOCKET_BACKLOG");
this.TIME_TO_WAIT_FOR_FURTHER_DATA = settings.getPropertyAsInt("GLOBAL_TIME_TO_WAIT_FOR_FURTHER_DATA_IN_MICROSEC");
this.LAYER_4_CLIENT_INPUT_STREAM_REPLY_BUFFER_SIZE = settings.getProperty("GLOBAL_LAYER_4_CLIENT_INPUT_STREAM_REPLY_BUFFER_SIZE");
this.LAYER_4_MIX_INPUT_STREAM_REQUEST_BUFFER_SIZE = settings.getProperty("GLOBAL_LAYER_4_MIX_INPUT_STREAM_REQUEST_BUFFER_SIZE");
this.DEBUG_MODE_ON = infoService.getIsDebugModeOn();
this.NUMBER_OF_MIXES = infoService.getNumberOfMixes();
this.FREE_ROUTE_LENGTH = settings.getPropertyAsInt("GLOBAL_FREE_ROUTE_LENGTH");
if (ROUTING_MODE != RoutingMode.GLOBAL_ROUTING && FREE_ROUTE_LENGTH > NUMBER_OF_MIXES)
throw new RuntimeException("FREE_ROUTE_LENGTH > NUMBER_OF_MIXES!");
if (ROUTING_MODE != RoutingMode.GLOBAL_ROUTING && NUMBER_OF_MIXES == 1)
throw new RuntimeException("free route mode requires at least two mixes");
if (commandLineParameters.gMixTool == ToolName.CLIENT) {
this.IS_CLIENT = true;
} else if (commandLineParameters.gMixTool == ToolName.MIX) {
this.IS_MIX = true;
if (PUBLIC_PSEUDONYM == 0) // TODO
this.IS_FIRST_MIX = true;
if (PUBLIC_PSEUDONYM == NUMBER_OF_MIXES-1)
this.IS_LAST_MIX = true;
} else if (commandLineParameters.gMixTool == ToolName.P2P) {
this.IS_MIX = true;
this.IS_CLIENT = true;
this.IS_P2P = true;
if (PUBLIC_PSEUDONYM == 0) // TODO
this.IS_FIRST_MIX = true;
if (PUBLIC_PSEUDONYM == NUMBER_OF_MIXES-1)
this.IS_LAST_MIX = true;
} else {
throw new RuntimeException("not supported tool type specified: " +commandLineParameters.gMixTool);
}
if (IS_MIX) {
infoService.postValueAsMix(PUBLIC_PSEUDONYM, "ADDRESS", settings.getPropertyAsInetAddress("GLOBAL_MIX_BIND_ADDRESS").getAddress());
infoService.postValueAsMix(PUBLIC_PSEUDONYM, "PORT", Util.intToByteArray(settings.getPropertyAsInt("GLOBAL_MIX_BIND_PORT")));
this.sockets = new HashMap<Integer, AdaptiveAnonServerSocket>();
this.requestInputQueue = new ArrayBlockingQueue<Request[]>(settings.getPropertyAsInt("GLOBAL_REQUEST_INPUT_QUEUE_SIZE"));
this.requestOutputQueue = new ArrayBlockingQueue<Request[]>(settings.getPropertyAsInt("GLOBAL_REQUEST_OUTPUT_QUEUE_SIZE"));
this.replyInputQueue = new ArrayBlockingQueue<Reply[]>(settings.getPropertyAsInt("GLOBAL_REPLY_INPUT_QUEUE_SIZE"));
this.replyOutputQueue = new ArrayBlockingQueue<Reply[]>(settings.getPropertyAsInt("GLOBAL_REPLY_OUTPUT_QUEUE_SIZE"));
}
if (RECORD_STATISTICS_ON && IS_MIX && IS_LAST_MIX) {
StatisticsRecorder.init(this);
StatisticsSensor.init();
}
}
private void setReferencesBetweenComponents() {
for (Controller c:components)
c.setComponentReferences(networkLayerMix, networkLayerClient, recodingLayerMix, recodingLayerClient, outputStrategyLayerMix, outputStrategyLayerClient, transportLayerMix, transportLayerClient, applicationLayerMix, applicationLayerClient, dynamicRoutingPlugInClient, dynamicRoutingPlugInMix, globalRoutingPlugInClient, sourceRoutingPlugInClient);
}
private void generateComponents() {
// NOTE: the order of the items is important (do not change it)
if (IS_MIX) {
this.outputStrategyLayerMix = new Layer3OutputStrategyMixController(this, settings, userDatabase, clock, infoService);
this.components.add(outputStrategyLayerMix);
this.recodingLayerMix = new Layer2RecodingSchemeMixController(this, settings, userDatabase, clock, infoService);
this.components.add(recodingLayerMix);
this.networkLayerMix = new Layer1NetworkMixController(this, settings, userDatabase, clock, infoService);
this.components.add(networkLayerMix);
this.transportLayerMix = new Layer4TransportMixController(this, settings, userDatabase, clock, infoService);
this.components.add(transportLayerMix);
this.applicationLayerMix = new Layer5ApplicationMixController(this, settings, userDatabase, clock, infoService);
this.components.add(applicationLayerMix);
if (ROUTING_MODE == RoutingMode.DYNAMIC_ROUTING)
this.dynamicRoutingPlugInMix = new DynamicRoutingMixController(this, settings, userDatabase, clock, infoService);
}
if (IS_CLIENT) { // the lower layer client plug-ins are loaded at runtime when a socket is created (directly or through layer 5 plug-ins)
this.outputStrategyLayerClient = new Layer3OutputStrategyClientController(this, settings, userDatabase, clock, infoService);
this.components.add(outputStrategyLayerClient);
this.recodingLayerClient = new Layer2RecodingSchemeClientController(this, settings, userDatabase, clock, infoService);
this.components.add(recodingLayerClient);
this.networkLayerClient = new Layer1NetworkClientController(this, settings, userDatabase, clock, infoService);
this.components.add(networkLayerClient);
this.transportLayerClient = new Layer4TransportClientController(this, settings, userDatabase, clock, infoService);
this.components.add(transportLayerClient);
this.applicationLayerClient = new Layer5ApplicationClientController(this, settings, userDatabase, clock, infoService);
this.components.add(applicationLayerClient);
if (ROUTING_MODE == RoutingMode.DYNAMIC_ROUTING)
this.dynamicRoutingPlugInClient = new DynamicRoutingClientController(this, settings, userDatabase, clock, infoService);
else if (ROUTING_MODE == RoutingMode.GLOBAL_ROUTING)
this.globalRoutingPlugInClient = new GlobalRoutingClientController(this, settings, userDatabase, clock, infoService);
else if (ROUTING_MODE == RoutingMode.SOURCE_ROUTING)
this.sourceRoutingPlugInClient = new SourceRoutingClientController(this, settings, userDatabase, clock, infoService);
}
}
public StreamAnonServerSocket createStreamAnonServerSocket(
int bindPort,
CommunicationDirection communicationMode,
IO_Mode ioMode,
boolean isFreeRoute
) {
return createStreamAnonServerSocket(
bindPort,
communicationMode,
ioMode,
null,
isFreeRoute
);
}
public StreamAnonServerSocket createStreamAnonServerSocket(
int bindPort,
CommunicationDirection communicationMode,
IO_Mode ioMode,
IO_EventObserver requestObserver,
boolean isFreeRoute
) {
if (!IS_MIX)
throw new RuntimeException("only mix and p2p anon nodes can create server sockets");
if (sockets.get(bindPort) != null)
throw new RuntimeException("this port is already in use");
return new StreamAnonServerSocketImpl(
this,
PUBLIC_PSEUDONYM,
bindPort,
communicationMode,
ioMode,
requestObserver,
isFreeRoute
);
}
public DatagramAnonServerSocket createDatagramServerSocket(
int bindPort,
CommunicationDirection communicationMode,
IO_Mode ioMode,
boolean isReliable,
boolean isOrderPreserving,
boolean isFreeRoute
) {
return createDatagramServerSocket(
bindPort,
communicationMode,
ioMode,
null,
isReliable,
isOrderPreserving,
isFreeRoute
);
}
public DatagramAnonServerSocket createDatagramServerSocket(
int bindPort,
CommunicationDirection communicationMode,
IO_Mode ioMode,
IO_EventObserver requestObserver,
boolean isReliable,
boolean isOrderPreserving,
boolean isFreeRoute
) {
if (!IS_MIX)
throw new RuntimeException("only mix and p2p anon nodes can create server sockets");
if (sockets.get(bindPort) != null)
throw new RuntimeException("this port is already in use");
return new DatagramAnonServerSocketImpl(
this,
PUBLIC_PSEUDONYM,
bindPort,
communicationMode,
ioMode,
requestObserver,
isReliable,
isOrderPreserving,
isFreeRoute
);
}
public ConnectedDatagramAnonServerSocket createConnectedDatagramServerSocket(
int bindPort,
CommunicationDirection communicationMode,
IO_Mode ioMode,
boolean isReliable,
boolean isOrderPreserving,
boolean isFreeRoute
) {
return createConnectedDatagramServerSocket(
bindPort,
communicationMode,
ioMode,
null,
isReliable,
isOrderPreserving,
isFreeRoute
);
}
public ConnectedDatagramAnonServerSocket createConnectedDatagramServerSocket(
int bindPort,
CommunicationDirection communicationMode,
IO_Mode ioMode,
IO_EventObserver requestObserver,
boolean isReliable,
boolean isOrderPreserving,
boolean isFreeRoute
) {
if (!IS_MIX)
throw new RuntimeException("only mix and p2p anon nodes can create server sockets");
if (sockets.get(bindPort) != null)
throw new RuntimeException("this port is already in use");
return new ConnectedDatagramAnonServerSocketImpl(
this,
PUBLIC_PSEUDONYM,
bindPort,
communicationMode,
ioMode,
requestObserver,
isReliable,
isOrderPreserving,
isFreeRoute
);
}
public void registerServerSocket(AdaptiveAnonServerSocket serverSocket) {
if (sockets.get(serverSocket.getBindPort()) != null)
throw new RuntimeException("this port is already in use: " +serverSocket.getBindPort());
sockets.put(serverSocket.getBindPort(), serverSocket);
}
// return null if no socket available
public AnonServerSocket getServerSocket(int port) {
if (!IS_MIX)
throw new RuntimeException("only mixes can open server sockets");
return sockets.get(port);
}
// return false if no socket found
public boolean removeSocket(int port) {
return sockets.remove(port) != null;
}
public DatagramAnonSocket createDatagramSocket(
CommunicationDirection communicationMode,
boolean isReliable,
boolean isOrderPreserving,
boolean isFreeRoute
) {
if (!IS_CLIENT)
throw new RuntimeException("only clients/p2p mixes can open none-server sockets");
return new DatagramAnonSocketClientImpl(
this,
communicationMode,
isReliable,
isOrderPreserving,
isFreeRoute
);
}
public StreamAnonSocket createStreamSocket(
CommunicationDirection communicationMode,
boolean isFreeRoute
) {
if (!IS_CLIENT)
throw new RuntimeException("only clients/p2p mixes can open none-server sockets");
return new StreamAnonSocketClientImpl(
this,
communicationMode,
isFreeRoute
);
}
public ConnectedDatagramAnonSocket createConnectedDatagramSocket(
CommunicationDirection communicationMode,
boolean isReliable,
boolean isOrderPreserving,
boolean isFreeRoute
) {
return new ConnectedDatagramAnonSocketClientImpl(
this,
communicationMode,
isReliable,
isOrderPreserving,
isFreeRoute
);
}
// called by layer 3 (output strategy) mix plug-ins
public void putOutRequest(Request request) {
if (!request.isFinalHop(this)) { // put request in output queue, from where it will be sent to the next hop (via layer 1)
putInRequestOutputQueue(request);
} else { // final hop: forward to layer 4 (note: layer 4 will call forwardToLayer5() later)
assert request.getDummyStatus() != DummyStatus.UNKNOWN;
if (request.getDummyStatus() == DummyStatus.NO_DUMMY) {
if (DISPLAY_ROUTE_INFO && ROUTING_MODE != RoutingMode.GLOBAL_ROUTING)
System.out.println("" +this +": i'm the final hop");
transportLayerMix.forwardRequest(request);
// TODO: log goodput, dummy-overhead and packet-padding-overhead separately
} else {
// we do not forward dummies to layer 4...
}
}
}
// called by layer 4 (transport) mix plug-ins
public void forwardToLayer5(Request request) {
// find desired socket and forward request to it
AdaptiveAnonServerSocket destSocket = null;
int dstPort = 0;
assert request.getDummyStatus() != DummyStatus.UNKNOWN;
if (request.getDummyStatus() == DummyStatus.NO_DUMMY) {
dstPort = Util.byteArrayToShort(Arrays.copyOf(request.getByteMessage(), 2)); // get desired socket
request.setByteMessage(Arrays.copyOfRange(request.getByteMessage(), 2, request.getByteMessage().length));
destSocket = sockets.get(dstPort);
if (destSocket == null) {
System.err.println("received message for unknown port: " +dstPort);
return;
} else {
destSocket.incomingRequest(request);
}
} // TODO: log goodput, dummy-overhead and packet-padding-overhead separately
if (this.RECORD_STATISTICS_ON) {
StatisticsRecorder.addMessageDwellTimeRecord(request);
StatisticsRecorder.addRequestThroughputRecord(request.getByteMessage().length, request.getOwner());
StatisticsSensor.addRequestThroughputRecord(request.getByteMessage().length);
}
}
// called by layer 3 (output strategy) mix plug-ins
public void putOutRequests(Request[] requests) {
if (ROUTING_MODE == RoutingMode.GLOBAL_ROUTING && !IS_LAST_MIX) { // put data in request output queue, from where it will be forwarded to the next mix via the layer 1 plug-in
putInRequestOutputQueue(requests);
} else {
for (Request request:requests)
putOutRequest(request);
}
}
public void putOutReply(Reply reply) {
assert reply != null;
this.putInReplyOutputQueue(reply);
}
public void putOutReplies(Reply[] replies) {
this.putInReplyOutputQueue(replies);
}
public ArrayBlockingQueue<Request[]> getRequestInputQueue() {
return this.requestInputQueue;
}
public ArrayBlockingQueue<Request[]> getRequestOutputQueue() {
return this.requestOutputQueue;
}
public ArrayBlockingQueue<Reply[]> getReplyInputQueue() {
return this.replyInputQueue;
}
public ArrayBlockingQueue<Reply[]> getReplyOutputQueue() {
return this.replyOutputQueue;
}
public Request[] getFromRequestInputQueue() {
try {
return requestInputQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
return getFromRequestInputQueue();
}
}
public Request[] getFromRequestOutputQueue() {
try {
return requestOutputQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
return getFromRequestOutputQueue();
}
}
public Reply[] getFromReplyInputQueue() {
try {
return replyInputQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
return getFromReplyInputQueue();
}
}
public Reply[] getFromReplyOutputQueue() {
try {
return replyOutputQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
return getFromReplyOutputQueue();
}
}
public void putInRequestInputQueue(Request[] requests) {
assert requests != null;
assert requests.length != 0;
if (requests.length > QUEUE_BLOCK_SIZE) {
Request[][] splitted = Util.splitInChunks(QUEUE_BLOCK_SIZE, requests);
for (Request[] block:splitted) {
try {
requestInputQueue.put(block);
} catch (InterruptedException e) {
e.printStackTrace();
putInRequestInputQueue(block);
}
}
} else {
try {
requestInputQueue.put(requests);
} catch (InterruptedException e) {
e.printStackTrace();
putInRequestInputQueue(requests);
}
}
}
//
public void putInRequestInputQueue(Request request) {
assert request != null;
try {
requestInputQueue.put(new Request[]{request});
} catch (InterruptedException e) {
e.printStackTrace();
putInRequestInputQueue(request);
}
}
public void putInRequestOutputQueue(Request request) {
assert request != null;
try {
requestOutputQueue.put(new Request[]{request});
} catch (InterruptedException e) {
e.printStackTrace();
putInRequestOutputQueue(request);
}
}
public void putInRequestOutputQueue(Request[] requests) {
assert requests != null;
assert requests.length != 0;
if (requests.length > QUEUE_BLOCK_SIZE) {
Request[][] splitted = Util.splitInChunks(QUEUE_BLOCK_SIZE, requests);
for (Request[] block:splitted) {
try {
requestOutputQueue.put(block);
} catch (InterruptedException e) {
e.printStackTrace();
putInRequestOutputQueue(block);
}
}
}
try {
requestOutputQueue.put(requests);
} catch (InterruptedException e) {
e.printStackTrace();
putInRequestOutputQueue(requests);
}
}
public void forwardToLayer2(Reply reply) {
putInReplyInputQueue(reply);
}
public void putInReplyInputQueue(Reply reply) {
assert reply != null;
try {
replyInputQueue.put(new Reply[]{reply});
} catch (InterruptedException e) {
e.printStackTrace();
putInReplyInputQueue(reply);
}
if (this.IS_LAST_MIX && this.RECORD_STATISTICS_ON) {
StatisticsRecorder.addReplyThroughputRecord(reply.getByteMessage().length, reply.getOwner());
StatisticsSensor.addReplyThroughputRecord(reply.getByteMessage().length);
}
}
public void forwardToLayer2(Reply[] replies) {
putInReplyInputQueue(replies);
}
public void putInReplyInputQueue(Reply[] replies) {
assert replies != null;
assert replies.length != 0;
if (replies.length > QUEUE_BLOCK_SIZE) {
Reply[][] splitted = Util.splitInChunks(QUEUE_BLOCK_SIZE, replies);
for (Reply[] block:splitted) {
try {
for (Reply r:block) {
if (this.IS_LAST_MIX && this.RECORD_STATISTICS_ON) {
StatisticsRecorder.addReplyThroughputRecord(r.getByteMessage().length, r.getOwner());
StatisticsSensor.addReplyThroughputRecord(r.getByteMessage().length);
}
}
replyInputQueue.put(block);
} catch (InterruptedException e) {
e.printStackTrace();
putInReplyInputQueue(block);
}
}
} else {
try {
replyInputQueue.put(replies);
} catch (InterruptedException e) {
e.printStackTrace();
putInReplyInputQueue(replies);
}
}
//if (this.RECORD_STATISTICS_ON)
// for (Reply reply:replies)
// StatisticsRecorder.addReplyThroughputRecord(reply.getByteMessage().length, reply.getOwner());
}
public void putInReplyOutputQueue(Reply reply) {
assert reply != null;
try {
replyOutputQueue.put(new Reply[]{reply});
} catch (InterruptedException e) {
e.printStackTrace();
putInReplyOutputQueue(reply);
}
}
public void putInReplyOutputQueue(Reply[] replies) {
assert replies != null;
assert replies.length != 0;
if (replies.length > QUEUE_BLOCK_SIZE) {
Reply[][] splitted = Util.splitInChunks(QUEUE_BLOCK_SIZE, replies);
for (Reply[] block:splitted) {
try {
replyOutputQueue.put(block);
} catch (InterruptedException e) {
e.printStackTrace();
putInReplyOutputQueue(block);
}
}
} else {
try {
replyOutputQueue.put(replies);
} catch (InterruptedException e) {
e.printStackTrace();
putInReplyOutputQueue(replies);
}
}
}
public void write(User user, byte[] data) {
outputStrategyLayerMix.write(user, data);
}
public Settings getSettings() {
return this.settings;
}
public UserDatabase getUserDatabase() {
return this.userDatabase;
}
public Clock getClock() {
return this.clock;
}
public InfoServiceClient getInfoService() {
return this.infoService;
}
public Layer1NetworkMixController getNetworkLayerControllerMix() {
return networkLayerMix;
}
public Layer1NetworkClientController getNetworkLayerControllerClient() {
return networkLayerClient;
}
public Layer2RecodingSchemeMixController getRecodingLayerControllerMix() {
return recodingLayerMix;
}
public Layer2RecodingSchemeClientController getRecodingLayerControllerClient() {
return recodingLayerClient;
}
public Layer3OutputStrategyMixController getOutputStrategyLayerControllerMix() {
return outputStrategyLayerMix;
}
public Layer3OutputStrategyClientController getOutputStrategyLayerControllerClient() {
return outputStrategyLayerClient;
}
public Layer4TransportMixController getTransportLayerControllerMix() {
return transportLayerMix;
}
public Layer4TransportClientController getTransportLayerControllerClient() {
return transportLayerClient;
}
public Layer5ApplicationMixController getApplicationLayerControllerMix() {
return applicationLayerMix;
}
public Layer5ApplicationClientController getApplicationLayerControllerClient() {
return applicationLayerClient;
}
public DynamicRoutingClientController getDynamicRoutingClientController() {
return dynamicRoutingPlugInClient;
}
public DynamicRoutingMixController getDynamicRoutingMixController() {
return dynamicRoutingPlugInMix;
}
public GlobalRoutingClientController getGlobalRoutingClientController() {
return globalRoutingPlugInClient;
}
public SourceRoutingClientController getSourceRoutingClientController() {
return sourceRoutingPlugInClient;
}
@Override
public String toString() {
return "AnonNode (" +this.gMixTool +" " +this.PUBLIC_PSEUDONYM +")";
}
/**
* Comment
*
* @param args Not used.
*/
public static void main(String[] args) {
CommandLineParameters params = new CommandLineParameters(args);
params.gMixTool = ToolName.MIX;
new AnonNode(params);
}
}