OverSim
SimpleUDP.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2000 Institut fuer Telematik, Universitaet Karlsruhe
3 // Copyright (C) 2004,2005 Andras Varga
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 //
19 
25 //
26 // Author: Jochen Reber
27 // Rewrite: Andras Varga 2004,2005
28 // Modifications: Stephan Krause
29 //
30 
31 #include <omnetpp.h>
32 
33 #include <CommonMessages_m.h>
34 #include <GlobalNodeListAccess.h>
35 #include <GlobalStatisticsAccess.h>
36 
37 #include <SimpleInfo.h>
38 #include "UDPPacket.h"
39 #include "SimpleUDP.h"
40 #include "IPControlInfo.h"
41 #include "IPv6ControlInfo.h"
42 
43 #include "IPAddressResolver.h"
44 
45 #include "IPDatagram_m.h"
46 #include "IPv6Datagram_m.h"
47 
48 #include "ICMPMessage_m.h"
49 #include "ICMPv6Message_m.h"
50 
51 
52 #define EPHEMERAL_PORTRANGE_START 1024
53 #define EPHEMERAL_PORTRANGE_END 5000
54 
55 
57 
59 std::map<std::string, SimpleUDP::delayFaultTypeNum> SimpleUDP::delayFaultTypeMap;
60 
61 
62 static std::ostream & operator<<(std::ostream & os,
63  const SimpleUDP::SockDesc& sd)
64 {
65  os << "sockId=" << sd.sockId;
66  os << " appGateIndex=" << sd.appGateIndex;
67  os << " userId=" << sd.userId;
68  os << " localPort=" << sd.localPort;
69  if (sd.remotePort!=0)
70  os << " remotePort=" << sd.remotePort;
71  if (!sd.localAddr.isUnspecified())
72  os << " localAddr=" << sd.localAddr;
73  if (!sd.remoteAddr.isUnspecified())
74  os << " remoteAddr=" << sd.remoteAddr;
75  if (sd.interfaceId!=-1)
76  os << " interfaceId=" << sd.interfaceId;
77 
78  return os;
79 }
80 
81 static std::ostream & operator<<(std::ostream & os,
82  const SimpleUDP::SockDescList& list)
83 {
84  for (SimpleUDP::SockDescList::const_iterator i=list.begin();
85  i!=list.end(); ++i)
86  os << "sockId=" << (*i)->sockId << " ";
87  return os;
88 }
89 
90 
91 //--------
92 
94 {
95  globalStatistics = NULL;
96 }
97 
99 {
100 
101 }
102 
103 void SimpleUDP::initialize(int stage)
104 {
105  if(stage == MIN_STAGE_UNDERLAY) {
106  WATCH_PTRMAP(socketsByIdMap);
107  WATCH_MAP(socketsByPortMap);
108 
109  lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
110  icmp = NULL;
111  icmpv6 = NULL;
112 
113  numSent = 0;
114  numPassedUp = 0;
115  numDroppedWrongPort = 0;
116  numDroppedBadChecksum = 0;
117  numQueueLost = 0;
118  numPartitionLost = 0;
120  WATCH(numSent);
121  WATCH(numPassedUp);
122  WATCH(numDroppedWrongPort);
123  WATCH(numDroppedBadChecksum);
124  WATCH(numQueueLost);
125  WATCH(numPartitionLost);
126  WATCH(numDestUnavailableLost);
127 
130  constantDelay = par("constantDelay");
131  useCoordinateBasedDelay = par("useCoordinateBasedDelay");
132 
133  delayFaultTypeString = par("delayFaultType").stdstringValue();
134  delayFaultTypeMap["live_all"] = delayFaultLiveAll;
135  delayFaultTypeMap["live_planetlab"] = delayFaultLivePlanetlab;
136  delayFaultTypeMap["simulation"] = delayFaultSimulation;
137 
142  faultyDelay = true;
143  break;
144  default:
145  faultyDelay = false;
146  break;
147  }
148 
149  jitter = par("jitter");
150  enableAccessRouterTxQueue = par("enableAccessRouterTxQueue");
151  nodeEntry = NULL;
152  WATCH_PTR(nodeEntry);
153  }
154 }
155 
157 {
158  globalStatistics->addStdDev("SimpleUDP: Packets sent",
159  numSent);
160  globalStatistics->addStdDev("SimpleUDP: Packets dropped with bad checksum",
161  numDroppedBadChecksum);
162  globalStatistics->addStdDev("SimpleUDP: Packets dropped due to queue overflows",
163  numQueueLost);
164  globalStatistics->addStdDev("SimpleUDP: Packets dropped due to network partitions",
166  globalStatistics->addStdDev("SimpleUDP: Packets dropped due to unavailable destination",
168 }
169 
171 {
172  char buf[80];
173  sprintf(buf, "passed up: %d pks\nsent: %d pks", numPassedUp, numSent);
174  if (numDroppedWrongPort>0) {
175  sprintf(buf+strlen(buf), "\ndropped (no app): %d pks", numDroppedWrongPort);
176  getDisplayString().setTagArg("i",1,"red");
177  }
178  if (numQueueLost>0) {
179  sprintf(buf+strlen(buf), "\nlost (queue overflow): %d pks", numQueueLost);
180  getDisplayString().setTagArg("i",1,"red");
181  }
182  getDisplayString().setTagArg("t",0,buf);
183 }
184 
185 void SimpleUDP::sendUp(cPacket *payload, UDPControlInfo *udpCtrl, SockDesc *sd)
186 {
187  // send payload with UDPControlInfo up to the application
188  udpCtrl->setSockId(sd->sockId);
189  udpCtrl->setUserId(sd->userId);
190  payload->setControlInfo(udpCtrl);
191 
192  send(payload, "appOut", sd->appGateIndex);
193  numPassedUp++;
194 }
195 
196 void SimpleUDP::processUndeliverablePacket(cPacket *udpPacket, cPolymorphic *ctrl)
197 {
198  numDroppedWrongPort++;
199  EV << "[SimpleUDP::processUndeliverablePacket()]\n"
200  << " Dropped packet bound to unreserved port, ignoring ICMP error"
201  << endl;
202 
203  delete udpPacket;
204  delete ctrl;
205 }
206 
207 void SimpleUDP::processUDPPacket(cPacket *udpPacket)
208 {
209  int srcPort, destPort;
210  IPvXAddress srcAddr, destAddr;
211 
212  UDPControlInfo *ctrl = check_and_cast<UDPControlInfo *>(udpPacket->removeControlInfo());
213 
214  srcPort = ctrl->getSrcPort();
215  destPort = ctrl->getDestPort();
216 
217  srcAddr = ctrl->getSrcAddr();
218  destAddr = ctrl->getDestAddr();
219 
220  // simulate checksum: discard packet if it has bit error
221  EV << "Packet " << udpPacket->getName() << " received from network, dest port " << destPort << "\n";
222  if (udpPacket->hasBitError())
223  {
224  EV << "Packet has bit error, discarding\n";
225  delete udpPacket;
226  numDroppedBadChecksum++;
227  return;
228  }
229 
230  // send back ICMP error if no socket is bound to that port
231  SocketsByPortMap::iterator it = socketsByPortMap.find(destPort);
232  if (it==socketsByPortMap.end())
233  {
234  EV << "No socket registered on port " << destPort << "\n";
235  processUndeliverablePacket(udpPacket, ctrl);
236  return;
237  }
238 
239  SockDescList& list = it->second;
240  int matches = 0;
241 
242  // deliver a copy of the packet to each matching socket
243 
244  if (destAddr.isIPv6())
245  {
246  // packet size is increased in processMsgFromApp
247  udpPacket->setByteLength(udpPacket->getByteLength() - UDP_HEADER_BYTES - IPv6_HEADER_BYTES);
248  }
249  else
250  {
251  udpPacket->setByteLength(udpPacket->getByteLength() - UDP_HEADER_BYTES - IP_HEADER_BYTES);
252  }
253  for (SockDescList::iterator it=list.begin(); it!=list.end(); ++it)
254  {
255  SockDesc *sd = *it;
256  if (sd->onlyLocalPortIsSet || matchesSocket(sd, destAddr, srcAddr, srcPort))
257  {
258  if (matches == 0) {
259  sendUp(udpPacket, ctrl, sd);
260  } else {
261  opp_error("Edit SimpleUDP.cc to support multibinding.");
262  }
263  matches++;
264  }
265  }
266 
267  // send back ICMP error if there is no matching socket
268  if (matches==0)
269  {
270  EV << "None of the sockets on port " << destPort << " matches the packet\n";
271  processUndeliverablePacket(udpPacket, ctrl);
272  return;
273  }
274 }
275 
276 void SimpleUDP::processMsgFromApp(cPacket *appData)
277 {
278  cModule *node = getParentModule();
279 
280  IPvXAddress srcAddr, destAddr;
281 
282  UDPControlInfo *udpCtrl = check_and_cast<UDPControlInfo *>(appData->getControlInfo());
283 
284  srcAddr = udpCtrl->getSrcAddr();
285  destAddr = udpCtrl->getDestAddr();
286 
287  // add header byte length for the skipped IP and UDP headers (decreased in processUDPPacket)
288  if (destAddr.isIPv6()) {
289  appData->setByteLength(appData->getByteLength() + UDP_HEADER_BYTES + IPv6_HEADER_BYTES);
290  } else {
291  appData->setByteLength(appData->getByteLength() + UDP_HEADER_BYTES + IP_HEADER_BYTES);
292  }
293 
294  /* main modifications for SimpleUDP start here */
295 
296  SimpleInfo* info = dynamic_cast<SimpleInfo*>(globalNodeList->getPeerInfo(destAddr));
297  numSent++;
298 
299  if (info == NULL) {
300  EV << "[SimpleUDP::processMsgFromApp() @ " << IPAddressResolver().addressOf(node) << "]\n"
301  << " No route to host " << destAddr
302  << endl;
303 
304  delete appData;
306  return;
307  }
308 
309  SimpleNodeEntry* destEntry = info->getEntry();
310 
311  // calculate delay
312  simtime_t totalDelay = 0;
313  if (srcAddr != destAddr) {
315  if (faultyDelay) {
316  SimpleInfo* thisInfo = static_cast<SimpleInfo*>(globalNodeList->getPeerInfo(srcAddr));
317  temp = nodeEntry->calcDelay(appData, *destEntry,
318  !(thisInfo->getNpsLayer() == 0 ||
319  info->getNpsLayer() == 0)); //TODO
320  } else {
321  temp = nodeEntry->calcDelay(appData, *destEntry);
322  }
323  if (useCoordinateBasedDelay == false) {
324  totalDelay = constantDelay;
325  } else if (temp.second == false) {
326  EV << "[SimpleUDP::processMsgFromApp() @ " << IPAddressResolver().addressOf(node) << "]\n"
327  << " Send queue full: packet " << appData << " dropped"
328  << endl;
329 
330  delete appData;
331  numQueueLost++;
332  return;
333  } else {
334  totalDelay = temp.first;
335  }
336  }
337 
338  SimpleInfo* thisInfo = dynamic_cast<SimpleInfo*>(globalNodeList->getPeerInfo(srcAddr));
339 
340  if (!globalNodeList->areNodeTypesConnected(thisInfo->getTypeID(), info->getTypeID())) {
341  EV << "[SimpleUDP::processMsgFromApp() @ " << IPAddressResolver().addressOf(node) << "]\n"
342  << " Partition " << thisInfo->getTypeID() << "->" << info->getTypeID()
343  << " is not connected"
344  << endl;
345 
346  delete appData;
348  return;
349  }
350 
351  if (jitter) {
352  // jitter
353  //totalDelay += truncnormal(0, SIMTIME_DBL(totalDelay) * jitter);
354 
355  //workaround (bug in truncnormal(): sometimes returns inf)
356  double temp = truncnormal(0, SIMTIME_DBL(totalDelay) * jitter);
357  while (temp == INFINITY || temp != temp) { // reroll if temp is INF or NaN
358  std::cerr << "\n******* SimpleUDP: truncnormal() -> inf !!\n"
359  << std::endl;
360  temp = truncnormal(0, SIMTIME_DBL(totalDelay) * jitter);
361  }
362 
363  totalDelay += temp;
364  }
365 
366  BaseOverlayMessage* temp = NULL;
367 
368  if (ev.isGUI() && appData) {
369  if ((temp = dynamic_cast<BaseOverlayMessage*>(appData))) {
370  switch (temp->getStatType()) {
371  case APP_DATA_STAT:
372  appData->setKind(1);
373  break;
374  case APP_LOOKUP_STAT:
375  appData->setKind(2);
376  break;
377  case MAINTENANCE_STAT:
378  default:
379  appData->setKind(3);
380  break;
381  }
382  } else {
383  appData->setKind(1);
384  }
385  }
386 
387  EV << "[SimpleUDP::processMsgFromApp() @ " << IPAddressResolver().addressOf(node) << "]\n"
388  << " Packet " << appData << " sent with delay = " << SIMTIME_DBL(totalDelay)
389  << endl;
390 
391  //RECORD_STATS(globalStatistics->addStdDev("SimpleUDP: delay", totalDelay));
392 
393  /* main modifications for SimpleUDP end here */
394 
395  if (!destAddr.isIPv6()) {
396  // send directly to IPv4 gate of the destination node
397  sendDirect(appData, totalDelay, 0, destEntry->getUdpIPv4Gate());
398 
399  } else {
400  sendDirect(appData, totalDelay, 0, destEntry->getUdpIPv6Gate());
401  }
402 }
403 
404 
405 void SimpleUDP::handleMessage(cMessage *msg)
406 {
407  // received from IP layer
408  if (msg->arrivedOn("ipIn") || msg->arrivedOn("ipv6In"))
409  {
410  SimpleNodeEntry::SimpleDelay temp = std::make_pair(0, true);
411 
414  }
415 
416  if (temp.second == false) {
417  delete msg;
418  return;
419  }
420 
421  if (temp.first > 0) {
422  scheduleAt(simTime() + temp.first, msg);
423  } else if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
424  processICMPError(PK(msg));
425  else
426  processUDPPacket(PK(msg));
427  }
428  else if (msg->isSelfMessage())
429  {
430  if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
431  processICMPError(PK(msg));
432  else
433  processUDPPacket(PK(msg));
434 
435  }
436  else // received from application layer
437  {
438  if (msg->getKind()==UDP_C_DATA)
439  processMsgFromApp(PK(msg));
440  else
441  processCommandFromApp(msg);
442  }
443 
444  if (ev.isGUI())
446 }
447 
448 
450 {
451  nodeEntry = entry;
452 }