/*
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 Karl-Peter Fuchs
*
* 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.simulatorPlugIns.plugins.trafficSource;
import org.apache.commons.math.random.RandomDataImpl;
import staticContent.evaluation.simulator.Simulator;
import staticContent.evaluation.simulator.annotations.plugin.Plugin;
import staticContent.evaluation.simulator.annotations.property.IntSimulationProperty;
import staticContent.evaluation.simulator.core.event.Event;
import staticContent.evaluation.simulator.core.event.SimulationEvent;
import staticContent.evaluation.simulator.core.message.EndToEndMessage;
import staticContent.evaluation.simulator.core.networkComponent.AbstractClient;
import staticContent.evaluation.traceParser.engine.dataStructure.ExtendedTransaction;
/**
*
* logic: paper "Never Been KIST: Tor’s Congestion Management Blossoms with
* Kernel-Informed Socket Transport", 2014, Rob Jansen, John Geddes, Chris
* Wacek, Micah Sherr, Paul Syverson
*
* web-clients: 78.26%:
* 1: wait [1,60000] ms (uniform)
* 2: download 320 KiB
* 3: goto 1
* dl-clients: 8.69%
* 1: download 5 MiB
* 2: goto
* tor-perf1: 4.35%
* 1: wait 60000 ms
* 2. download 50 KiB
* 3. goto 1
* tor-perf2: 4.35%
* 1: wait 60000 ms
* 2. download 1 MiB
* 3. goto 1
* tor-perf3: 4.35%
* 1: wait 60000 ms
* 2. download 5 MiB
* 3. goto 1
* Total: one hour simulation time
*
*/
@Plugin(pluginKey = "JANSEN", pluginName="Jansen Model")
public class JansenClient extends AbstractClient {
public enum ClientType {WEB, DOWNLOAD, PERF1, PERF2, PERF3};
private ClientType clientType;
private RandomDataImpl rand = new RandomDataImpl();
private int requestSize;
@IntSimulationProperty( name = "Maximum bytes/sec for server to send replies (bw-limit)",
key = "JANSEN_SERVER_BW_LIMIT_BYTES_PER_SEC",
min = 1)
private int maxBytesPerSec;
private int sendInterval;
private int maxReplyPayloadSize;
private int expectedReplies = 0;
private int receivedReplies = 0;
public JansenClient(ClientType clientType, String identifier, Simulator simulator, int clientId) {
super(identifier, simulator);
this.clientId = clientId;
this.clientType = clientType;
this.requestSize = Simulator.settings.getPropertyAsInt("MIX_REQUEST_PAYLOAD_SIZE");
this.maxReplyPayloadSize = Simulator.settings.getPropertyAsInt("MIX_REPLY_PAYLOAD_SIZE");
this.maxBytesPerSec = Simulator.settings.getPropertyAsInt("JANSEN_SERVER_BW_LIMIT_BYTES_PER_SEC");
this.sendInterval = (int) Math.round(1000d/((double)maxBytesPerSec/(double)maxReplyPayloadSize));
}
public void startSending() {
int delay = rand.nextSecureInt(1, 1000);
Event startSendingEvent = new Event(this, Simulator.getNow() + delay, JansenClientEvent.START_SENDING);
simulator.scheduleEvent(startSendingEvent, this);
}
@Override
public void incomingMessage(EndToEndMessage message) {
receivedReplies ++;
if (receivedReplies == expectedReplies)
scheduleNextMessage();
}
@Override
public void messageReachedServer(EndToEndMessage message) {
// JansenClient uses arrival of reply as feedback, so we do
// nothing here
}
/**
*
* logic: paper "Never Been KIST: Tor’s Congestion Management Blossoms with
* Kernel-Informed Socket Transport", 2014, Rob Jansen, John Geddes, Chris
* Wacek, Micah Sherr, Paul Syverson
*
* web-clients: 78.26%:
* 1: wait [1,60000] ms (uniform)
* 2: download 320 KiB
* 3: goto 1
* dl-clients: 8.69%
* 1: download 5 MiB
* 2: goto
* tor-perf1: 4.35%
* 1: wait 60000 ms
* 2. download 50 KiB
* 3. goto 1
* tor-perf2: 4.35%
* 1: wait 60000 ms
* 2. download 1 MiB
* 3. goto 1
* tor-perf3: 4.35%
* 1: wait 60000 ms
* 2. download 5 MiB
* 3. goto 1
* Total: one hour simulation time
*
*/
private void scheduleNextMessage() {
if (clientType == ClientType.WEB) {
int delay = rand.nextSecureInt(1, 60000);
int replySize = 320*1024;
ExtendedTransaction et = createTransaction(replySize);
EndToEndMessage eteMessage = new EndToEndMessage(0, et, true);
Event sendNextMessageEvent = new Event(this, Simulator.getNow() + delay, JansenClientEvent.SEND_NEXT_MESSAGE, eteMessage);
simulator.scheduleEvent(sendNextMessageEvent, this);
} else if (clientType == ClientType.DOWNLOAD) {
int replySize = 5*1024*1024;
ExtendedTransaction et = createTransaction(replySize);
EndToEndMessage eteMessage = new EndToEndMessage(0, et, true);
sendMessage(eteMessage);
} else if (clientType == ClientType.PERF1) {
int delay = 60000;
int replySize = 50*1024;
ExtendedTransaction et = createTransaction(replySize);
EndToEndMessage eteMessage = new EndToEndMessage(0, et, true);
Event sendNextMessageEvent = new Event(this, Simulator.getNow() + delay, JansenClientEvent.SEND_NEXT_MESSAGE, eteMessage);
simulator.scheduleEvent(sendNextMessageEvent, this);
} else if (clientType == ClientType.PERF2) {
int delay = 60000;
int replySize = 1024*1024;
ExtendedTransaction et = createTransaction(replySize);
EndToEndMessage eteMessage = new EndToEndMessage(0, et, true);
Event sendNextMessageEvent = new Event(this, Simulator.getNow() + delay, JansenClientEvent.SEND_NEXT_MESSAGE, eteMessage);
simulator.scheduleEvent(sendNextMessageEvent, this);
} else if (clientType == ClientType.PERF3) {
int delay = 60000;
int replySize = 5*1024*1024;
ExtendedTransaction et = createTransaction(replySize);
EndToEndMessage eteMessage = new EndToEndMessage(0, et, true);
Event sendNextMessageEvent = new Event(this, Simulator.getNow() + delay, JansenClientEvent.SEND_NEXT_MESSAGE, eteMessage);
simulator.scheduleEvent(sendNextMessageEvent, this);
} else {
throw new RuntimeException("Unknown ClientType -> check source code (impementation fault)");
}
}
private ExtendedTransaction createTransaction(int toSend) {
int numberOfReplies = (int)Math.ceil((double)toSend/maxReplyPayloadSize);
long[] replyOffsets = new long[numberOfReplies];
int[] replySizes = new int[numberOfReplies];
int remaining = toSend;
int replyOffset = 0;
for (int i=0; i<numberOfReplies; i++) {
replyOffsets[i] = replyOffset;
replyOffset += sendInterval;
if (remaining >= maxReplyPayloadSize) {
replySizes[i] = maxReplyPayloadSize;
remaining -= maxReplyPayloadSize;
} else {
replySizes[i] = remaining;
}
}
this.expectedReplies = numberOfReplies;
this.receivedReplies = 0;
return new ExtendedTransaction(0, 0l, 0l, requestSize, 0, replyOffsets, replyOffsets, replySizes);
}
// TODO:remove:
public static ExtendedTransaction createT(int toSend, int maxReplyPayloadSize, int sendInterval, int requestSize) {
int numberOfReplies = (int)Math.ceil((double)toSend/maxReplyPayloadSize);
long[] replyOffsets = new long[numberOfReplies];
int[] replySizes = new int[numberOfReplies];
int remaining = toSend;
int replyOffset = 0;
for (int i=0; i<numberOfReplies; i++) {
replyOffsets[i] = replyOffset;
replyOffset += sendInterval;
if (remaining >= maxReplyPayloadSize) {
replySizes[i] = maxReplyPayloadSize;
remaining -= maxReplyPayloadSize;
} else {
replySizes[i] = remaining;
}
}
expectedR = numberOfReplies;
return new ExtendedTransaction(0, 0l, 0l, requestSize, 0, replyOffsets, replyOffsets, replySizes);
}
static int expectedR = 0;
/**
* Comment
*
* @param args Not used.
*/
public static void main(String[] args) {
Integer[] test = new Integer[] {(50*1024), (320*1024), (1024*1024), (5*1024*1024)};
int sendInterval = (int) Math.round(1000d/((double)15625/(double)512));
for (int i=0; i<test.length; i++) {
System.out.println();
System.out.println("size: " +test[i]);
createT(test[i], 512, sendInterval, 512);
System.out.println("expected replies: " +expectedR);
System.out.println("transfer duration: " +(expectedR*sendInterval) +"ms");
/*System.out.println();
int numberOfClients = test[i];
int webClients = (int) Math.round(0.7826d*(double)numberOfClients);
int dlClients = (int) Math.round(0.0869d*(double)numberOfClients);
int perf1Clients = (int) Math.round(0.0435d*(double)numberOfClients);
int perf2Clients = (int) Math.round(0.0435d*(double)numberOfClients);
int perf3Clients = (int) Math.round(0.0435d*(double)numberOfClients);
int sum = webClients + dlClients + perf1Clients + perf2Clients + perf3Clients;
if (sum < numberOfClients)
webClients += numberOfClients - sum;
else if (sum > numberOfClients)
webClients--;
System.out.println();
System.out.println(numberOfClients + " clients:");
System.out.println("web: " +webClients);
System.out.println("dlClients: " +dlClients);
System.out.println("perf1Clients: " +perf1Clients);
System.out.println("perf2Clients: " +perf2Clients);
System.out.println("perf3Clients: " +perf3Clients); */
System.out.println();
}
}
@Override
public void close() {
// nothing to do here
}
@Override
public void executeEvent(Event event) {
if (event.getEventType() instanceof JansenClientEvent) {
if (event.getEventType() == JansenClientEvent.SEND_NEXT_MESSAGE) {
sendMessage((EndToEndMessage)event.getAttachment());
} else if (event.getEventType() == JansenClientEvent.START_SENDING) {
scheduleNextMessage();
} else {
throw new RuntimeException("ERROR: received unknown Event: " +event.toString());
}
} else {
super.executeEvent(event);
}
}
private enum JansenClientEvent implements SimulationEvent {
SEND_NEXT_MESSAGE,
START_SENDING;
}
}