/******************************************************************************* * 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.simulatorPlugIns.plugins.outputStrategy; import java.util.HashMap; import java.util.Map; import java.util.Vector; 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.EventExecutor; import staticContent.evaluation.simulator.core.message.MessageFragment; import staticContent.evaluation.simulator.core.message.MixMessage; import staticContent.evaluation.simulator.core.message.TransportMessage; import staticContent.evaluation.simulator.core.networkComponent.AbstractClient; import staticContent.evaluation.simulator.core.networkComponent.Mix; import userGeneratedContent.simulatorPlugIns.pluginRegistry.MixSendStyle; import userGeneratedContent.simulatorPlugIns.pluginRegistry.Topology; import userGeneratedContent.simulatorPlugIns.plugins.clientSendStyle.ClientBasicSynchronous; import userGeneratedContent.simulatorPlugIns.plugins.clientSendStyle.ClientSendStyleImpl; import userGeneratedContent.simulatorPlugIns.plugins.clientSendStyle.ClientSendWithoutMixes; import userGeneratedContent.simulatorPlugIns.plugins.mixSendStyle.MixSendStyleImpl; // 1991: Andreas Pfitzmann, Birgit Pfitzmann, Michael Waidner: ISDN-MIXes: // Untraceable Communication with Very Small Bandwidth Overhead // simplified version; no broadcast; no anonymity for servers // mix that expects exactly one message from each participant per "sendingRate" // (see class "ClientBasicSynchronous") // (blocks until every client has sent a message!) // will put out a reply batch every "replyRate" ms // (creates dummies if no data available) @Plugin(pluginKey = "BASIC_SYNCHRONOUS_BATCH", pluginName = "Basic Synchronous Batch") public class BasicSynchronousBatch extends OutputStrategyImpl implements EventExecutor { public class SimplexSynchronousBatch { private final int batchSize; private final MixMessage[] collectedMessages; private final boolean isRequestBatch; private int nextFreeSlot = 0; public SimplexSynchronousBatch(int batchSize, boolean isRequestBatch) { this.batchSize = batchSize; this.isRequestBatch = isRequestBatch; this.collectedMessages = new MixMessage[batchSize]; } public void addMessage(MixMessage mixMessage) { this.collectedMessages[this.nextFreeSlot++] = mixMessage; if (this.nextFreeSlot == this.batchSize) { for (MixMessage m : this.collectedMessages) { if (this.isRequestBatch) { BasicSynchronousBatch.this.mix.putOutRequest(m); } else { BasicSynchronousBatch.this.mix.putOutReply(m); } } this.nextFreeSlot = 0; } } } private Map<String, Vector<TransportMessage>> clientReplyWaitingQueues; private SimplexSynchronousBatch replyBatch; @IntSimulationProperty( name = "Reply interval (ms)", key = "BASIC_SYNCHRONOUS_REPLY_INTERVAL_IN_MS", min = 0 ) private int replyInterval; private final SimplexSynchronousBatch requestBatch; public BasicSynchronousBatch(Mix mix, Simulator simulator) { super(mix, simulator); int batchSize = Simulator.getSimulator().getNumberOfClients(); this.requestBatch = new SimplexSynchronousBatch(batchSize, true); if (super.simulateReplyChannel) { this.replyBatch = new SimplexSynchronousBatch(batchSize, false); this.replyInterval = Simulator.settings .getPropertyAsInt("BASIC_SYNCHRONOUS_REPLY_INTERVAL_IN_MS"); if (mix.isLastMix()) { this.clientReplyWaitingQueues = new HashMap<String, Vector<TransportMessage>>(); for (AbstractClient c : simulator.getClients().values()) { this.clientReplyWaitingQueues.put(c.getIdentifier(), new Vector<TransportMessage>(10, 10)); } } // schedule first reply batch: Event putOutNextReplyBatchEvent = new Event(this, Simulator.getNow() + this.replyInterval, OutputStrategyEvent.PUT_OUT_REPLY_BATCH); simulator.scheduleEvent(putOutNextReplyBatchEvent, this); } } @Override public void executeEvent(Event event) { if (event.getEventType() != OutputStrategyEvent.PUT_OUT_REPLY_BATCH) { throw new RuntimeException("ERROR! received unsupported event!" + event); } this.putOutReplyBatch(); } @Override public ClientSendStyleImpl getClientSendStyle(AbstractClient client) { boolean noMixes = !Topology.getTopology().containsAtLeastOneMix(); boolean noRequestChannel = Simulator.settings.getProperty( "COMMUNICATION_MODE").equals("SIMPLEX_REPLY"); if (noMixes || noRequestChannel) { return new ClientSendWithoutMixes(client, Simulator.getSimulator()); } else { return new ClientBasicSynchronous(client, Simulator.getSimulator()); } } @Override public MixSendStyleImpl getMixSendStyle() { return MixSendStyle.getInstance(this.mix, this.mix); } @Override public void incomingReply(MixMessage mixMessage) { this.replyBatch.addMessage(mixMessage); } public void incomingReply(TransportMessage transportMessage) { if (!this.mix.isLastMix()) { throw new RuntimeException( "ERROR: BasicSynchronousBatch only supports TransportMessage as reply from distant proxy!"); } this.clientReplyWaitingQueues.get( transportMessage.getOwner().getIdentifier()).add( transportMessage); } @Override public void incomingRequest(MixMessage mixMessage) { this.requestBatch.addMessage(mixMessage); } private void putOutReplyBatch() { for (AbstractClient client : this.simulator.getClients().values()) { Vector<TransportMessage> replyWaitingQueue = this.clientReplyWaitingQueues .get(client.getIdentifier()); boolean isDummy = replyWaitingQueue.size() == 0 ? true : false; MixMessage mixMessage = MixMessage.getInstance(false, this.mix, client, client, Simulator.getNow(), isDummy); if (isDummy) { this.incomingReply(mixMessage); } else { for (int i = 0; i < replyWaitingQueue.size(); i++) { TransportMessage noneMixMessage = replyWaitingQueue.get(i); if ((mixMessage.getFreeSpace() >= noneMixMessage .getLength()) && !noneMixMessage.isFragmented()) { // noneMixMessage // fits // in // mixMessage // completely replyWaitingQueue.remove(noneMixMessage); i--; mixMessage.addPayloadObject(noneMixMessage); } else { // add Fragment if (noneMixMessage.hasNextFragment()) { MessageFragment messageFragment = noneMixMessage .getFragment(mixMessage.getFreeSpace()); mixMessage.addPayloadObject(messageFragment); } if (!noneMixMessage.hasNextFragment()) { replyWaitingQueue.remove(i); i--; } } if (mixMessage.getFreeSpace() == 0) { break; } } this.incomingReply(mixMessage); } } Event sendNextReplyEvent = new Event(this, Simulator.getNow() + this.replyInterval, OutputStrategyEvent.PUT_OUT_REPLY_BATCH); this.simulator.scheduleEvent(sendNextReplyEvent, this); } }