Commit f4559a45 authored by Björn Richerzhagen's avatar Björn Richerzhagen
Browse files

initialized clean Simonstrator-PeerfactSim.KOM-repository to FINALLY get rid...

initialized clean Simonstrator-PeerfactSim.KOM-repository to FINALLY get rid of huge blob objects and ancient history that is not relevant to the simonstrator-branch of PeerfactSim.KOM
parents
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.linklayer.mac.wifi;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
/**
* This class is the state of the stations of the {@link IdealRemoteStation}. It
* stores the last SNR of a received Message of this station.
*
* @author Christoph Muenker
* @version 1.0, 22.02.2013
*/
public class IdealRemoteStation implements IWifiRemoteStation {
private double lastSnr = Double.MIN_VALUE;
private MacAddress address;
public IdealRemoteStation(MacAddress address) {
this.address = address;
}
public void setLastSnr(double lastSnr) {
this.lastSnr = lastSnr;
}
public double getLastSnr() {
return lastSnr;
}
@Override
public MacAddress getMacAddress() {
return address;
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.linklayer.mac.wifi;
import java.text.DecimalFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.analyzer.LinklayerAnalyzer;
import de.tud.kom.p2psim.api.analyzer.MessageAnalyzer.Reason;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.linklayer.LinkLayerMessage;
import de.tud.kom.p2psim.api.linklayer.mac.Link;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tud.kom.p2psim.api.linklayer.mac.MacEventInformation;
import de.tud.kom.p2psim.api.linklayer.mac.PhyType;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.views.TopologyView;
import de.tud.kom.p2psim.api.topology.views.wifi.phy.PropagationLossModel;
import de.tud.kom.p2psim.api.topology.views.wifi.phy.WifiMode;
import de.tud.kom.p2psim.api.topology.views.wifi.phy.WifiPhy;
import de.tud.kom.p2psim.api.topology.views.wifi.phy.WifiPhy.Standard_802_11;
import de.tud.kom.p2psim.api.topology.views.wifi.phy.WifiPhy.WifiPreamble;
import de.tud.kom.p2psim.impl.linklayer.DefaultLinkMessageEvent;
import de.tud.kom.p2psim.impl.linklayer.mac.AbstractMacLayer;
import de.tud.kom.p2psim.impl.linklayer.mac.wifi.AbstractRateManager.RateManagerTypes;
import de.tud.kom.p2psim.impl.linklayer.mac.wifi.DcfManager.WifiState;
import de.tud.kom.p2psim.impl.topology.views.wifi.WifiTopologyView;
import de.tud.kom.p2psim.impl.util.LiveMonitoring;
import de.tud.kom.p2psim.impl.util.LiveMonitoring.ProgressValue;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.core.MonitorComponent.AnalyzerNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.operation.AbstractOperation;
/**
* This class implements the IEEE 802.11 MAC for the adHoc case. This is only a
* simple implementation of the IEEE 802.11 standard, but has the same behavior. <br>
* It supports the sending of Unicast message with and without RTS- and
* CTS-Messages, plus the sending of messages as Broadcasts.<br>
* The sending of RTS-, CTS- and ACK-Messages will be only simulated. This mean,
* that we calculate the times, the energy consumption and as interferences, but
* we send no message to the other MAC. This has the benefit that we have a
* performance boost, but the drawback is, that this messages can not be
* dropped.<br>
* Additionally it handle no crypto or SSIDs. It can only exist one Network.
* Different channels will be additionally not handled.<br>
* Messages like Beacons are not available and will be not simulated.
* <p>
* The sending of the real data will be attended with the
* {@link WifiTopologyView}. This is needed to calculate the drop of a
* message.So it is important to add the RTS-,CTS-,ACK-Messages as interferences
* and the real data as a transfer. Hence, this class works only with the
* {@link WifiTopologyView}.
* <p>
* Additional the implementation works with a {@link DcfManager}, which will be
* manipulated from this class during the sending and receiving of messages. The
* DCF-Manager has the task to handle the state of the MAC and to calculate the
* BackOffTimerEnd-Time.<br>
* The BackOffTimer can be extended through other events. So we have a the
* {@link GetSendSlotOperation} to get a send slot. The send slot will be ready,
* if the BackOffTimer is 0. But through the extension of the BackOffTimer, is
* the endTime not really fix. So it is possible that the
* {@link GetSendSlotOperation} must be called multiple times. This can be a big
* drawback, because it produce a many events, which are doing nothing.
* <p>
* <p>
* This class inherit from {@link AbstractMacLayer}, but use few methods from
* them. The main reason for the not using of few methods is, that the handling
* of the drop is doing in the sender method, but this implementation needed it
* in the receiver.
* <p>
* <b>NOTE:</b> If after the configuration a parameter is changed, you should
* inform the underlay layer about the change.
*
* @author Christoph Muenker
* @version 1.0, 28.02.2013
*/
public class Ieee80211AdHocMac extends AbstractMacLayer {
protected static Logger log = SimLogger.getLogger(Ieee80211AdHocMac.class);
/*
* For Analyzing
*/
public static long _wifiBroadcastSent, _wifiUnicastSent, _wifiUnicastRcvd,
_wifiBroadcastRcvd, _wifiUnicastDropped, _wifiResent,
_wifiBroadcastDropped, _wifiBroadcastDataSent,
_wifiBroadcastDataRcvd = 0;
public static boolean _analyzersInitialized = false;
/**
* Size of Frame Check Sequence in Bytes
*/
protected static int FCS = 4;
/**
* CTS message size in Bytes
*/
protected static int CTS_MSG_SIZE = 10 + FCS; // macHeader + FCS
/**
* RTS message size in Bytes
*/
protected static int RTS_MSG_SIZE = 16 + FCS; // macHeader + FCS
/**
* ACK message size in Bytes
*/
protected static int ACK_MSG_SIZE = 10 + FCS; // macHeader + FCS
/**
* Maximal Frame size of IEEE 802.11 packet, as specified in
* "802.11 Wireless Networks - Definitive Guide" from Matthew Gast
* (p.47,53).
*/
protected static long MAX_FRAME_SIZE = 2304;
/**
* The {@link WifiTopologyView}, which will be informed about interferences.
*/
private WifiTopologyView topoView;
/**
* Stores the corresponding IEEE802.11 standard, which is used by this MAC
* to communicate.
*/
private Standard_802_11 standard_802_11;
/**
* Counts the retries of the ({@link Ieee80211AdHocMac#toSend}) actually
* message.
*/
private int retryCounter = 0;
private DcfManager dcfManager;
private AbstractRateManager rateManager;
/**
* The txPower in watt
*/
private double txPowerW;
/**
* The txPower in dBm
*/
private double txPowerDbm;
private Random rand = Randoms.getRandom(Ieee80211AdHocMac.class);
/**
* The minimum size of the message (with MAC-Header and FCS), at should be
* used RTS/CTS for the unicast-message.
*/
protected long rtsCtsThreshold;
/**
* The channel number which is used.
*/
private int channel;
private final static IEEE80211DummyACKMessage MSG_DUMMY_ACK = new IEEE80211DummyACKMessage();
private final static IEEE80211DummyCTSMessage MSG_DUMMY_CTS = new IEEE80211DummyCTSMessage();
private final static IEEE80211DummyRTSMessage MSG_DUMMY_RTS = new IEEE80211DummyRTSMessage();
/**
* Contains the last acknowledged transmissions. Needed for Broadcasts, to
* identify multiple calls.
* <p>
* The maximal size of this cache is 10.
*/
private Map<MacEventInformation, Void> ackCache = new LinkedHashMap<MacEventInformation, Void>(
100, 0.75f, true) {
private final static int MAX_SIZE = 10;
protected boolean removeEldestEntry(
Map.Entry<MacEventInformation, Void> eldest) {
return this.size() > MAX_SIZE;
}
};
// don't change this. WIFI_PREAMBLE_SHORT is not practicable for long
// ranges.
private WifiPreamble preamble = WifiPreamble.WIFI_PREAMBLE_LONG;
/**
* The type of the Rate Manager.
*/
private RateManagerTypes rateManagerType;
/**
* The message, which is actually transfered.
*/
private QueueEntry toSend = null;
/**
* The actually operation, which tries to get a send slot. It is the timer
* for the BackoffTimer, but because the backOffTimer can be extended, the
* end time is not fix! So this Operation tries to get a slot to send.
* <p>
* If no operation is running, this field should be <code>null</code>. So we
* know, that a new operation can be started.
*/
protected GetSendSlotOperation op = null;
/**
* Creates the Ieee802.11 AdHoc MAC. Sets the given values. The class is not
* ready for using. After this should be called the initialize method, to
* create the missing components.
*
*
*/
public Ieee80211AdHocMac(SimHost host, MacAddress ownMacAddress,
PhyType phy, Standard_802_11 standard, int maxQueueLength,
long maxTimeInQueue, int maxRetransmissions, BandwidthImpl bandwidth,
RateManagerTypes rateManagerType) {
super(host, ownMacAddress, phy, maxQueueLength, maxTimeInQueue,
maxRetransmissions, bandwidth);
this.dcfManager = new DcfManager(this, standard);
this.standard_802_11 = standard;
this.rateManagerType = rateManagerType;
}
@Override
public void initialize() throws ConfigurationException {
super.initialize();
// initialize the LiveMonitoring.
if (!_analyzersInitialized) {
LiveMonitoring
.addProgressValueIfNotThere(new WifiUnicastProgress());
LiveMonitoring
.addProgressValueIfNotThere(new WifiBroadcastProgress());
_analyzersInitialized = true;
}
// TODO: check for WifiTopologyView, otherwise throw
// ConfigurationExcpetion
topoView = (WifiTopologyView) getTopologyView();
this.rateManager = AbstractRateManager.createRateManager(this,
rateManagerType, standard_802_11);
if (this.rateManager == null) {
throw new ConfigurationException("The RateManager is not set!");
}
// TODO check configuration...
// is the size of the netlayer acceptable?
}
@Override
protected void handleNewQueueEntry() {
if (this.toSend == null) {
sendNextMessage();
}
}
/**
* Take the first element from the Queue and starts the sending procedure.
* The message, which is to send, will be stored in
* {@link Ieee80211AdHocMac#toSend}. Additionally the retryCounter will be
* reseted to 0.
*/
protected void sendNextMessage() {
toSend = null;
retryCounter = 0;
if (getQueueSize() > 0) {
toSend = getQueueHead();
sendMessage();
}
}
/**
* Start the procedure of the sending of the message in
* {@link Ieee80211MacMessage#toSend}.<br>
* The message will be insert in a new MAC-Message and then added to an
* event info. If a link is not available, the message will be aborted,
* otherwise it will be tried to get a SendSlot to transfer the message.
*/
protected void sendMessage() {
if (toSend != null) {
/*
* Here, we must scrape out the message from the netlayer, because
* the surrounding linklayer message does not contain all the
* information, which are required for the IEEE80211MacMessage.
*/
LinkLayerMessage dlm = toSend.getMessage();
Ieee80211MacMessage msg = new Ieee80211MacMessage(dlm.getSender(),
dlm.getReceiver(), dlm.getPayload());
WifiMacEventInformation eventInfo = new WifiMacEventInformation(
msg, this.getMacAddress(), toSend.getReceiver(),
Time.getCurrentTime() - toSend.getTimeEntered());
if (msg.getSize() >= MAX_FRAME_SIZE) {
log.warn("Try to send a Frame, which is to big ("
+ msg.getSize()
+ "Byte)! Please check the fragementation size in the Net-Layer. The message will be still send, with the side-effects (for example, higher Bandwidth)");
}
if (eventInfo.isBroadcast()) {
tryToGetSendSlot(eventInfo);
} else {
// check for link connected
Link link = topoView.getLinkBetween(eventInfo.getSender(),
eventInfo.getReceiver());
if (link.isConnected()) {
tryToGetSendSlot(eventInfo);
} else {
messageDropped(DropReason.NO_LINK, msg);
sendNextMessage();
}
}
} else {
log.error("sendMessage was called, but no Message exists");
}
}
/**
* Tries to get a send slot. For that, it starts the BackoffTimer in the
* {@link DcfManager} and then must be scheduled to the end of the
* BackoffTimer.
*
* @param eventInfo
* The {@link MacEventInformation} with the containing
* information to the message.
*/
private void tryToGetSendSlot(MacEventInformation eventInfo) {
dcfManager.resetBackoffTimer();
dcfManager.startBackoffTimer();
long tryTime = dcfManager.getBackoffTimeEnd();
if (op == null) {
op = new GetSendSlotOperation(this, eventInfo);
op.scheduleWithDelay(tryTime - Time.getCurrentTime());
} else {
// easy policy to check an failure. If two or more operation
// running, then is op not null!
log.fatal("Two or more GetSendSlotOperation are running! This should be not happen, because a station cannot send two or more Frames on the same time!");
}
}
/**
* Executes the sending of the message as a unicast message with RTS/CTS as
* prequel. The RTS and CTS Message will be not send as a real message
* through the simulator. The RTS and CTS Message will be only simulated as
* interferences. It has be shown, that this is important to simulate this
* as interferences. Otherwise is the drop rate of other messages low.<br>
* Additionally, the DCF-Manager of the other MACs in the neighborhood will
* be manipulated.<br>
* The energy component will be informed about the sending and receiving.
* <p>
* If the link is not more connected, then will be dropped the message and a
* new Message will be started. If the receiver MAC is not in
* {@link WifiState#IDLE}, then we simulate only the RTS-Message.
*
* @param eventInfo
* The message which is to transfer.
*/
protected void mySendUnicast(WifiMacEventInformation eventInfo) {
// Check online state over all possibilities to ensure that the device
// is really online
assert isOnline();
Link link = topoView.getLinkBetween(eventInfo.getSender(),
eventInfo.getReceiver());
Ieee80211AdHocMac recMac = (Ieee80211AdHocMac) topoView
.getMac(eventInfo.getReceiver());
// Determine if there is a link for a unicast transmission between the
// sender and the receiver
if (link.isConnected()) {
long current = Time.getCurrentTime();
WifiState recState = recMac.getWifiState();
// Check the state of the receiver and - depending on its state -
// start the data transmission or only the transmission of RTS and
// CTS
if (recState == WifiState.IDLE && recMac.isOnline()) {
// determine WifiMode for RTS, CTS, ACK
WifiMode rtsMode = rateManager.getRtsMode(recMac
.getMacAddress());
WifiMode ctsMode = rateManager.getCtsMode(rtsMode);
rateManager.reportRtsOk(recMac.getMacAddress(), rateManager
.calculateActuallySNR(recMac.getPosition(),
this.getPosition(), ctsMode, txPowerDbm),
ctsMode);
WifiMode dataMode = rateManager.getUnicastDataMode(recMac
.getMacAddress());
WifiMode ackMode = rateManager.getAckMode(dataMode);
long rtsDuration = WifiPhy.calculateTxDuration(RTS_MSG_SIZE,
rtsMode, preamble);
long ctsDuration = WifiPhy.calculateTxDuration(CTS_MSG_SIZE,
ctsMode, preamble);
long dataDuration = WifiPhy.calculateTxDuration((int) eventInfo
.getMessage().getSize(), dataMode, preamble);
long ackDuration = WifiPhy.calculateTxDuration(ACK_MSG_SIZE,
ackMode, preamble);
eventInfo.setTransmissionDuration(dataDuration);
eventInfo.setAckDuration(ackDuration);
eventInfo.setAckMode(ackMode);
eventInfo.setMode(dataMode);
long startRts = current;
long startCts = startRts + rtsDuration + getSifs();
long startData = startCts + ctsDuration + getSifs();
long duration = rtsDuration + getSifs() + ctsDuration
+ getSifs() + dataDuration + getSifs() + ackDuration;
// update DCF-Managers
this.getDcfManager().notifyTxNow(duration);
recMac.getDcfManager().notifyRxNow(duration);
// Sender Neighbors only with CTS Timeout. If no CTS is
// received, then will be stopped the NAV-Timer.
// This is the update for the received RTS-Message
updateNeighborsNavTimer(
getTopologyView().getNeighbors(eventInfo.getSender()),
getDcfManager().getCtsTimeout());
// this the CTS-NAV update.
updateNeighborsNavTimer(
getTopologyView().getNeighbors(eventInfo.getReceiver()),
duration);
// Inform InterferenceHelper about Data Transfer
topoView.addTransfer(startData, startData + dataDuration,
this.getPosition(), this.getTxPowerDdm(),
eventInfo.getMessage(), dataMode, preamble,
this.getHost(), getMacAddress());
topoView.addInterference(startRts, current + rtsDuration,
this.getPosition(), this.getTxPowerDdm(), rtsMode,
this.getMacAddress());
topoView.addInterference(startCts, startCts + ctsDuration,
recMac.getPosition(), recMac.getTxPowerDdm(), ctsMode,
recMac.getMacAddress());
/*
* This case represents a complete transmission of data
* including (i) the sending of a RTS, (ii) the receiving of a
* CTS, (iii) the sending and receiving of CTS, (iv) the
* transmission of data, and (v) the receiving of the ack.
*/
// (i) send the RTS
this.getEnergyComponent().send(rtsDuration, MSG_DUMMY_RTS,
false);
_linkMsgEvent(MSG_DUMMY_RTS, getHost(), Reason.SEND);
// (ii) Iterate over all listening devices in the communication
// range, which receive the RTS
for (MacAddress address : getTopologyView().getNeighbors(
eventInfo.getSender())) {
Ieee80211AdHocMac rtsRecMac = (Ieee80211AdHocMac) getTopologyView()
.getMac(address);
if (rtsRecMac.isOnline()
&& (rtsRecMac.getWifiState() == WifiState.IDLE)) {
rtsRecMac.getEnergyComponent().receive(rtsDuration,
MSG_DUMMY_RTS, false, true);
_linkMsgEvent(MSG_DUMMY_RTS, rtsRecMac.getHost(),
Reason.RECEIVE);
}
}
// (iiia) The intended receiver sends the CTS
recMac.getEnergyComponent().send(ctsDuration, MSG_DUMMY_CTS,
false);
_linkMsgEvent(MSG_DUMMY_CTS, recMac.getHost(), Reason.SEND);
// (iiib) The sender receives the CTS
this.getEnergyComponent().receive(ctsDuration, MSG_DUMMY_CTS,
false, true);
_linkMsgEvent(MSG_DUMMY_CTS, getHost(), Reason.RECEIVE);
// (iv) The transmission of the actual data
this.getEnergyComponent().send(dataDuration,
eventInfo.getMessage(), false);
// schedule receiving of the message
scheduleReceive(recMac, eventInfo, (startData + dataDuration)
- current, false);
_linkMsgEvent(eventInfo.getMessage(), getHost(),
Reason.SEND);
currentBandwidth.outgoingTransmission(eventInfo.getMessage()
.getSize());
_wifiUnicastSent++;
} else {
// Start the NAV-Timer. If no CTS is received, then will be
// stopped after CTS-Timeout.
updateNeighborsNavTimer(
getTopologyView().getNeighbors(eventInfo.getSender()),
getDcfManager().getCtsTimeout());
rateManager.reportRtsFailed(recMac.getMacAddress());
/*
* Energy for (i) sending and (ii) receiving RTS
*/
// (i) Send the RTS message
WifiMode rtsMode = rateManager.getRtsMode(recMac
.getMacAddress());
long rtsDuration = WifiPhy.calculateTxDuration(RTS_MSG_SIZE,
rtsMode, preamble);
this.getEnergyComponent().send(rtsDuration, MSG_DUMMY_RTS,
false);
_linkMsgEvent(MSG_DUMMY_RTS, getHost(), Reason.SEND);
// (ii) Iterate over all listening devices in the communication
// range, which receive the RTS message
for (MacAddress address : getTopologyView().getNeighbors(
eventInfo.getSender())) {
Ieee80211AdHocMac rtsRecMac = (Ieee80211AdHocMac) getTopologyView()
.getMac(address);
if (rtsRecMac.isOnline()
&& (rtsRecMac.getWifiState() == WifiState.IDLE)) {
rtsRecMac.getEnergyComponent().receive(rtsDuration,
MSG_DUMMY_RTS, false, true);
_linkMsgEvent(MSG_DUMMY_RTS, rtsRecMac.getHost(),
Reason.RECEIVE);
}
}
topoView.addInterference(current, current + rtsDuration,
this.getPosition(), this.getTxPowerDdm(), rtsMode,
this.getMacAddress());
// try again after CTS Timeout
dcfManager.notifiyCTSTimeout();
unsuccessfulTransmitted(eventInfo);
}
} else {
messageDropped(DropReason.NO_LINK, eventInfo.getMessage());
sendNextMessage();
}
}
/**
* Updates for all neighbors the NAV-Timer.
*
* @param neighbors
* A list of MacAddresses, which should be updated.
* @param duration
* The duration of the NAV.
*/
private void updateNeighborsNavTimer(List<MacAddress> neighbors,
long duration) {
for (MacAddress address : neighbors) {
// If in Idle, NAV or CCA, it is possible to update the
// NAV Timer.
Ieee80211AdHocMac navMac = (Ieee80211AdHocMac) getTopologyView()
.getMac(address);
WifiState navMacState = navMac.getWifiState();
if (navMacState != WifiState.TX && navMacState != WifiState.RX) {
navMac.getDcfManager().notifyNavNow(duration);
}
}
}
/**
*
* Executes the sending of the message as a unicast message without RTS/CTS
* as prequel. Additionally, the DCF-Manager of the other MACs in the
* neighborhood will be manipulated.<br>
* The energy component will be informed about the sending and receiving.
* <p>
* If the link is not more connected, then will be dropped the message and a
* new Message will be started.
*
* @param eventInfo
* The message, which should be send.
*/
protected void mySendUnicastWithoutRtsCts(WifiMacEventInformation eventInfo) {
// Check online state over all possibilities to ensure that the device
// is really online
assert isOnline();
Link link = topoView.getLinkBetween(eventInfo.getSender(),
eventInfo.getReceiver());
Ieee80211AdHocMac recMac = (Ieee80211AdHocMac) topoView
.getMac(eventInfo.getReceiver());
if (link.isConnected()) {
WifiState recMacState = recMac.getWifiState();
WifiMode dataMode = rateManager.getUnicastDataMode(recMac
.getMacAddress());
WifiMode ackMode = rateManager.getAckMode(dataMode);
long current = Time.getCurrentTime();
long dataDuration = WifiPhy.calculateTxDuration((int) eventInfo
.getMessage().getSize(), dataMode, preamble);
long ackDuration = WifiPhy.calculateTxDuration(ACK_MSG_SIZE,
ackMode, preamble);
eventInfo.setTransmissionDuration(dataDuration);
eventInfo.setAckDuration(ackDuration);
eventInfo.setAckMode(ackMode);
eventInfo.setMode(dataMode);
long startData = current;
long duration = dataDuration + getSifs() + ackDuration;
// Inform InterferenceHelper about Data Transfer
topoView.addTransfer(startData, startData + dataDuration,
this.getPosition(), getTxPowerDdm(),
eventInfo.getMessage(), dataMode, preamble, this.getHost(),
getMacAddress());
// Energy for sending Data.
this.getEnergyComponent().send(dataDuration,
eventInfo.getMessage(), false);
_linkMsgEvent(eventInfo.getMessage(), getHost(), Reason.SEND);
currentBandwidth.outgoingTransmission(eventInfo.getMessage()
.getSize());
this.getDcfManager().notifyTxNow(duration);
updateNeighborsNavTimer(
getTopologyView().getNeighbors(eventInfo.getSender()),
duration);
// schedule receive
if (recMacState != WifiState.TX && recMacState != WifiState.RX && recMac.isOnline()) {
recMac.getDcfManager().notifyRxNow(duration);
scheduleReceive(recMac, eventInfo, (startData + dataDuration)
- current, false);
} else {
// schedule with drop, because receiver is not listen.
scheduleReceive(recMac, eventInfo, (startData + dataDuration)
- current, true);
}
_wifiUnicastSent++;
} else {
messageDropped(DropReason.NO_LINK, eventInfo.getMessage());
sendNextMessage();
}
}
/**
* Gets a copy of the real position of this host.
*
* @return The position of this host.
*/
private Position getPosition() {
/*
* FIXME this leads to serious performance degradations. Do we REALLY
* need a copy?
*/
return this.getHost().getTopologyComponent().getRealPosition(); // .clone();
}
/**
* Gets the SIFS (Short Interframe Spacing) of the {@link DcfManager} back.
*
* @return The SIFS of the {@link DcfManager}.
*/
private long getSifs() {
return dcfManager.getSifs();
}
/**
* Executes the sending of the message as a broadcast message.<br>
* All neighbors will be informed about the receiving of this message.
* Neighbors, which are in {@link WifiState#TX} or {@link WifiState#RX}
* receive the message as a drop (The neighbor will have a higher SNR during
* the sending of this broadcast).Additionally, the DCF-Manager of the other
* MACs in the neighborhood will be manipulated.<br>
* The energy component will be informed about the sending and receiving.
*
* <p>
* After this sending, this MAC will be informed about a successful
* transmit, because a new sending procedure with a new message from the
* queue must be started.
*
* @param eventInfo
* The message which should be send as a broadcast.
*/
protected void mySendBroadcast(WifiMacEventInformation eventInfo) {
// Check online state over all possibilities to ensure that the device
// is really online
assert isOnline();
WifiMode dataMode = rateManager.getBroadcastDataMode();
long duration = WifiPhy.calculateTxDuration((int) eventInfo
.getMessage().getSize(), dataMode, preamble);
eventInfo.setTransmissionDuration(duration);
eventInfo.setAckDuration(0);
eventInfo.setAckMode(null);
eventInfo.setMode(dataMode);
long startData = Time.getCurrentTime();
long endData = startData + duration;
// update DCF-Managers
this.getDcfManager().notifyTxNow(duration);
for (MacAddress address : getTopologyView().getNeighbors(
eventInfo.getSender())) {
Ieee80211AdHocMac recMac = (Ieee80211AdHocMac) getTopologyView()
.getMac(address);
// If it is not in RX, TX and online then it is possible to receive
// this message. In case NAV it is possible that exist more
// interferences and the Messages will be dropped.
WifiState recMacState = recMac.getWifiState();
if (recMacState != WifiState.TX && recMacState != WifiState.RX && recMac.isOnline()) {
recMac.getDcfManager().notifyRxNow(duration);
// schedule receive
scheduleReceive(recMac, eventInfo, duration, false);
} else {
// schedule with drop, because receiver is not listen.
scheduleReceive(recMac, eventInfo, duration, true);
}
}
// Inform InterferenceHelper about Data Transfer
topoView.addTransfer(startData, endData, this.getPosition(),
getTxPowerDdm(), eventInfo.getMessage(), dataMode, preamble,
this.getHost(), getMacAddress());
getEnergyComponent().send(duration, eventInfo.getMessage(), true);
this.successfulTransmitted(eventInfo);
_linkMsgEvent(eventInfo.getMessage(), getHost(),
Reason.SEND);
currentBandwidth.outgoingTransmission(eventInfo.getMessage().getSize());
_wifiBroadcastSent++;
_wifiBroadcastDataSent += eventInfo.getMessage().getSize();
}
/**
* Gets the DCF Manager.
*
* @return The {@link DcfManager} of this MAC.
*/
public DcfManager getDcfManager() {
return dcfManager;
}
@Override
protected void handleReceivedMessage(MacEventInformation eventInfo) {
// Check online state over all possibilities to ensure that the device
// is really online
assert isOnline();
Message msg = eventInfo.getMessage();
WifiMacEventInformation wifiEventInfo = (WifiMacEventInformation) eventInfo;
Ieee80211AdHocMac senderMac = (Ieee80211AdHocMac) topoView
.getMac(eventInfo.getSender());
boolean successful;
if (checkCollision()) {
// we send and receive to the same time. But we cannot receive the
// message, because the tx-power is to strong and will be destroy
// the rx-signal.
// So we know, that the receiving is unsuccessful!
successful = false;
this.dcfManager.increaseCw();
// if the sender is in collision, then will be dropped the
// receiving, but the sending is successful. He has no chance to
// detect the rx-signal.
} else {
double per = topoView.calculatePer(msg, getPosition());
successful = rand.nextDouble() > per;
// Energy for receive
this.getEnergyComponent().receive(
wifiEventInfo.getTransmissionDuration(), msg,
eventInfo.isBroadcast(), true);
}
if (successful) {
notifyLinkLayer(new DefaultLinkMessageEvent(
(LinkLayerMessage) eventInfo.getMessage(),
getPhyType(), eventInfo.getSender(),
eventInfo.isBroadcast()));
senderMac.successfulTransmitted(eventInfo);
// inform rateManager about the snr of the received packet
double snr = rateManager.calculateActuallySNR(
senderMac.getPosition(), this.getPosition(),
wifiEventInfo.getMode(), txPowerDbm);
rateManager.reportRxOk(senderMac.getMacAddress(), snr,
wifiEventInfo.getMode());
// Energy for Ack and add the ACK message as interference.
if (!eventInfo.isBroadcast()) {
long current = Time.getCurrentTime();
long ackDuration = wifiEventInfo.getAckDuration();
long startInterference = current + getSifs();
topoView.addInterference(startInterference, startInterference
+ ackDuration, this.getPosition(),
this.getTxPowerDdm(), wifiEventInfo.getAckMode(),
this.getMacAddress());
// Simulate the sending of an ACK-message
this.getEnergyComponent().send(ackDuration, MSG_DUMMY_ACK,
false);
_linkMsgEvent(MSG_DUMMY_ACK, getHost(), Reason.SEND);
// Simulate the reception of an ACK-message
if (senderMac.isOnline()
&& (senderMac.getWifiState() == WifiState.IDLE)) {
senderMac.getEnergyComponent().receive(ackDuration,
MSG_DUMMY_ACK, false, true);
_linkMsgEvent(MSG_DUMMY_ACK, senderMac.getHost(),
Reason.RECEIVE);
}
}
} else {
// inform dcfManager for drop
this.dcfManager.notifyRxDrop();
senderMac.unsuccessfulTransmitted(eventInfo);
}
}
/**
* Checks the start time of RX and TX-States of the {@link DcfManager}. If
* both times the same, then we know that we have a collision.<br>
* This works only, if no propagation delay is used!
*
* @return <code>true</code> if the RX and TX StartTime is the same,
* otherwise <code>false</code>.
*/
private boolean checkCollision() {
long txStartTime = this.getDcfManager().getTxStartTime();
long rxStartTime = this.getDcfManager().getRxStartTime();
return txStartTime == rxStartTime;
}
@Override
protected void handleEvent(Object data, int type) {
if ((type == MESSAGE_RECEIVED && !isOnline())
|| type == MESSAGE_DROPPED) {
if (data instanceof MacEventInformation) {
MacEventInformation eventInfo = (MacEventInformation) data;
Ieee80211AdHocMac senderMac = (Ieee80211AdHocMac) topoView
.getMac(eventInfo.getSender());
senderMac.unsuccessfulTransmitted(eventInfo);
}
}
}
/**
* If a message is successful transmitted, then should be called this method
* of the sender MAC. In the broader sense, it is for the handling of the
* ACK-Message<br>
* The Contention Window of the DCF-Manager will be reseted. The next
* message will be triggered and the rate manager will be informed about the
* correct receiving of the message.
*
* @param eventInfo
* The message which is successfully transmitted with all meta
* information.
*/
protected void successfulTransmitted(MacEventInformation eventInfo) {
// for progress display
if (eventInfo.isBroadcast() && ackCache.containsKey(eventInfo)) {
_wifiBroadcastRcvd++;
_wifiBroadcastDataRcvd += eventInfo.getMessage().getSize();
}
if (!eventInfo.isBroadcast() && !ackCache.containsKey(eventInfo)) {
_wifiUnicastRcvd++;
}
// reset the CW, because the message was successful transmitted
this.dcfManager.resetCw();
// this check is used to handle broadcasts, because it can called
// several times...
if (!ackCache.containsKey(eventInfo)) {
sendNextMessage();
reportDataOk(eventInfo);
ackCache.put(eventInfo, null);
}
}
/**
* Inform the RateManager about the successful transmission of the data.<br>
* It will be only informed, if the message was not a broadcast.
*
* @param eventInfo
* The message which is successfully transmitted with all meta
* information.
*/
private void reportDataOk(MacEventInformation eventInfo) {
if (!eventInfo.isBroadcast()) {
WifiMacEventInformation eInfo = (WifiMacEventInformation) eventInfo;
// startPosition is from receiver (because ack come from this!)
Position startPosition = ((Ieee80211AdHocMac) topoView
.getMac(eventInfo.getReceiver())).getPosition();
Position targetPosition = this.getPosition();
double ackSnr = rateManager.calculateActuallySNR(startPosition,
targetPosition, eInfo.getAckMode(), txPowerDbm);
rateManager.reportDataOk(eventInfo.getReceiver(), ackSnr,
eInfo.getAckMode());
}
}
/**
* If a message is unsuccessful transmitted, then should be called this
* method of the sender MAC. In the broader sense, it is for the handling
* for the missing ACK-Message<br>
* The Contention Window of the DCF-Manager will be increased. The
* retryCounter will be increased and if the maximal retransmission is not
* reached, it will be start to send the same message again. Additionally
* the rate manager will be informed about the failing of the data
* transmission.
*
* @param eventInfo
* The message which is unsuccessfully transmitted with all meta
* information.
*/
protected void unsuccessfulTransmitted(MacEventInformation eventInfo) {
if (!ackCache.containsKey(eventInfo)) {
if (!eventInfo.isBroadcast()) {
this.retryCounter++;
this.dcfManager.increaseCw();
if (retryCounter <= getMaxRetransmissions()) {
this.sendMessage();
rateManager.reportDataFailed(eventInfo.getReceiver());
_wifiResent++;
} else {
this.messageDropped(DropReason.LINK_DROP,
eventInfo.getMessage());
this.sendNextMessage();
rateManager.reportFinalDataFailed(eventInfo.getReceiver());
_wifiUnicastDropped++;
}
} else {
// for broadcasts, to start a new send message.
// should be never called, because mySendBroadcast call
// successfulTrasmitted.
this.sendNextMessage();
}
// to handle broadcasts, because multiple calls of successful or
// unsuccessful is possible
ackCache.put(eventInfo, null);
}
if (eventInfo.isBroadcast()) {
_wifiBroadcastDropped++;
}
}
/**
* Gets the actually {@link WifiState} of this MAC.
*
* @return Returns the actually {@link WifiState} from the
* {@link DcfManager}.
*/
public WifiState getWifiState() {
return this.dcfManager.getWifiState();
}
/**
* Gets the TX Power in watt.
*
* @return The tx Power in watt.
*/
public double getTxPowerW() {
return txPowerW;
}
/**
* Gets the TX Power in dBm.
*
* @return The tx Power in dBm.
*/
public double getTxPowerDdm() {
return txPowerDbm;
}
/**
* Sets the TX Power in dBm and in watt.
*
* @param txPowerDbm
* The TX power in dBm.
*/
public void setTxPowerDbm(double txPowerDbm) {
this.txPowerDbm = txPowerDbm;
this.txPowerW = PropagationLossModel.dbmToW(txPowerDbm);
}
/**
* Sets the RTS/CTS Threshold.
*
* @param rtsCtsThreshold
* The new RTS/CTS Threshold.
*/
public void setRtsCtsThreshold(long rtsCtsThreshold) {
this.rtsCtsThreshold = rtsCtsThreshold;
}
/**
* Inform the DCF-Manager about a higher noise on the medium or rather, the
* channel is not clear.
*
* @param duration
* The duration of this noise.
*/
public void notifyCarrierSense(long duration) {
this.dcfManager.notifyCcaNow(duration);
}
/**
* Gets the unerlaying {@link WifiTopologyView}.
*
* @return The {@link WifiTopologyView}.
*/
public WifiTopologyView getWifiTopologyView() {
return topoView;
}
/**
* The used {@link Standard_802_11} from this MAC.
*
*/
public Standard_802_11 getStandard_802_11() {
return standard_802_11;
}
/**
* Sets the channel which should be used. This should be called before the
* MAC is added to the {@link TopologyView}. Changes after this will be
* ignored.
*
* @param channel
* The channel number
*/
public void setChannel(int channel) {
this.channel = channel;
}
/**
* Gets the used channel.
*
* @return The used channelnumber.
*/
public int getChannel() {
return this.channel;
}
/**
* Gets the used frequency in Hz. It is dependent of the channel.
*
* @return The used frequency.
*/
public long getFrequency() {
long basicFrequency = standard_802_11.getBasicFrequency();
long channelBandwidth = 5000000l; // 5MHz;
long frequency = basicFrequency + this.channel * channelBandwidth;
return frequency;
}
/**
* This Operation tries to get a Send Slot. It is started, after the
* BackoffTimer is started. If the event for the execution is fired, then
* will be checked if the BackOffTimer is 0. If it 0, then will be started
* the transfer of the message. If it is not 0, then will be created a new
* SendSlotOperation and new scheduled to the time of BackOffTimerEnd.
*
* @author Christoph Muenker
* @version 1.0, 28.02.2013
*/
private class GetSendSlotOperation extends
AbstractOperation<Ieee80211AdHocMac, Void> {
private MacEventInformation eventInfo;
protected GetSendSlotOperation(Ieee80211AdHocMac mac,
MacEventInformation eventInfo) {
super(mac);
this.eventInfo = eventInfo;
}
@Override
protected void execute() {
getComponent().op = null;
if (!getComponent().isOnline()) {
log.warn(Time.getFormattedTime()
+ " node "
+ eventInfo.getSender()
+ " wanted to get a slot to send but was already offline.");
return;
}
boolean ignoreWifiState = getComponent().getDcfManager()
.isIgnoreWifiState();
long backOffTimeEnd = getComponent().getDcfManager()
.getBackoffTimeEnd();
long current = Time.getCurrentTime();
if (backOffTimeEnd == current) {
// Theory: MAC must be in an Idle State, if the backOffTimeEnd
// == current!
// The flag ignoreWifiState is useful to create collisions,
// because the backOffTime is 0 for multiple MACs, but the
// wifiState was changed from an other MAC.
if (ignoreWifiState
|| getComponent().getWifiState() == WifiState.IDLE) {
WifiMacEventInformation wifiEventInfo = (WifiMacEventInformation) eventInfo;
if (eventInfo.isBroadcast()) {
getComponent().mySendBroadcast(wifiEventInfo);
} else {
if ((eventInfo.getMessage().getSize() + getComponent().FCS) < getComponent().rtsCtsThreshold) {
getComponent().mySendUnicastWithoutRtsCts(
wifiEventInfo);
} else {
getComponent().mySendUnicast(wifiEventInfo);
}
}
} else {
log.fatal("Why is the Mac not in an Idle State? "
+ getComponent().getWifiState()
+ " "
+ (getComponent().getDcfManager()
.getTimeToIdleState()));
getComponent().sendMessage();
}
} else {
if (backOffTimeEnd < current) {
log.fatal("How can be the backOffTimeEnd smaller then the current time? ");
} else {
op = new GetSendSlotOperation(getComponent(), eventInfo);
op.scheduleWithDelay(backOffTimeEnd
- Time.getCurrentTime());
}
}
this.operationFinished(true);
}
@Override
public Void getResult() {
return null;
}
}
/**
* The {@link ProgressValue} for the sending of unicast messages. It shows
* the number of sent, received, dropped and resent messages.
*
* @author Christoph Muenker
* @version 1.0, 28.02.2013
*/
public class WifiUnicastProgress implements ProgressValue {
@Override
public String getName() {
return "WiFi Unicast (Sent/Rcvd/Dropped/Resent)";
}
@Override
public String getValue() {
return String.format("WiFi Unicast (%10d/%10d/%10d/%10d)",
_wifiUnicastSent, _wifiUnicastRcvd, _wifiUnicastDropped,
_wifiResent);
}
}
/**
* The {@link ProgressValue} for the sending of broadcasts messages. It
* shows the number of sent, received and dropped messages. Additionally it
* shows the traffic, which is generated of successfully transmitted
* broadcasts.
*
* @author Christoph Muenker
* @version 1.0, 28.02.2013
*/
public class WifiBroadcastProgress implements ProgressValue {
@Override
public String getName() {
return "WiFi Broadcast (Sent/Rcvd/Dropped); Traffic (Sent/Rcvd)";
}
@Override
public String getValue() {
return String.format(
"WiFi Broadcast (%10d/%10d/%10d); Traffic (%5s/%5s)",
_wifiBroadcastSent, _wifiBroadcastRcvd,
_wifiBroadcastDropped,
readableFileSize(_wifiBroadcastDataSent),
readableFileSize(_wifiBroadcastDataRcvd));
}
}
/**
* Helper to create readable file sizes up to TB.
*
* @param size
* The size in Byte.
* @return A human readable String for the size.
*/
public static String readableFileSize(long size) {
if (size <= 0)
return "0";
final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size
/ Math.pow(1024, digitGroups))
+ " " + units[digitGroups];
}
private static boolean _linkAnalyzerInitialized = false;
private static LinklayerAnalyzer _linkAnalyzer = null;
protected static void _linkMsgEvent(LinkLayerMessage msg, SimHost host,
Reason reason) {
if (!_linkAnalyzerInitialized) {
try {
_linkAnalyzer = Monitor.get(LinklayerAnalyzer.class);
} catch (AnalyzerNotAvailableException e) {
_linkAnalyzer = null;
}
_linkAnalyzerInitialized = true;
}
if (_linkAnalyzerInitialized && _linkAnalyzer != null) {
_linkAnalyzer.linkMsgEvent(msg, host, reason);
}
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.linklayer.mac.wifi;
import de.tud.kom.p2psim.api.linklayer.LinkLayerMessage;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tudarmstadt.maki.simonstrator.api.Message;
/**
* This is a Ieee80211 MAC Message, which contains the Message from the upper
* layer and adds the size of the headers to this message. The fields and their
* sizes are taken from "802.11 Wireless Networks - Definitive Guide" from
* Matthew Gast (p.47,53). In total, the header of the message has a size of 34
* bytes, while the data can be up to 2312 bytes. However
* "802.11 can transmit frames with a maximum payload of 2304 bytes" from higher
* levels.
*
* @author Christoph Muenker
* @version 1.0, 22.02.2013
*/
public class Ieee80211MacMessage implements LinkLayerMessage {
private static final long FRAME_CONTROL = 2;
private static final long DURATION_ID = 2;
private static final long ADDR1 = 6;
private static final long ADDR2 = 6;
private static final long ADDR3 = 6;
private static final long SEQUENCE_CONTROL = 2;
private static final long ADDR4 = 6;
private static final long FCS = 4;
/**
* Specifies the overall size of the header of the
* {@link Ieee80211MacMessage}, which is 34 bytes.
*/
private static final long HEADER_SIZE = FRAME_CONTROL + DURATION_ID + ADDR1
+ ADDR2 + ADDR3 + SEQUENCE_CONTROL + ADDR4 + FCS;
private Message payload;
private MacAddress sender;
private MacAddress receiver;
public Ieee80211MacMessage(MacAddress sender, MacAddress receiver,
Message msg) {
this.sender = sender;
this.receiver = receiver;
this.payload = msg;
}
@Override
public long getSize() {
return payload.getSize() + HEADER_SIZE;
}
@Override
public Message getPayload() {
return payload;
}
@Override
public MacAddress getReceiver() {
return receiver;
}
@Override
public MacAddress getSender() {
return sender;
}
@Override
public String toString() {
return "IEEE80211LinkLayerMessage from " + sender.toString() + " to "
+ receiver.toString() + ", carrying " + payload.toString();
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.linklayer.mac.wifi;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tud.kom.p2psim.api.topology.views.wifi.phy.WifiMode;
import de.tud.kom.p2psim.impl.linklayer.mac.DefaultMacEventInformation;
/**
* This class extends the {@link DefaultMacEventInformation}. This added
* information are specific needed for the {@link Ieee80211AdHocMac}, because we
* need this information at the receiver of the message.
*
* @author Christoph Muenker
* @version 1.0, 22.02.2013
*/
public class WifiMacEventInformation extends DefaultMacEventInformation {
private long transmissionDuration;
private long ackDuration = 0;
private WifiMode ackMode = null;
private WifiMode mode = null;
public WifiMacEventInformation(Ieee80211MacMessage msg, MacAddress sender,
MacAddress receiver, long timeInQueue) {
super(msg, sender, receiver, timeInQueue);
}
@Override
public Ieee80211MacMessage getMessage() {
return (Ieee80211MacMessage) super.getMessage();
}
public void setTransmissionDuration(long transmissionDuration) {
this.transmissionDuration = transmissionDuration;
}
public void setAckDuration(long ackDuration) {
this.ackDuration = ackDuration;
}
public long getTransmissionDuration() {
return transmissionDuration;
}
public long getAckDuration() {
return ackDuration;
}
public void setAckMode(WifiMode ackMode) {
this.ackMode = ackMode;
}
public WifiMode getAckMode() {
return ackMode;
}
public void setMode(WifiMode mode) {
this.mode = mode;
}
public WifiMode getMode() {
return mode;
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.analyzer.ConnectivityAnalyzer;
import de.tud.kom.p2psim.api.analyzer.MessageAnalyzer.Reason;
import de.tud.kom.p2psim.api.analyzer.NetlayerAnalyzer;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.linklayer.mac.PhyType;
import de.tud.kom.p2psim.api.network.NetMessage;
import de.tud.kom.p2psim.api.network.NetMessageListener;
import de.tud.kom.p2psim.api.network.NetMsgEvent;
import de.tud.kom.p2psim.api.network.SimNetInterface;
import de.tud.kom.p2psim.api.network.SimNetworkComponent;
import de.tud.kom.p2psim.api.transport.TransProtocol;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.core.MonitorComponent.AnalyzerNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.network.Bandwidth;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetInterface;
import de.tudarmstadt.maki.simonstrator.api.component.transport.ConnectivityListener;
/**
* This abstract class provides a skeletal implementation of the
* <code>StandaloneNetLayer<code> interface to lighten the effort for implementing this interface.
*
* All Netlayers implementing this abstract base class can only provide exactly one {@link NetInterface},
* i.e., they do not have multiple communication interfaces. For simulations with multiple interfaces,
* you need to use the routedNetLayer and corresponding Linklayers.
*
* @author Sebastian Kaune
* @author Konstantin Pussep
* @version 3.0, 11/29/2007
*
*/
public abstract class AbstractNetLayer implements SimNetworkComponent,
SimNetInterface {
protected static Logger log = SimLogger.getLogger(AbstractNetLayer.class);
private final List<NetMessageListener> msgListeners;
private final List<ConnectivityListener> connListeners;
private final NetID myID;
protected NetMeasurementDB.Host hostMeta;
private boolean online;
private Position position;
Bandwidth currentBandwidth;
Bandwidth maxBandwidth;
private final SimHost host;
protected boolean hasAnalyzer = false;
protected NetlayerAnalyzer netAnalyzerProxy;
/**
* Abstract constructor called by a subclass of this instance
*
* @param maxDownBandwidth
* the maximum physical download bandwidth
* @param maxUpBandwidth
* the maximum physical upload bandwidth
* @param position
* the NetPosition of the network layer
*/
public AbstractNetLayer(SimHost host, NetID netId, Bandwidth maxBandwidth,
Position position, NetMeasurementDB.Host hostMeta) {
this.myID = netId;
this.msgListeners = new LinkedList<NetMessageListener>();
this.connListeners = new LinkedList<ConnectivityListener>();
if (maxBandwidth.getDownBW() < maxBandwidth.getUpBW())
log.warn("maxDownBandwidth < maxUpBandwidth on host with NetID "
+ this.myID);
this.maxBandwidth = maxBandwidth;
this.currentBandwidth = maxBandwidth.clone();
this.position = position;
this.hostMeta = hostMeta;
this.host = host;
}
@Override
public void initialize() {
/*
* Bind the analyzer-Proxy
*/
try {
netAnalyzerProxy = Monitor.get(NetlayerAnalyzer.class);
hasAnalyzer = true;
} catch (AnalyzerNotAvailableException e) {
// no analyzer, no problem
}
}
@Override
public void shutdown() {
throw new AssertionError(
"You are not supposed to shutdown this component.");
}
/**
* This message is called by the subnet to deliver a new NetMessage to a
* remote NetLayer. (@see de.tud.kom.p2psim.impl.network.AbstractSubnet).
* Calling this method informs further all registered NetMsgListeners about
* the receipt of this NetMessage using a appropriate NetMsgEvent.
*
* @param message
* The NetMessage that was received by the NetLayer.
*/
public void receive(NetMessage message) {
if (this.isOnline()) {
// log.info(Simulator.getSimulatedRealtime() + " Receiving " +
// message);
if (hasAnalyzer) {
netAnalyzerProxy
.netMsgEvent(message, getHost(),
Reason.RECEIVE);
}
NetMsgEvent event = new NetMsgEvent(message, this);
if (msgListeners == null || msgListeners.isEmpty()) {
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(message, getHost(),
Reason.DROP);
}
log.warn(this + "Cannot deliver message "
+ message.getPayload() + " at netID=" + myID
+ " as no message msgListeners registered");
} else {
for (NetMessageListener listener : msgListeners) {
listener.messageArrived(event);
}
}
} else {
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(message, getHost(), Reason.DROP);
}
}
}
/**
* Return whether the required transport protocol is supported by the given
* NetLayer instance
*
* @param protocol
* the required transport protocol
* @return true if supported
*/
protected abstract boolean isSupported(TransProtocol protocol);
/**
* As the download bandwidth of a host might be shared between concurrently
* established connections, this method will be used by the subnet in order
* to adapt the current available download bandwidth.
*
* @param currentDownBandwidth
* the new available download bandwidth
*/
@Deprecated
public void setCurrentDownBandwidth(long currentDownBandwidth) {
this.currentBandwidth.setDownBW(currentDownBandwidth);
}
/**
* As the upload bandwidth of a host might be shared between concurrently
* established connections, this method will be used by the subnet in order
* to adapt the current available upload bandwidth.
*
* @param currentUpBandwidth
* the new available upload bandwidth
*/
@Deprecated
public void setCurrentUpBandwidth(long currentUpBandwidth) {
this.currentBandwidth.setUpBW(currentUpBandwidth);
}
public void setCurrentBandwidth(Bandwidth currentBandwidth) {
this.currentBandwidth = currentBandwidth;
}
/*
* (non-Javadoc)
*
* @seede.tud.kom.p2psim.api.api.network.NetLayer#addNetMsgListener(
* NetMessageListener) listener)
*/
public void addNetMsgListener(NetMessageListener listener) {
if (!this.msgListeners.contains(listener)) {
log.debug("Register msg listener " + listener);
this.msgListeners.add(listener);
}
}
public List<NetMessageListener> getNetMsgListeners() {
return this.msgListeners;
}
/*
* (non-Javadoc)
*
* @seede.tud.kom.p2psim.api.api.network.NetLayer#removeNetMsgListener(
* NetMessageListener) listener)
*/
public void removeNetMsgListener(NetMessageListener listener) {
this.msgListeners.remove(listener);
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.api.network.NetLayer#getNetID()
*/
public NetID getNetID() {
return this.myID;
}
@Override
public NetID getLocalInetAddress() {
return this.myID;
}
@Override
public NetID getBroadcastAddress() {
return IPv4NetID.LOCAL_BROADCAST;
}
@Override
public SimNetInterface getByName(NetInterfaceName name) {
if (name == NetInterfaceName.ETHERNET) {
return this;
} else {
throw new AssertionError("This NetLayer supports only ETHERNET!");
}
}
@Override
public NetID getByName(String name) {
return new IPv4NetID(name);
}
@Override
public SimNetInterface getByNetId(NetID netID) {
if (getLocalInetAddress().equals(netID)) {
return this;
} else {
return null;
}
}
@Override
public Iterable<NetInterface> getNetworkInterfaces() {
List<NetInterface> list = new LinkedList<NetInterface>();
list.add(this);
return list;
}
@Override
public Iterable<SimNetInterface> getSimNetworkInterfaces() {
List<SimNetInterface> list = new LinkedList<SimNetInterface>();
list.add(this);
return list;
}
@Override
public NetInterfaceName getName() {
return NetInterfaceName.ETHERNET;
}
@Override
public int getMTU() {
return PhyType.ETHERNET.getDefaultMTU();
}
@Override
public boolean isUp() {
return isOnline();
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.api.network.NetLayer#goOffline()
*/
public void goOffline() {
if (this.online) {
this.online = false;
for (ConnectivityListener connListener : connListeners) {
connListener.wentOffline(host, this);
}
try {
Monitor.get(ConnectivityAnalyzer.class).wentOffline(host);
} catch (AnalyzerNotAvailableException e) {
//
}
log.info(myID + " disconnected @ " + Time.getFormattedTime());
}
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.api.network.NetLayer#goOnline()
*/
public void goOnline() {
if (!this.online) {
this.online = true;
for (ConnectivityListener connListener : connListeners) {
connListener.wentOnline(host, this);
}
try {
Monitor.get(ConnectivityAnalyzer.class).wentOnline(host);
} catch (AnalyzerNotAvailableException e) {
//
}
log.info(myID + " connected @ " + Time.getFormattedTime());
}
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.api.network.NetLayer#isOffline()
*/
@Override
public boolean isOffline() {
return !online;
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.api.network.NetLayer#isOnline()
*/
@Override
public boolean isOnline() {
return online;
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.common.Component#getHost()
*/
@Override
public SimHost getHost() {
return this.host;
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.api.network.NetLayer#getNetPosition()
*/
@Override
public Position getNetPosition() {
return this.position;
}
@Override
public Bandwidth getCurrentBandwidth() {
return currentBandwidth;
}
@Override
public Bandwidth getMaxBandwidth() {
return maxBandwidth;
}
/*
* (non-Javadoc)
*
* @see
* de.tud.kom.p2psim.api.network.NetLayer#removeConnectivityListener(de.
* tud.kom.p2psim.api.common.ConnectivityListener)
*/
@Override
public void removeConnectivityListener(ConnectivityListener listener) {
this.connListeners.remove(listener);
}
@Override
public void addConnectivityListener(ConnectivityListener listener) {
this.connListeners.add(listener);
}
/**
* Gets the dB host meta from NetMessurementDB
*
* @return the dB host meta
*/
public NetMeasurementDB.Host getDBHostMeta() {
return hostMeta;
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network;
import de.tud.kom.p2psim.api.network.BandwidthDetermination;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.util.BackToXMLWritable;
import de.tudarmstadt.maki.simonstrator.api.component.HostComponentFactory;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
public abstract class AbstractNetLayerFactory implements HostComponentFactory,
BackToXMLWritable {
/**
* In bytes per second. This variable is used to initialize
* <code>downBandwidth</code> with a default value if the config-file does
* not specify a separate value.
*/
protected final static long DEFAULT_DOWN_BANDWIDTH = 5000l;
/**
* In bytes per second. This variable is used to initialize
* <code>upBandwidth</code> with a default value if the config-file does not
* specify a separate value.
*/
protected final static long DEFAULT_UP_BANDWIDTH = 5000l;
/**
* In bytes per second. <code>downBandwidth</code> is initialized with a
* value, that can be provided by the config-file, otherwise it gets the
* value stored in <code>DEFAULT_DOWN_BANDWIDTH</code>.
*/
protected long downBandwidth;
/**
* In bytes per second. <code>upBandwidth</code> is initialized with a
* value, that can be provided by the config-file, otherwise it gets the
* value stored in <code>DEFAULT_UP_BANDWIDTH</code>.
*/
protected long upBandwidth;
protected BandwidthDetermination bandwidthDetermination;
protected NetMeasurementDB db;
public AbstractNetLayerFactory() {
this.downBandwidth = DEFAULT_DOWN_BANDWIDTH;
this.upBandwidth = DEFAULT_UP_BANDWIDTH;
this.bandwidthDetermination = null;
}
protected BandwidthImpl getBandwidth(NetID netID) {
if (bandwidthDetermination == null) {
return new BandwidthImpl(this.downBandwidth, this.upBandwidth);
}
return bandwidthDetermination.getRandomBandwidth();
}
public void setBandwidthDetermination(
BandwidthDetermination bandwidthDetermination) {
this.bandwidthDetermination = bandwidthDetermination;
}
/**
* Sets the downstream bandwidth in bytes/sec
*
* @param downBandwidth
*/
public void setDownBandwidth(long downBandwidth) {
this.downBandwidth = downBandwidth;
}
/**
* Sets the upstream bandwidth in bytes/sec
*
* @param upBandwidth
*/
public void setUpBandwidth(long upBandwidth) {
this.upBandwidth = upBandwidth;
}
/**
* Sets the measurement db.
*
* @param db the new measurement db
*/
public void setMeasurementDB(NetMeasurementDB db) {
this.db = db;
}
@Override
public void writeBackToXML(BackWriter bw) {
bw.writeSimpleType("downBandwidth", downBandwidth);
bw.writeSimpleType("upBandwidth", upBandwidth);
bw.writeComplexType("BandwidthDetermination", bandwidthDetermination);
bw.writeComplexType("MeasurementDB", db);
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network;
import de.tud.kom.p2psim.api.network.NetMessage;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* This abstract class provides a skeletal implementation of the
* <code>NetMessage<code> interface to lighten the effort for implementing this interface.
*
* @author Sebastian Kaune
* @author Konstantin Pussep
* @version 3.0, 11/29/2007
*/
public abstract class AbstractNetMessage implements NetMessage {
/**
* The payload of the NetMessage.
*/
private Message payload;
/**
* The NetID of the receiver.
*/
private NetID receiver;
/**
* The NetID of the sender.
*/
private NetID sender;
/**
* The NetProtocol of the NetMessage.
*/
private NetProtocol netProtocol;
/**
* The Number of Fragments.
*/
protected int noOfFragments = 0;
/**
* Constructor called by subclasses of this
*
* @param payload
* The payload of the ComplexNetworkMessage.
* @param receiver
* The NetID of the receiver.
* @param sender
* The NetID of the sender.
* @param netProtocol
* The ServiceCategory of the ComplexNetworkMessage.
*/
public AbstractNetMessage(Message payload, NetID receiver, NetID sender,
NetProtocol netProtocol) {
this.payload = payload;
this.receiver = receiver;
this.sender = sender;
this.netProtocol = netProtocol;
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.network.NetMessage#getReceiver()
*/
public NetID getReceiver() {
return this.receiver;
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.network.NetMessage#getSender()
*/
public NetID getSender() {
return this.sender;
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.network.NetMessage#getNetProtocol()
*/
public NetProtocol getNetProtocol() {
return this.netProtocol;
}
/*
* (non-Javadoc)
*
* @see de.tud.kom.p2psim.api.common.Message#getPayload()
*/
public Message getPayload() {
return this.payload;
}
/**
* Returns the number of fragments the message is split into.
* @return
*/
public int getNoOfFragments() {
return noOfFragments;
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network;
import de.tud.kom.p2psim.api.network.NetLayer;
import de.tud.kom.p2psim.api.network.NetMessage;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.transport.AbstractTransMessage;
import de.tudarmstadt.maki.simonstrator.api.Message;
/**
* The Subnet models the intrinsic complexity of the internet as a "big cloud"
* which appears to be transparent for the end-systems (hosts). That is, when
* sending a message using the tcp/udp protocol, the message is given from the
* sending host to the the subnet and the subnet manages the calculation of
* transmission times, establishes a tcp connection (if necessary) between the
* sender and receiver, models the packet loss and jitter and schedules the
* appropriate events at the simulation framework. It also triggers the arrival
* of a message at the appropriate receiver by using the
* de.tud.kom.p2psim.impl.network.AbstractNetLayer#receive(NetMessage) method.
*
* @author Sebastian Kaune
* @author Konstantin Pussep
* @version 3.0, 11/29/2007
*/
public abstract class AbstractSubnet {
/**
* Used MeasurementDB for Latency, Jitter, etc.
*/
private NetMeasurementDB db;
private int lastCommId = 0;
/**
* This method passes a given NetMessage from the sending host to the
* subnet.
*
* @param msg
* the message to be send
*/
public abstract void send(NetMessage msg);
/**
* Registers a new NetLayer to the subnet
*
* @param net
* the NetLayet to be registered
*/
public abstract void registerNetLayer(NetLayer net);
/**
*
* @param message
* @return
*/
public int determineTransMsgNumber(Message message) {
// Iterate over the nested messages until AbstractTransMessage is
// reached
while (!(message instanceof AbstractTransMessage)) {
message = message.getPayload();
}
// Depending on the current commId of transMsg return a new id or the
// old one
AbstractTransMessage transMsg = (AbstractTransMessage) message;
if (transMsg.getCommId() == -1) {
return lastCommId++;
} else {
return transMsg.getCommId();
}
}
/**
* Set Measurement-DB
*
* @param db
*/
public void setDB(NetMeasurementDB db) {
this.db = db;
}
/**
* Get Measurement-DB
*
* @return
*/
public NetMeasurementDB getDB() {
return db;
}
}
package de.tud.kom.p2psim.impl.network;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* Borrowed from the P2Pstream-overlay this component is able to estimate the
* current bandwidth consumption at a host. It can be used in the NetLayer or
* any other component that estimates a bandwidth by passing message sizes.
*
* It supports two modes of operation: estimation of used bandwidth as well as
* estimation of remaining free bandwidth - have a look at the constructors.
*
* @author Bjoern Richerzhagen, based on sources by unknown
* @version 1.0, 08.08.2012
*/
public class BandwidthEstimator {
/**
* Estimation interval in seconds
*/
private final int estimationInterval;
private final BandwidthImpl estimatedBandwidth;
/**
* if this is not null, the estimator will return the remaining FREE
* bandwidth (i.e. max - estimate)
*/
private final BandwidthImpl maxBandwidth;
private final boolean isFreeBandwidth;
private final long[] inTransRing;
private final long[] outTransRing;
private long inLastEditInSec = -1;
private long outLastEditInSec = -1;
private long inTransBytes = 0;
private long outTransBytes = 0;
/**
*
* @param estimationInterval
* time that is used for the estimation in seconds
*/
public BandwidthEstimator(int estimationInterval) {
this(new BandwidthImpl(0, 0), estimationInterval);
}
/**
* A bandwidth estimator that counts the bandwidth that is USED (i.e. not
* the remaining free BW).
*
* @param estimatedBandwidth
* this object is updated with the estimations each time a change
* occurs.
* @param estimationInterval
* seconds of historical data that is used to estimate the
* current BW (window smoothing)
*/
public BandwidthEstimator(BandwidthImpl estimatedUsedBandwidth,
int estimationInterval) {
this(estimatedUsedBandwidth, null, estimationInterval);
}
/**
* A bandwidth estimator that counts the bandwidth that is remaining free
* with respect to the maximum bandwidth provided.
*
* @param estimatedRemainingBandwidth
* @param maxBandwidth
* @param estimationInterval
*/
public BandwidthEstimator(BandwidthImpl estimatedRemainingBandwidth,
BandwidthImpl maxBandwidth, int estimationInterval) {
this.estimationInterval = estimationInterval;
this.estimatedBandwidth = estimatedRemainingBandwidth;
this.maxBandwidth = maxBandwidth;
this.isFreeBandwidth = maxBandwidth != null;
this.inTransRing = new long[estimationInterval];
this.outTransRing = new long[estimationInterval];
}
/**
* Current estimation (the object is updated with every new estimate)
*
* @return
*/
public BandwidthImpl getEstimatedBandwidth() {
refresh();
return estimatedBandwidth;
}
/**
* If true, this estimator returns an estimation of remaining free BW with
* respect to a max-BW. If false, it just returns an estimation of the used
* bandwidth.
*
* @return
*/
public boolean isFreeBandwidth() {
return isFreeBandwidth;
}
/**
* Seconds of historical data that is used to compute the bandwidth.
*
* @return
*/
public int getEstimationInterval() {
return estimationInterval;
}
/**
* Call this whenever an incoming transmission took place
*
* @param size
*/
public void incomingTransmission(long size) {
long currentTimeInSec = Time.getCurrentTime() / Time.SECOND;
int index = (int) (currentTimeInSec % inTransRing.length);
refresh();
inTransRing[index] += size;
inTransBytes += size;
inLastEditInSec = currentTimeInSec;
if (isFreeBandwidth) {
estimatedBandwidth.setDownBW(Math.max(0, maxBandwidth.getDownBW()
- inTransBytes / inTransRing.length));
} else {
estimatedBandwidth.setDownBW(inTransBytes / inTransRing.length);
}
}
/**
* Call this whenever an outgoing transmission took place
*
* @param size
*/
public void outgoingTransmission(long size) {
long currentTimeInSec = Time.getCurrentTime() / Time.SECOND;
int index = (int) (currentTimeInSec % outTransRing.length);
refresh();
outTransRing[index] += size;
outTransBytes += size;
outLastEditInSec = currentTimeInSec;
if (isFreeBandwidth) {
estimatedBandwidth.setUpBW(Math.max(0, maxBandwidth.getUpBW()
- outTransBytes / outTransRing.length));
} else {
estimatedBandwidth.setUpBW(outTransBytes / outTransRing.length);
}
}
/**
* Triggers a refresh of the Bandwidth-Object (this might be necessary if no
* transmission was counted for a long time)
*/
public void refresh() {
long currentTimeInSec = Time.getCurrentTime() / Time.SECOND;
if (currentTimeInSec > outLastEditInSec) {
if (currentTimeInSec - outLastEditInSec > outTransRing.length) {
/*
* There was no transmission for a long time --> Reset of ring
* is the best.
*/
for (int i = 0; i < outTransRing.length; i++) {
outTransRing[i] = 0;
}
outTransBytes = 0;
} else {
for (long i = outLastEditInSec + 1; i <= currentTimeInSec; i++) {
int eraseIndex = (int) (i % outTransRing.length);
outTransBytes -= outTransRing[eraseIndex];
outTransRing[eraseIndex] = 0;
}
}
if (isFreeBandwidth) {
estimatedBandwidth.setUpBW(Math.max(0, maxBandwidth.getUpBW()
- outTransBytes / outTransRing.length));
} else {
estimatedBandwidth.setUpBW(outTransBytes / outTransRing.length);
}
}
if (currentTimeInSec > inLastEditInSec) {
if (currentTimeInSec - inLastEditInSec > inTransRing.length) {
/*
* There was no transmission for a long time --> Reset of ring
* is the best.
*/
for (int i = 0; i < inTransRing.length; i++) {
inTransRing[i] = 0;
}
inTransBytes = 0;
} else {
for (long i = inLastEditInSec + 1; i <= currentTimeInSec; i++) {
int eraseIndex = (int) (i % inTransRing.length);
inTransBytes -= inTransRing[eraseIndex];
inTransRing[eraseIndex] = 0;
}
}
if (isFreeBandwidth) {
estimatedBandwidth.setDownBW(Math.max(0,
maxBandwidth.getDownBW() - inTransBytes
/ inTransRing.length));
} else {
estimatedBandwidth.setDownBW(inTransBytes / inTransRing.length);
}
}
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network;
import de.tud.kom.p2psim.api.network.NetMessageEvent;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
*
* @author Bjoern Richerzhagen
* @version 1.0, 29.02.2012
*/
public class DefaultNetMessageEvent implements NetMessageEvent {
private Message payload;
private NetID sender;
private NetID receiver;
private NetProtocol netProtocol;
/**
* Constructs NetMsgEvent
*
* @param netMsg
* the NetMessage received by the NetLayer
* @param source
* the source of this event
*/
public DefaultNetMessageEvent(NetProtocol protocol, NetID sender,
NetID receiver, Message payload) {
this.netProtocol = protocol;
this.sender = sender;
this.receiver = receiver;
this.payload = payload;
}
/**
* Returns the data which was encapsulated in the network message
*
* @return the data which was encapsulated in the network message
*/
@Override
public Message getPayload() {
return payload;
}
/**
* Returns the NetID of the sender of the received network message
*
* @return the NetID of sender of the received network message
*/
@Override
public NetID getSender() {
return sender;
}
@Override
public NetID getReceiver() {
return receiver;
}
/**
* Returns the used network protocol
*
* @return the used network protocol
*
*/
@Override
public NetProtocol getNetProtocol() {
return netProtocol;
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* Implements the NetworkMessage-Interface for the complex network model.
*
* @author Sebastian Kaune
*/
public class IPv4Message extends AbstractNetMessage {
/** Packet header size. */
public static final int HEADER_SIZE = 20;
public static final int MAX_IP_PACKET_SIZE = 65535;
public static final int MTU_SIZE = 1500;
private int noOfFragments = 1;
private long size = 0;
public IPv4Message(Message payload, NetID receiver, NetID sender) {
super(payload, receiver, sender, NetProtocol.IPv4);
noOfFragments = (int) Math.ceil((double) getPayload().getSize()
/ (double) (MTU_SIZE - HEADER_SIZE));
size = getPayload().getSize() + HEADER_SIZE * noOfFragments; //FIXME: why "* noOfFragments"?
}
public long getSize() {
return size;
}
public int getNoOfFragments() {
return noOfFragments;
}
@Override
public String toString() {
return "[ IP " + super.getSender() + " -> " + super.getReceiver()
+ " | size: " + getSize() + " ( " + noOfFragments + "*"
+ HEADER_SIZE + " + " + getPayload().getSize()
+ " ) bytes | payload: " + getPayload() + " ]";
}
}
\ No newline at end of file
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* Implementation of the NetID-Interface for IPv4-Addresses
*
* @author Gerald Klunker
*/
public class IPv4NetID implements NetID {
/**
* 32bit IP Address (with respect to the algebraic sign of 32bit Integers in
* a 64bit Long Value).
*/
private Long id;
/**
* Broadcast-Adress which is used by the subnet
*/
public static IPv4NetID LOCAL_BROADCAST = new IPv4NetID("255.255.255.255");
/**
* Creates an Instance of IPv4NetID.
*
* @param id
* The Long-ID.
*/
public IPv4NetID(Long id) {
this.id = id;
}
public IPv4NetID(String id) {
try {
long ip = Long.parseLong(id);
this.id = ip;
} catch (Exception e) {
long ip = IPv4NetID.ipToLong(id);
this.id = ip;
}
}
/**
* @return The Long-ID.
*/
public long getID() {
return this.id;
}
/**
* @param obj
* An object.
* @return Whether the parameter is equal to this IPv4NetID or not.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof IPv4NetID) {
return getID() == ((IPv4NetID) obj).getID();
} else {
return false;
}
}
/**
* @return The hashcode of this IPv4NetID.
*/
@Override
public int hashCode() {
return this.id.hashCode();
}
/**
* @return A string representing this InternetProtocolNetID.
*/
@Override
public String toString() {
return IPv4NetID.ipToString(this.id);
}
// TODO Throw exceptions on invalid values for the parameters
/**
* @param ip
* 32bit IP-Address
* @return A readable IP-String like "192.168.0.1"
*/
public static String ipToString(Long ip) {
String returnString = "";
returnString += Long.toString((ip << 32) >>> 56) + ".";
returnString += Long.toString((ip << 40) >>> 56) + ".";
returnString += Long.toString((ip << 48) >>> 56) + ".";
returnString += Long.toString((ip << 56) >>> 56);
return returnString;
}
/**
*
* @param ip
* readable IP-String like "192.168.0.1"
* @return A 32bit IP-Address
*/
public static Long ipToLong(String ip) {
String[] ipBytes = ip.split("\\.");
Long ipLong = new Long(0);
try {
ipLong += (Long.valueOf(ipBytes[0])) << 24;
ipLong += (Long.valueOf(ipBytes[1])) << 16;
ipLong += (Long.valueOf(ipBytes[2])) << 8;
ipLong += Long.valueOf(ipBytes[3]);
} catch (Exception e) {
return null;
}
return ipLong;
}
public static int ipToInt(String ip) {
String[] ipBytes = ip.split("\\.");
int ipInt = 0;
ipInt += (Integer.valueOf(ipBytes[0])) << 24;
ipInt += (Integer.valueOf(ipBytes[1])) << 16;
ipInt += (Integer.valueOf(ipBytes[2])) << 8;
ipInt += Integer.valueOf(ipBytes[3]);
return ipInt;
}
/**
* @param ip
* 32bit IP-Address
* @return A readable IP-String like "192.168.0.1"
*/
public static String intToIP(int ip) {
String returnString = "";
returnString += Integer.toString((ip << 32) >>> 56) + ".";
returnString += Integer.toString((ip << 40) >>> 56) + ".";
returnString += Integer.toString((ip << 48) >>> 56) + ".";
returnString += Integer.toString((ip << 56) >>> 56);
return returnString;
}
public static long intToLong(int ip) {
return Long.parseLong(Integer.toBinaryString(ip), 2);
}
public static int longToInt(long ip) {
return (int) ip;
}
@Override
public int getTransmissionSize() {
return 4;
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.bandwidthDetermination;
/**
* The implemented bandwidth distribution is taken from the latest OECD
* broadband report (For further information, please see Oecd broadband portal,
* http://www.oecd.org/sti/ict/broadband). The provided values for upload- and
* download-bandwidth are denoted in bytes per second.
*
* @author Leo Nobach (additional changes: Dominik Stingl)
*
*/
public class OECDReportBandwidthDetermination extends PickFromRandomGroupBandwidthDetermination {
@Override
public void addBandwidthGroups() {
addNewBandwidth(7000, 7000, 600); // Modem 15%
addNewBandwidth(8000, 8000, 600); // ISDN
addNewBandwidth(87355, 1202843, 1601); // DSL 41%
addNewBandwidth(89000, 236111, 47); // Wireless 1%
addNewBandwidth(158001, 1856966, 758); // Cable 19%
addNewBandwidth(4280818, 8165793, 258); // FTTx 6%
// 3864
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.bandwidthDetermination;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.network.BandwidthDetermination;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
/**
* Picks a random bandwidth (weighted) from a list of bandwidth groups assigned.
* Overriding classes should add specific bandwidth groups.
*
* @author Leo Nobach (additional changes: Dominik Stingl)
*
*/
public abstract class PickFromRandomGroupBandwidthDetermination implements
BandwidthDetermination<Integer> {
private static Logger log = SimLogger
.getLogger(PickFromRandomGroupBandwidthDetermination.class);
Random rand = Randoms
.getRandom(PickFromRandomGroupBandwidthDetermination.class);
int distributionMax = 0;
List<Integer> distribution = new ArrayList<Integer>();
List<BandwidthImpl> bandwidths = new ArrayList<BandwidthImpl>();
public PickFromRandomGroupBandwidthDetermination() {
log.debug("Init RandomBandwidthDetermination");
addBandwidthGroups();
}
public abstract void addBandwidthGroups();
/**
* Adds a new type of a network interface to the collection of different
* network interfaces. The specification for a new type consists of the
* upload- and download-bandwidth as well as of the relative usage-amount of
* the network interface
*
* @param upBW
* describes the maximum upload-bandwidth in byte per second
* @param downBW
* describes the maximum download-bandwidth in byte per second
* @param part
* describes the proportion of network interfaces of the given
* type
*/
protected void addNewBandwidth(long upBW, long downBW, int part) {
distributionMax += part;
distribution.add(distributionMax);
bandwidths.add(new BandwidthImpl(downBW, upBW));
}
public BandwidthImpl getRandomBandwidth() {
int random = rand.nextInt(distributionMax);
for (int i = 0; i < bandwidths.size(); i++) {
if (distribution.get(i) > random) {
log.trace("Getting " + bandwidths.get(i).toString());
return bandwidths.get(i);
}
}
log
.trace("Getting "
+ bandwidths.get(bandwidths.size() - 1).toString());
return bandwidths.get(bandwidths.size() - 1);
}
@Override
public BandwidthImpl getBandwidthByObject(Integer object) {
// nothing to do
return null;
}
@Override
public void writeBackToXML(BackWriter bw) {
//No simple/complex types to write back
}
}
/*
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM 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
* any later version.
*
* PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.network.bandwidthDetermination;
import java.util.Random;
import de.tud.kom.p2psim.api.network.BandwidthDetermination;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
/**
* This class implements a randomized determination of bandwidth, that follows
* no certain distribution, but is used to omit a static assignment of
* bandwidth-capacities.
*
* @author Dominik Stingl
*
*/
public class RandomizedBandwidthDetermination implements
BandwidthDetermination<Integer> {
private double maxDownBandwidth = 10000d;
private double minDownBandwidth = 5000d;
private double upstreamBWQuota = 0.1;
private Random rnd = Randoms
.getRandom(RandomizedBandwidthDetermination.class);
@Override
public BandwidthImpl getBandwidthByObject(Integer object) {
// not needed
return null;
}
@Override
public BandwidthImpl getRandomBandwidth() {
double downBandwidth = minDownBandwidth + rnd.nextDouble()
* (maxDownBandwidth - minDownBandwidth);
double upBandwidth = downBandwidth * upstreamBWQuota;
return new BandwidthImpl((long)Math.floor(downBandwidth), (long)Math.floor(upBandwidth));
}
public void setMaxDownBandwidth(double maxDownBandwidth) {
this.maxDownBandwidth = maxDownBandwidth;
}
public void setMinDownBandwidth(double minDownBandwidth) {
this.minDownBandwidth = minDownBandwidth;
}
@Override
public void writeBackToXML(BackWriter bw) {
bw.writeSimpleType("maxDownBandwidth", maxDownBandwidth);
bw.writeSimpleType("minDownBandwidth", minDownBandwidth);
}
}
package de.tud.kom.p2psim.impl.network.fairshare;
/**
* A Connection connects two distinct Nodes. It is directed, that is, it
* connects a source to a destination. Connections are Comparable in that a
* Connection with a smaller "bid" is smaller than a Connection with a bigger
* "bid" (see {@link #getMinBid()}).
*
* @author Tobias Lauinger
*/
public interface Connection extends Comparable<Connection> {
/**
* Returns one of the end points of this Connection.
*
* @param destination
* true if the sink is to be returned (else the source).
*
* @return the download/upload Node of this Connection.
*/
public Node getNode(boolean destination);
/**
* @return true if this Connection is currently used (false if idle).
*/
public boolean isInUse();
/**
* Resets the state of this Connection for a new, clean run of the fair
* share algorithm. The state that will be cleared is the assigned
* bandwidth.
*/
public void reset();
/**
* @return the bandwidth that has been assigned to this Connection by the
* fair share algorithm. Returns 0 if the bandwidth has not yet been
* determined.
*/
public double getBandwidth();
/**
* @return the minimum bandwidth bid of the two connected Nodes.
*/
public double getMinBid();
/**
* Assigns the given bandwidth to this Connection and updates the source and
* destination Nodes of this Connection.
*
* @param bandwidth
* the bandwidth of this Connection.
*/
public void assignBandwidth(double bandwidth);
}
package de.tud.kom.p2psim.impl.network.fairshare;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
/**
* An implementation of the fair share bandwidth allocation algorithm. TODO
* extend and move to a sensible place.
*
* @author Tobias Lauinger
*/
public class FairShareAlgorithm {
/**
* Runs the fair share algorithm.
*
* NOTE: CHANGED by Peter Heise:
*
* Did not recalculate all links on remove. Now has to called like:
* LinkedHashSet<Connection> links = new LinkedHashSet<Connection>();
* receiver.traverseConnections(links, true);
* sender.traverseConnections(links, false);
* fairShare.run(links);
*
*
* @param links
* Collection of all affected links
*/
public void run(LinkedHashSet<Connection> links) {
LinkedList<Connection> sortedLinks = new LinkedList<Connection>(links);
Collections.sort(sortedLinks);
while( !sortedLinks.isEmpty() ) {
Connection min = sortedLinks.remove(0);
min.assignBandwidth(min.getMinBid());
/*
* NOTE: CHANGED by Peter Heise:
* Needs to be recalculated in every iteration so that all flows are fully saturated.
*
* Reference: "Accurate and Efficient Simulation of Bandwidth Dynamics for Peer-To-Peer Overlay Networks"
* by Alexandros Gkogkas, see proposed Algorithm 1.
*
*/
Collections.sort(sortedLinks);
}
}
}
package de.tud.kom.p2psim.impl.network.fairshare;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* An implementation of the Connection interface. TODO to be extended.
*
* @author Tobias Lauinger
*/
public class Link implements Connection {
static Logger log = SimLogger.getLogger(Link.class);
private final Node src;
private final Node dst;
private long lastTime;
private long transferEndTime;
private double bandwidth;
private double oldBandwidth;
private double remainingBytes;
// private double transferedBytes;
private double messageSize;
private long creationTime;
private boolean burstMessage;
private boolean statusChanged;
private final long propagationDelay;
public Link(final Node source, final Node sink, double msgSize,
final long minimumDelay) {
src = source;
dst = sink;
src.addConnection(this, false);
dst.addConnection(this, true);
creationTime = Time.getCurrentTime();
remainingBytes = msgSize;
messageSize = msgSize;
lastTime = creationTime;
burstMessage = false;
statusChanged = false;
propagationDelay = minimumDelay;
}
public long getCreationTime() {
return creationTime;
}
public long getPropagationDelay() {
return propagationDelay;
}
public void addBurstMessage(double msgSize) {
creationTime = Time.getCurrentTime();
remainingBytes = msgSize;
assert (remainingBytes > 0);
messageSize = msgSize;
lastTime = creationTime;
burstMessage = true;
statusChanged = true;
}
@Override
public double getBandwidth() {
return bandwidth;
}
public void calculateNewTransferEndTime() {
long currentTime = Time.getCurrentTime();
long lastTransferInterval = currentTime - lastTime;
lastTime = currentTime;
assert (lastTransferInterval >= 0);
double byteBurst = (lastTransferInterval / (double) Time.SECOND)
* oldBandwidth;
remainingBytes -= byteBurst;
double time = remainingBytes / bandwidth;
transferEndTime = Math.round(time * Time.SECOND) + currentTime;
if (transferEndTime < currentTime)
transferEndTime = currentTime;
// log.info("**************************************************************");
// log.info("Link " + src.getNetID() + " -> " + dst.getNetID() + " @ "
// + Simulator.getCurrentTime());
// log.info("lastTransferInterval (ns): " + lastTransferInterval
// + " | Total bytes: " + messageSize + " | Remaining bytes "
// + remainingBytes);
// log.info("Allocated link bandwidth: " + bandwidth
// + " bytes/s | Transmission duration: " + time
// * Simulator.MILLISECOND_UNIT + " ms");
// log.info("Transfer endtime: " + transferEndTime);
// log.info("**************************************************************");
// log.info("");
statusChanged = false;
assert (creationTime < transferEndTime);
}
public long getTransferEndTime() {
return this.transferEndTime;
}
@Override
public double getMinBid() {
final double bidSrc = src.getCurrentFairShare(false);
final double bidDst = dst.getCurrentFairShare(true);
assert (bidSrc > 0);
assert (bidDst > 0);
if (bidSrc > bidDst) {
return bidDst;
} else {
return bidSrc;
}
}
@Override
public Node getNode(boolean destination) {
if (destination) {
return dst;
} else {
return src;
}
}
@Override
public boolean isInUse() {
return true;
}
public boolean isBurst() {
return burstMessage;
}
public void resetBurst() {
burstMessage = false;
}
@Override
public void reset() {
oldBandwidth = bandwidth;
statusChanged = true;
bandwidth = 0;
}
public boolean hasStatusChanged() {
return statusChanged;
}
@Override
public int compareTo(Connection c) {
if (c instanceof Link)
return ((Double) getMinBid()).compareTo((Double) c.getMinBid());
log.error("Cannot compare Link to " + c.getClass());
return 0;
}
@Override
public void assignBandwidth(final double newBandwidth) {
assert (newBandwidth > 0);
bandwidth = newBandwidth;
src.updateAvailableBandwidth(bandwidth, false);
dst.updateAvailableBandwidth(bandwidth, true);
log.debug("Setting rate to " + newBandwidth + "bytes/sec for " + this);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Link) {
Link aLink = (Link) obj;
if (this.getNode(true).equals(aLink.getNode(true))) {
if (this.getNode(false).equals(aLink.getNode(false))) {
return true;
}
}
}
return false;
}
@Override
public String toString() {
return "Flow[ " + this.src.getNetID() + "(U:"
+ this.src.getCurrentBandwidth().getUpBW() + "/D:"
+ this.src.getCurrentBandwidth().getDownBW() + ")" + "\t"
+ " -> " + this.dst.getNetID() + "(U:"
+ this.dst.getCurrentBandwidth().getUpBW() + "/D:"
+ this.dst.getCurrentBandwidth().getDownBW() + ")" + "\t"
+ " ]";
}
}
package de.tud.kom.p2psim.impl.network.fairshare;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.analyzer.MessageAnalyzer.Reason;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tud.kom.p2psim.api.network.FlowBasedNetlayer;
import de.tud.kom.p2psim.api.network.NetMessage;
import de.tud.kom.p2psim.api.network.NetProtocol;
import de.tud.kom.p2psim.api.transport.TransProtocol;
import de.tud.kom.p2psim.impl.network.AbstractNetLayer;
import de.tud.kom.p2psim.impl.network.IPv4Message;
import de.tud.kom.p2psim.impl.network.IPv4NetID;
import de.tud.kom.p2psim.impl.network.fairshare.position.FairshareGnpPosition;
import de.tud.kom.p2psim.impl.network.fairshare.position.GeoLocation;
import de.tud.kom.p2psim.impl.transport.AbstractTransMessage;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
/**
* A Node is a participant in a network. It has connections to other Nodes, but
* never to itself. Its incoming and outgoing network bandwidth is restricted.
* It can participate in an algorithm to assign each connection a fair share of
* bandwidth.
*
* @author Tobias Lauinger, Sebastian Kaune, Yue Sheng
*/
public class Node extends AbstractNetLayer implements FlowBasedNetlayer {
private static Logger log = SimLogger.getLogger(Node.class);
private final HashSet<Connection> incomingConnections;
private final HashSet<Connection> outgoingConnections;
private final OptimizedSubnet subnet;
private double unassignedIncomingConnections;
private double unassignedOutgoingConnections;
private final GeoLocation geoLocation;
private final Map<Node, List<NetMessage>> hostQueues;
public Node(SimHost host, final double maxDownBW, final double maxUpBW,
IPv4NetID netID,
FairshareGnpPosition netPosition, GeoLocation geoLoc,
OptimizedSubnet gnpSubNet) {
super(host, netID, new BandwidthImpl(maxDownBW, maxUpBW), netPosition,
null);
subnet = gnpSubNet;
incomingConnections = new LinkedHashSet<Connection>();
outgoingConnections = new LinkedHashSet<Connection>();
geoLocation = geoLoc;
hostQueues = new HashMap<Node, List<NetMessage>>();
subnet.registerNetLayer(this);
}
public void setIncomingBandwidth(double incomingBw) {
getMaxBandwidth().setDownBW(incomingBw);
}
public void setOutgoingBandwidth(double outgoingBw) {
getMaxBandwidth().setUpBW(outgoingBw);
}
/**
* Adds the given Connection to the Connections of this Node. The new
* Connection does not automatically obtain bandwidth; this has to be
* triggered via a run of the fair share algorithm.
*
* @param c
* the Connection to be added.
* @param incoming
* true if the Connection is a download connection.
*/
public void addConnection(Connection c, boolean incoming) {
if (incoming) {
incomingConnections.add(c);
// unassignedIncomingConnections++;
} else {
outgoingConnections.add(c);
// unassignedOutgoingConnections++;
}
}
/**
* Removes the given Connection from the Connections of this Node.
*
* @param c
* the Connection to be removed.
* @param incoming
* true if the Connection is a download connection.
*/
public void removeConnection(Connection c, boolean incoming) {
if (incoming) {
incomingConnections.remove(c);
} else {
outgoingConnections.remove(c);
}
}
/**
* Adds the Connections of this Node, either incoming or outgoing, to the
* given Collection and calls this method on the Nodes on the other sides of
* the Connections, if they were not previously contained in the Collection.
* Also resets the state of the involved Connections and Nodes.
*
* @param c
* the Collection with the Connections that have already been
* visited.
* @param incoming
* true if download Connections are to be followed (which means
* that at the other end of this Node's Connections upload
* Connections will be followed).
*/
public void traverseConnections(Collection<Connection> c, boolean incoming) {
final Collection<Connection> toTraverse;
if (incoming) {
toTraverse = incomingConnections;
} else {
toTraverse = outgoingConnections;
}
this.reset(incoming);
for (final Connection con : toTraverse) {
// add only if in use, traverse only if added
if (con.isInUse() && c.add(con)) {
// reset state of Connection
con.reset(); // TODO will be called twice
// traverse other end of connection
// traverse other type of connections at other end
con.getNode(!incoming).traverseConnections(c, !incoming);
}
}
}
/**
* Resets the state of this Node for a new, clean run of the fair share
* algorithm. The state that will be cleared are the number of assigned
* connections and the currently unassigned incoming and outgoing network
* capacity.
*
* @param incoming
* true if the state for the incoming (download) Connections is
* to be reset (else the outgoing/upload connections).
*/
public void reset(boolean incoming) {
if (incoming) {
getCurrentBandwidth().setDownBW(getMaxBandwidth().getDownBW());
unassignedIncomingConnections = incomingConnections.size();
} else {
getCurrentBandwidth().setUpBW(getMaxBandwidth().getUpBW());
unassignedOutgoingConnections = outgoingConnections.size();
}
}
/**
* Calculates the current fair share of bandwidth for the unassigned
* connections (the available bandwidth divided by the number of unassigned
* connections).
*
* @param incoming
* true if download connections are to be considered, else
* considering upload connections.
* @return the current fair share for the unassigned connections.
*/
public double getCurrentFairShare(boolean incoming) {
// TODO "incoming" not currently used
if (incoming) {
assert unassignedIncomingConnections > 0 : "unassigned download-connections:"
+ unassignedIncomingConnections;
return getCurrentBandwidth().getDownBW()
/ unassignedIncomingConnections;
} else {
assert unassignedOutgoingConnections > 0;
return getCurrentBandwidth().getUpBW()
/ unassignedOutgoingConnections;
}
}
/**
* Updates this Node with the newly assigned bandwidth. It will be
* subtracted from the currently unassigned bandwidth.
*
* @param bandwidth
* the bandwidth that has been assigned to the Connection.
* @param incoming
* true if the updated Connection was a download connection.
*/
public void updateAvailableBandwidth(double bandwidth, boolean incoming) {
double newBandwidth;
if (incoming) {
assert unassignedIncomingConnections > 0;
// unassignedIncomingBandwidth -= bandwidth;
newBandwidth = getCurrentBandwidth().getDownBW() - bandwidth;
getCurrentBandwidth().setDownBW(newBandwidth);
unassignedIncomingConnections--;
} else {
assert unassignedOutgoingConnections > 0;
// unassignedOutgoingBandwidth -= bandwidth;
newBandwidth = getCurrentBandwidth().getUpBW() - bandwidth;
getCurrentBandwidth().setUpBW(newBandwidth);
unassignedOutgoingConnections--;
}
assert newBandwidth >= 0;
}
@Override
protected boolean isSupported(TransProtocol protocol) {
return (protocol.equals(TransProtocol.UDP) || protocol
.equals(TransProtocol.TCP));
}
/**
*
* @return 2-digit country code
*/
public String getCountryCode() {
return geoLocation.getCountryCode();
}
@Override
public void send(Message msg, NetID receiverId, NetProtocol protocol) {
if (isOnline()) {
assert (msg.getSize() >= 0);
assert (isSupported(((AbstractTransMessage) msg).getProtocol()));
NetMessage netMsg = new IPv4Message(msg, receiverId,
this.getLocalInetAddress());
TransProtocol current = ((AbstractTransMessage) msg).getProtocol();
if (current.equals(TransProtocol.UDP)) {
if (hasAnalyzer) {
netAnalyzerProxy
.netMsgEvent(netMsg, getHost(), Reason.SEND);
}
this.subnet.sendUDP(netMsg);
} else if (current.equals(TransProtocol.TCP)) {
Node receiver = subnet.getNetLayer(receiverId);
if (!hostQueues.containsKey(receiver))
hostQueues.put(receiver, new LinkedList<NetMessage>());
List<NetMessage> queuedMessages = hostQueues.get(receiver);
if (queuedMessages.isEmpty()) {
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(netMsg, getHost(),
Reason.SEND);
}
subnet.sendTCPMessage(this, receiver, netMsg.getSize());
}
queuedMessages.add(netMsg);
}
}
}
public boolean isMessageQueueEmpty(Node receiver) {
return hostQueues.get(receiver).isEmpty();
}
public double peekMessageQueue(Node receiver) {
return hostQueues.get(receiver).get(0).getSize();
}
public List<NetMessage> getViewOnMessageQueue(Node receiver) {
return Collections.unmodifiableList(hostQueues.get(receiver));
}
public NetMessage removeMessageFromQueue(Node receiver) {
return hostQueues.get(receiver).remove(0);
}
/**
* Returns the minimum end-to-end propagation delay in microseconds between
* this host, and the host the specified netID belongs to.
*
* @param netId
* the remote netID
* @return -1 if no information available, else the minimum delay (in
* microseconds)
*/
public long getMinimumPropagationDelay(NetID netId) {
if (subnet.getNetLayer(netId) != null)
return subnet.getLatencyModel().getLatency(this,
subnet.getNetLayer(netId));
else
return -1l;
}
@Override
public void goOffline() {
super.goOffline();
hostQueues.clear();
subnet.isOffline(this,
(HashSet<Connection>) outgoingConnections.clone(),
(HashSet<Connection>) incomingConnections.clone());
assert (incomingConnections.size() == 0);
assert (outgoingConnections.size() == 0);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Node) {
Node aNode = (Node) obj;
if (this.getLocalInetAddress().equals(aNode.getNetID())) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return getLocalInetAddress().hashCode();
}
}
package de.tud.kom.p2psim.impl.network.fairshare;
import org.apache.log4j.Logger;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.network.NetLatencyModel;
import de.tud.kom.p2psim.api.network.NetLayer;
import de.tud.kom.p2psim.impl.util.logging.SimLogger;
import de.tudarmstadt.maki.simonstrator.api.Time;
public class OptimizedLatencyModel implements NetLatencyModel {
private static Logger log = SimLogger
.getLogger(OptimizedLatencyModel.class);
@Override
public long getLatency(NetLayer sender, NetLayer receiver) {
Position senderPos = sender.getNetPosition();
Position receiverPos = receiver.getNetPosition();
double minRtt = senderPos.getDistance(receiverPos);
double receiveTime = minRtt / 2.0;
long latency = Math.round(receiveTime * Time.MILLISECOND);
log.info("Propagation Delay for " + sender.getNetID() + " to "
+ receiver.getNetID() + ": " + receiveTime + " ms");
return latency;
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment