OverSim
SimpleTCP.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004 Andras Varga
3 // Copyright (C) 2010 Institut fuer Telematik, Karlsruher Institut fuer Technologie (KIT)
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 
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 <SimpleUDP.h>
39 #include "IPDatagram_m.h"
40 #include "TCPSegment.h"
41 #include "SimpleTCP.h"
42 #include "TCPCommand_m.h"
43 #include "IPControlInfo.h"
44 #include "IPv6ControlInfo.h"
45 #include "ICMPMessage_m.h"
46 #include "ICMPv6Message_m.h"
47 #include "IPAddressResolver.h"
48 #include "TCPSendQueue.h"
49 #include "TCPSACKRexmitQueue.h"
50 #include "TCPReceiveQueue.h"
51 #include "TCPAlgorithm.h"
52 
53 #define EPHEMERAL_PORTRANGE_START 1024
54 #define EPHEMERAL_PORTRANGE_END 5000
55 
57 
58 
59 
60 static std::ostream& operator<<(std::ostream& os, const TCP::SockPair& sp)
61 {
62  os << "loc=" << IPvXAddress(sp.localAddr) << ":" << sp.localPort << " "
63  << "rem=" << IPvXAddress(sp.remoteAddr) << ":" << sp.remotePort;
64  return os;
65 }
66 
67 static std::ostream& operator<<(std::ostream& os, const TCP::AppConnKey& app)
68 {
69  os << "connId=" << app.connId << " appGateIndex=" << app.appGateIndex;
70  return os;
71 }
72 
73 static std::ostream& operator<<(std::ostream& os, const TCPConnection& conn)
74 {
75  os << "connId=" << conn.connId << " " << TCPConnection::stateName(conn.getFsmState())
76  << " state={" << const_cast<TCPConnection&>(conn).getState()->info() << "}";
77  return os;
78 }
79 
80 void SimpleTCP::initialize(int stage)
81 {
82  if (stage == MIN_STAGE_UNDERLAY) {
83  lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
84  WATCH(lastEphemeralPort);
85 
86  WATCH_PTRMAP(tcpConnMap);
87  WATCH_PTRMAP(tcpAppConnMap);
88 
89  recordStatistics = par("recordStats");
90 
91  cModule *netw = simulation.getSystemModule();
92  testing = netw->hasPar("testing") && netw->par("testing").boolValue();
93  logverbose = !testing && netw->hasPar("logverbose") && netw->par("logverbose").boolValue();
94 
95  // start of modifications
96 
97  sad.numSent = 0;
98  sad.numQueueLost = 0;
101  WATCH(sad.numQueueLost);
102  WATCH(sad.numPartitionLost);
104 
107  sad.constantDelay = par("constantDelay");
108  sad.useCoordinateBasedDelay = par("useCoordinateBasedDelay");
109 
110  sad.delayFaultTypeString = par("delayFaultType").stdstringValue();
112  sad.delayFaultTypeMap["live_planetlab"] = sad.delayFaultLivePlanetlab;
114 
119  sad.faultyDelay = true;
120  break;
121  default:
122  sad.faultyDelay = false;
123  }
124 
125  sad.jitter = par("jitter");
126  sad.nodeEntry = NULL;
127  WATCH_PTR(sad.nodeEntry);
128  }
129 }
130 
132 {
133  sad.globalStatistics->addStdDev("SimpleTCP: Packets sent",
134  sad.numSent);
135  sad.globalStatistics->addStdDev("SimpleTCP: Packets dropped due to queue overflows",
136  sad.numQueueLost);
137  sad.globalStatistics->addStdDev("SimpleTCP: Packets dropped due to network partitions",
139  sad.globalStatistics->addStdDev("SimpleTCP: Packets dropped due to unavailable destination",
141 }
142 
143 void SimpleTCP::handleMessage(cMessage *msg)
144 {
145  if (msg->isSelfMessage())
146  {
147  SimpleTCPConnection *conn = (SimpleTCPConnection *) msg->getContextPointer();
148  bool ret = conn->processTimer(msg);
149  if (!ret)
150  removeConnection(conn);
151  }
152  else if (msg->arrivedOn("ipIn") || msg->arrivedOn("ipv6In"))
153  {
154  if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
155  {
156  tcpEV << "ICMP error received -- discarding\n"; // FIXME can ICMP packets really make it up to TCP???
157  delete msg;
158  }
159  else
160  {
161  // must be a TCPSegment
162  TCPSegment *tcpseg = check_and_cast<TCPSegment *>(msg);
163 
164  // get src/dest addresses
165  IPvXAddress srcAddr, destAddr;
166  if (dynamic_cast<IPControlInfo *>(tcpseg->getControlInfo())!=NULL)
167  {
168  IPControlInfo *controlInfo = (IPControlInfo *)tcpseg->removeControlInfo();
169  srcAddr = controlInfo->getSrcAddr();
170  destAddr = controlInfo->getDestAddr();
171  delete controlInfo;
172  }
173  else if (dynamic_cast<IPv6ControlInfo *>(tcpseg->getControlInfo())!=NULL)
174  {
175  IPv6ControlInfo *controlInfo = (IPv6ControlInfo *)tcpseg->removeControlInfo();
176  srcAddr = controlInfo->getSrcAddr();
177  destAddr = controlInfo->getDestAddr();
178  delete controlInfo;
179  }
180  else
181  {
182  error("(%s)%s arrived without control info", tcpseg->getClassName(), tcpseg->getName());
183  }
184 
185  // process segment
186  SimpleTCPConnection *conn = dynamic_cast<SimpleTCPConnection*>(findConnForSegment(tcpseg, srcAddr, destAddr));
187 
188  if (conn)
189  {
190  bool ret = conn->processTCPSegment(tcpseg, srcAddr, destAddr);
191  if (!ret)
192  removeConnection(conn);
193  }
194  else
195  {
196  segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr);
197  }
198  }
199  }
200  else // must be from app
201  {
202  TCPCommand *controlInfo = check_and_cast<TCPCommand *>(msg->getControlInfo());
203  int appGateIndex = msg->getArrivalGate()->getIndex();
204  int connId = controlInfo->getConnId();
205 
206  SimpleTCPConnection *conn = (SimpleTCPConnection*)findConnForApp(appGateIndex, connId);
207 
208  if (!conn)
209  {
210  conn = createConnection(appGateIndex, connId);
211 
212  // add into appConnMap here; it'll be added to connMap during processing
213  // the OPEN command in SimpleTCPConnection's processAppCommand().
214  AppConnKey key;
215  key.appGateIndex = appGateIndex;
216  key.connId = connId;
217  tcpAppConnMap[key] = conn;
218 
219  tcpEV << "TCP connection created for " << msg << "\n";
220  }
221  bool ret = conn->processAppCommand(msg);
222  if (!ret)
223  removeConnection(conn);
224  }
225 
226  if (ev.isGUI())
227  updateDisplayString();
228 }
229 
231 {
232  sad.nodeEntry = entry;
233 }
234 
235 SimpleTCPConnection *SimpleTCP::createConnection(int appGateIndex, int connId)
236 {
237  return new SimpleTCPConnection(this, appGateIndex, connId);
238 }
239 
240 void SimpleTCP::segmentArrivalWhileClosed(TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr)
241 {
243  tmp->segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr);
244  delete tmp;
245  delete tcpseg;
246 }
247 
249 {
250  SimpleTCPConnection *conn = new SimpleTCPConnection(tcpMain,appGateIndex,connId);
251 
252  // following code to be kept consistent with initConnection()
253  const char *sendQueueClass = sendQueue->getClassName();
254  conn->sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass));
255  conn->sendQueue->setConnection(conn);
256 
257  const char *receiveQueueClass = receiveQueue->getClassName();
258  conn->receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass));
259  conn->receiveQueue->setConnection(conn);
260 
261  // create SACK retransmit queue
262  rexmitQueue = new TCPSACKRexmitQueue();
263  rexmitQueue->setConnection(this);
264 
265  const char *tcpAlgorithmClass = tcpAlgorithm->getClassName();
266  conn->tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass));
267  conn->tcpAlgorithm->setConnection(conn);
268 
269  conn->state = conn->tcpAlgorithm->getStateVariables();
270  configureStateVariables();
271  conn->tcpAlgorithm->initialize();
272 
273  // put it into LISTEN, with our localAddr/localPort
274  conn->state->active = false;
275  conn->state->fork = true;
276  conn->localAddr = localAddr;
277  conn->localPort = localPort;
278  FSM_Goto(conn->fsm, TCP_S_LISTEN);
279 
280  return conn;
281 }
282 
283 
284 void SimpleTCPConnection::sendRst(uint32 seq, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
285 {
286  TCPSegment *tcpseg = createTCPSegment("RST");
287 
288  tcpseg->setSrcPort(srcPort);
289  tcpseg->setDestPort(destPort);
290 
291  tcpseg->setRstBit(true);
292  tcpseg->setSequenceNo(seq);
293 
294  // send it
295  SimpleTCPConnection::sendToIP(tcpseg, src, dest);
296 }
297 
298 void SimpleTCPConnection::sendRstAck(uint32 seq, uint32 ack, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
299 {
300  TCPSegment *tcpseg = createTCPSegment("RST+ACK");
301 
302  tcpseg->setSrcPort(srcPort);
303  tcpseg->setDestPort(destPort);
304 
305  tcpseg->setRstBit(true);
306  tcpseg->setAckBit(true);
307  tcpseg->setSequenceNo(seq);
308  tcpseg->setAckNo(ack);
309 
310  // send it
311  SimpleTCPConnection::sendToIP(tcpseg, src, dest);
312 }
313 
314 void SimpleTCPConnection::sendToIP(TCPSegment *tcpseg)
315 {
316  StatisticsAndDelay& sad = dynamic_cast<SimpleTCP*>(tcpMain)->sad;
317  // record seq (only if we do send data) and ackno
318  if (sndNxtVector && tcpseg->getPayloadLength()!=0)
319  sndNxtVector->record(tcpseg->getSequenceNo());
320  if (sndAckVector)
321  sndAckVector->record(tcpseg->getAckNo());
322 
323  // final touches on the segment before sending
324  tcpseg->setSrcPort(localPort);
325  tcpseg->setDestPort(remotePort);
326  ASSERT(tcpseg->getHeaderLength() >= TCP_HEADER_OCTETS); // TCP_HEADER_OCTETS = 20 (without options)
327  ASSERT(tcpseg->getHeaderLength() <= TCP_MAX_HEADER_OCTETS); // TCP_MAX_HEADER_OCTETS = 60
328 
329  // add header byte length for the skipped IP header
330  int ipHeaderBytes = 0;
331  if (remoteAddr.isIPv6()) {
332  ipHeaderBytes = IPv6_HEADER_BYTES;
333  } else {
334  ipHeaderBytes = IP_HEADER_BYTES;
335  }
336  tcpseg->setByteLength(tcpseg->getHeaderLength() +
337  tcpseg->getPayloadLength() + ipHeaderBytes);
338 
339  tcpEV << "Sending: ";
340  printSegmentBrief(tcpseg);
341 
342  // TBD reuse next function for sending
343 
344 
345  /* main modifications for SimpleTCP start here */
346 
347  const IPvXAddress& src = IPAddressResolver().addressOf(tcpMain->getParentModule());
348  //const IPvXAddress& src = localAddr;
349  const IPvXAddress& dest = remoteAddr;
350 
351  SimpleInfo* info = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(dest));
352  sad.numSent++;
353 
354  if (info == NULL) {
355  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
356  << " No route to host " << dest
357  << endl;
358 
359  delete tcpseg;
361  return;
362  }
363 
364  SimpleNodeEntry* destEntry = info->getEntry();
365 
366  // calculate delay
367  simtime_t totalDelay = 0;
368  if (src != dest) {
370  if (sad.faultyDelay) {
371  SimpleInfo* thisInfo = static_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
372  temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry,
373  !(thisInfo->getNpsLayer() == 0 ||
374  info->getNpsLayer() == 0)); //TODO
375  } else {
376  temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry);
377  }
378  if (sad.useCoordinateBasedDelay == false) {
379  totalDelay = sad.constantDelay;
380  } else if (temp.second == false) {
381  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
382  << " Send queue full: packet " << tcpseg << " dropped"
383  << endl;
384  delete tcpseg;
385  sad.numQueueLost++;
386  return;
387  } else {
388  totalDelay = temp.first;
389  }
390  }
391 
392  SimpleInfo* thisInfo = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
393 
394  if (!sad.globalNodeList->areNodeTypesConnected(thisInfo->getTypeID(), info->getTypeID())) {
395  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
396  << " Partition " << thisInfo->getTypeID() << "->" << info->getTypeID()
397  << " is not connected"
398  << endl;
399  delete tcpseg;
400  sad.numPartitionLost++;
401  return;
402  }
403 
404  if (sad.jitter) {
405  // jitter
406  //totalDelay += truncnormal(0, SIMTIME_DBL(totalDelay) * jitter);
407 
408  //workaround (bug in truncnormal(): sometimes returns inf)
409  double temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
410  while (temp == INFINITY || temp != temp) { // reroll if temp is INF or NaN
411  std::cerr << "\n******* SimpleTCPConnection: truncnormal() -> inf !!\n"
412  << std::endl;
413  temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
414  }
415 
416  totalDelay += temp;
417  }
418 
419 
420 
421  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
422  << " Packet " << tcpseg << " sent with delay = " << totalDelay
423  << endl;
424 
425  //RECORD_STATS(globalStatistics->addStdDev("SimpleTCP: delay", totalDelay));
426 
427 
428  /* main modifications for SimpleTCP end here */
429 
430  if (!remoteAddr.isIPv6())
431  {
432  // send over IPv4
433  IPControlInfo *controlInfo = new IPControlInfo();
434  controlInfo->setProtocol(IP_PROT_TCP);
435  controlInfo->setSrcAddr(src.get4());
436  controlInfo->setDestAddr(dest.get4());
437  tcpseg->setControlInfo(controlInfo);
438 
439  tcpMain->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv4Gate());
440  }
441  else
442  {
443  // send over IPv6
444  IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
445  controlInfo->setProtocol(IP_PROT_TCP);
446  controlInfo->setSrcAddr(src.get6());
447  controlInfo->setDestAddr(dest.get6());
448  tcpseg->setControlInfo(controlInfo);
449 
450  tcpMain->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv6Gate());
451  }
452 }
453 
454 void SimpleTCPConnection::sendToIP(TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
455 {
456 
457  /* main modifications for SimpleTCP start here */
458  StatisticsAndDelay& sad = dynamic_cast<SimpleTCP*>(tcpMain)->sad;
459 
460  SimpleInfo* info = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(dest));
461  sad.numSent++;
462 
463  if (info == NULL) {
464  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
465  << " No route to host " << dest
466  << endl;
467 
468  delete tcpseg;
470  return;
471  }
472 
473  SimpleNodeEntry* destEntry = info->getEntry();
474 
475  // calculate delay
476  simtime_t totalDelay = 0;
477  if (src != dest) {
479  if (sad.faultyDelay) {
480  SimpleInfo* thisInfo = static_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
481  temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry,
482  !(thisInfo->getNpsLayer() == 0 ||
483  info->getNpsLayer() == 0)); //TODO
484  } else {
485  temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry);
486  }
487  if (sad.useCoordinateBasedDelay == false) {
488  totalDelay = sad.constantDelay;
489  } else if (temp.second == false) {
490  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
491  << " Send queue full: packet " << tcpseg << " dropped"
492  << endl;
493  delete tcpseg;
494  sad.numQueueLost++;
495  return;
496  } else {
497  totalDelay = temp.first;
498  }
499  }
500 
501  SimpleInfo* thisInfo = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
502 
503  if (!sad.globalNodeList->areNodeTypesConnected(thisInfo->getTypeID(), info->getTypeID())) {
504  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
505  << " Partition " << thisInfo->getTypeID() << "->" << info->getTypeID()
506  << " is not connected"
507  << endl;
508  delete tcpseg;
509  sad.numPartitionLost++;
510  return;
511  }
512 
513  if (sad.jitter) {
514  // jitter
515  //totalDelay += truncnormal(0, SIMTIME_DBL(totalDelay) * jitter);
516 
517  //workaround (bug in truncnormal(): sometimes returns inf)
518  double temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
519  while (temp == INFINITY || temp != temp) { // reroll if temp is INF or NaN
520  std::cerr << "\n******* SimpleTCPConnection: truncnormal() -> inf !!\n"
521  << std::endl;
522  temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
523  }
524 
525  totalDelay += temp;
526  }
527 
528 
529 
530  EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
531  << " Packet " << tcpseg << " sent with delay = " << totalDelay
532  << endl;
533 
534  //RECORD_STATS(globalStatistics->addStdDev("SimpleTCP: delay", totalDelay));
535 
536 
537  /* main modifications for SimpleTCP end here */
538 
539  tcpEV << "Sending: ";
540  printSegmentBrief(tcpseg);
541 
542  if (!dest.isIPv6())
543  {
544  // send over IPv4
545  IPControlInfo *controlInfo = new IPControlInfo();
546  controlInfo->setProtocol(IP_PROT_TCP);
547  controlInfo->setSrcAddr(src.get4());
548  controlInfo->setDestAddr(dest.get4());
549  tcpseg->setControlInfo(controlInfo);
550 
551  check_and_cast<TCP *>(simulation.getContextModule())->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv4Gate());
552  }
553  else
554  {
555  // send over IPv6
556  IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
557  controlInfo->setProtocol(IP_PROT_TCP);
558  controlInfo->setSrcAddr(src.get6());
559  controlInfo->setDestAddr(dest.get6());
560  tcpseg->setControlInfo(controlInfo);
561 
562  check_and_cast<TCP *>(simulation.getContextModule())->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv6Gate());
563  }
564 }