INET Framework for OMNeT++/OMNEST
inet::tcp::TCPConnection Class Reference

Manages a TCP connection. More...

#include <TCPConnection.h>

Inheritance diagram for inet::tcp::TCPConnection:

Public Member Functions

virtual void sendAck ()
 Utility: send ACK. More...
 
virtual bool sendData (bool fullSegmentsOnly, uint32 congestionWindow)
 Utility: Send data from sendQueue, at most congestionWindow. More...
 
virtual bool sendProbe ()
 Utility: sends 1 bytes as "probe", called by the "persist" mechanism. More...
 
virtual void retransmitOneSegment (bool called_at_rto)
 Utility: retransmit one segment from snd_una. More...
 
virtual void retransmitData ()
 Utility: retransmit all from snd_una to snd_max. More...
 
virtual void sendRst (uint32 seqNo)
 Utility: sends RST. More...
 
virtual void sendRst (uint32 seq, L3Address src, L3Address dest, int srcPort, int destPort)
 Utility: sends RST; does not use connection state. More...
 
virtual void sendRstAck (uint32 seq, uint32 ack, L3Address src, L3Address dest, int srcPort, int destPort)
 Utility: sends RST+ACK; does not use connection state. More...
 
virtual void sendFin ()
 Utility: sends FIN. More...
 
virtual void sendSegment (uint32 bytes)
 Utility: sends one segment of 'bytes' bytes from snd_nxt, and advances snd_nxt. More...
 
virtual void sendToIP (TCPSegment *tcpseg)
 Utility: adds control info to segment and sends it to IP. More...
 
virtual TCPSegmentcreateTCPSegment (const char *name)
 Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment. More...
 
virtual void startSynRexmitTimer ()
 Utility: start SYN-REXMIT timer. More...
 
virtual void signalConnectionTimeout ()
 Utility: signal to user that connection timed out. More...
 
void scheduleTimeout (cMessage *msg, simtime_t timeout)
 Utility: start a timer. More...
 
virtual void printConnBrief () const
 Utility: prints local/remote addr/port and app gate index/connId. More...
 
virtual void updateRcvQueueVars ()
 Utility: update receiver queue related variables and statistics - called before setting rcv_wnd. More...
 
virtual bool hasEnoughSpaceForSegmentInReceiveQueue (TCPSegment *tcpseg)
 Utility: returns true when receive queue has enough space for store the tcpseg. More...
 
virtual unsigned short updateRcvWnd ()
 Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled. More...
 
virtual void updateWndInfo (TCPSegment *tcpseg, bool doAlways=false)
 Utility: update window information (snd_wnd, snd_wl1, snd_wl2) More...
 
 TCPConnection (TCP *mod, int appGateIndex, int connId)
 The "normal" constructor. More...
 
 TCPConnection ()
 Note: this default ctor is NOT used to create live connections, only temporary ones so that TCPMain can invoke their segmentArrivalWhileClosed(). More...
 
virtual ~TCPConnection ()
 Destructor. More...
 
int getLocalPort () const
 
L3Address getLocalAddress () const
 
int getRemotePort () const
 
L3Address getRemoteAddress () const
 
virtual void segmentArrivalWhileClosed (TCPSegment *tcpseg, L3Address src, L3Address dest)
 This method gets invoked from TCP when a segment arrives which doesn't belong to an existing connection. More...
 
virtual bool processTimer (cMessage *msg)
 Process self-messages (timers). More...
 
virtual bool processTCPSegment (TCPSegment *tcpSeg, L3Address srcAddr, L3Address destAddr)
 Process incoming TCP segment. More...
 
virtual bool processAppCommand (cMessage *msg)
 Process commands from the application. More...
 
virtual bool isLost (uint32 seqNum)
 For SACK TCP. More...
 
virtual void setPipe ()
 For SACK TCP. More...
 
virtual bool nextSeg (uint32 &seqNum)
 For SACK TCP. More...
 
virtual void sendDataDuringLossRecoveryPhase (uint32 congestionWindow)
 Utility: send data during Loss Recovery phase (if SACK is enabled). More...
 
virtual void sendSegmentDuringLossRecoveryPhase (uint32 seqNum)
 Utility: send segment during Loss Recovery phase (if SACK is enabled). More...
 
virtual void sendOneNewSegment (bool fullSegmentsOnly, uint32 congestionWindow)
 Utility: send one new segment from snd_max if allowed (RFC 3042). More...
 
virtual bool isSendQueueEmpty ()
 Utility: checks if send queue is empty (no data to send). More...
 
Various getters
int getFsmState () const
 
TCPStateVariablesgetState ()
 
TCPSendQueuegetSendQueue ()
 
TCPSACKRexmitQueuegetRexmitQueue ()
 
TCPReceiveQueuegetReceiveQueue ()
 
TCPAlgorithmgetTcpAlgorithm ()
 
TCPgetTcpMain ()
 

Static Public Member Functions

static void printSegmentBrief (TCPSegment *tcpseg)
 Utility: prints important header fields. More...
 
static const char * stateName (int state)
 Utility: returns name of TCP_S_xxx constants. More...
 
static const char * eventName (int event)
 Utility: returns name of TCP_E_xxx constants. More...
 
static const char * indicationName (int code)
 Utility: returns name of TCP_I_xxx constants. More...
 
static const char * optionName (int option)
 Utility: returns name of TCPOPTION_xxx constants. More...
 
static uint32 convertSimtimeToTS (simtime_t simtime)
 Utility: converts a given simtime to a timestamp (TS). More...
 
static simtime_t convertTSToSimtime (uint32 timestamp)
 Utility: converts a given timestamp (TS) to a simtime. More...
 

Public Attributes

int appGateIndex = -1
 
int connId = -1
 
L3Address localAddr
 
L3Address remoteAddr
 
int localPort = -1
 
int remotePort = -1
 
TCPSACKRexmitQueuerexmitQueue = nullptr
 

Protected Member Functions

virtual TCPConnectioncloneListeningConnection ()
 Utility: clone a listening connection. More...
 
virtual void initConnection (TCPOpenCommand *openCmd)
 Utility: creates send/receive queues and tcpAlgorithm. More...
 
virtual void configureStateVariables ()
 Utility: set snd_mss, rcv_wnd and sack in newly created state variables block. More...
 
virtual void selectInitialSeqNum ()
 Utility: generates ISS and initializes corresponding state variables. More...
 
virtual bool isSegmentAcceptable (TCPSegment *tcpseg) const
 Utility: check if segment is acceptable (all bytes are in receive window) More...
 
virtual void sendSyn ()
 Utility: send SYN. More...
 
virtual void sendSynAck ()
 Utility: send SYN+ACK. More...
 
virtual void readHeaderOptions (TCPSegment *tcpseg)
 Utility: readHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implemented) More...
 
virtual TCPSegment writeHeaderOptions (TCPSegment *tcpseg)
 Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implemented) More...
 
virtual TCPSegment addSacks (TCPSegment *tcpseg)
 Utility: adds SACKs to segments header options field. More...
 
virtual uint32 getTSval (TCPSegment *tcpseg) const
 Utility: get TSval from segments TS header option. More...
 
virtual uint32 getTSecr (TCPSegment *tcpseg) const
 Utility: get TSecr from segments TS header option. More...
 
cMessage * cancelEvent (cMessage *msg)
 Utility: cancel a timer. More...
 
virtual void sendToApp (cMessage *msg)
 Utility: sends packet to application. More...
 
virtual void sendIndicationToApp (int code, const int id=0)
 Utility: sends status indication (TCP_I_xxx) to application. More...
 
virtual void sendEstabIndicationToApp ()
 Utility: sends TCP_I_ESTABLISHED indication with TCPConnectInfo to application. More...
 
FSM transitions: analysing events and executing state transitions
virtual TCPEventCode preanalyseAppCommandEvent (int commandCode)
 Maps app command codes (msg kind of app command msgs) to TCP_E_xxx event codes. More...
 
virtual bool performStateTransition (const TCPEventCode &event)
 Implemements the pure TCP state machine. More...
 
virtual void stateEntered (int state, int oldState, TCPEventCode event)
 Perform cleanup necessary when entering a new state, e.g. More...
 
Processing app commands. Invoked from processAppCommand().
virtual void process_OPEN_ACTIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
virtual void process_OPEN_PASSIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
virtual void process_SEND (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
virtual void process_CLOSE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
virtual void process_ABORT (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
virtual void process_STATUS (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
virtual void process_QUEUE_BYTES_LIMIT (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
virtual void process_READ_REQUEST (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
 
Processing TCP segment arrivals. Invoked from processTCPSegment().
virtual bool tryFastRoute (TCPSegment *tcpseg)
 Shortcut to process most common case as fast as possible. More...
 
virtual TCPEventCode process_RCV_SEGMENT (TCPSegment *tcpseg, L3Address src, L3Address dest)
 Process incoming TCP segment. More...
 
virtual TCPEventCode processSegmentInListen (TCPSegment *tcpseg, L3Address src, L3Address dest)
 
virtual TCPEventCode processSegmentInSynSent (TCPSegment *tcpseg, L3Address src, L3Address dest)
 
virtual TCPEventCode processSegment1stThru8th (TCPSegment *tcpseg)
 
virtual TCPEventCode processRstInSynReceived (TCPSegment *tcpseg)
 
virtual bool processAckInEstabEtc (TCPSegment *tcpseg)
 
Processing of TCP options. Invoked from readHeaderOptions(). Return value indicates whether the option was valid.
virtual bool processMSSOption (TCPSegment *tcpseg, const TCPOptionMaxSegmentSize &option)
 
virtual bool processWSOption (TCPSegment *tcpseg, const TCPOptionWindowScale &option)
 
virtual bool processSACKPermittedOption (TCPSegment *tcpseg, const TCPOptionSackPermitted &option)
 
virtual bool processSACKOption (TCPSegment *tcpseg, const TCPOptionSack &option)
 
virtual bool processTSOption (TCPSegment *tcpseg, const TCPOptionTimestamp &option)
 
Processing timeouts. Invoked from processTimer().
virtual void process_TIMEOUT_2MSL ()
 
virtual void process_TIMEOUT_CONN_ESTAB ()
 
virtual void process_TIMEOUT_FIN_WAIT_2 ()
 
virtual void process_TIMEOUT_SYN_REXMIT (TCPEventCode &event)
 

Static Protected Member Functions

static void sendToIP (TCPSegment *tcpseg, L3Address src, L3Address dest)
 Utility: send IP packet. More...
 

Protected Attributes

TCPtcpMain = nullptr
 
cFSM fsm
 
TCPStateVariablesstate = nullptr
 
TCPSendQueuesendQueue = nullptr
 
TCPReceiveQueuereceiveQueue = nullptr
 
TCPDataTransferMode transferMode = TCP_TRANSFER_UNDEFINED
 
TCPAlgorithmtcpAlgorithm = nullptr
 
cMessage * the2MSLTimer = nullptr
 
cMessage * connEstabTimer = nullptr
 
cMessage * finWait2Timer = nullptr
 
cMessage * synRexmitTimer = nullptr
 
cOutVector * sndWndVector = nullptr
 
cOutVector * rcvWndVector = nullptr
 
cOutVector * rcvAdvVector = nullptr
 
cOutVector * sndNxtVector = nullptr
 
cOutVector * sndAckVector = nullptr
 
cOutVector * rcvSeqVector = nullptr
 
cOutVector * rcvAckVector = nullptr
 
cOutVector * unackedVector = nullptr
 
cOutVector * dupAcksVector = nullptr
 
cOutVector * pipeVector = nullptr
 
cOutVector * sndSacksVector = nullptr
 
cOutVector * rcvSacksVector = nullptr
 
cOutVector * rcvOooSegVector = nullptr
 
cOutVector * rcvNASegVector = nullptr
 
cOutVector * sackedBytesVector = nullptr
 
cOutVector * tcpRcvQueueBytesVector = nullptr
 
cOutVector * tcpRcvQueueDropsVector = nullptr
 

Detailed Description

Manages a TCP connection.

This class itself implements the TCP state machine as well as handling control PDUs (SYN, SYN+ACK, RST, FIN, etc.), timers (2MSL, CONN-ESTAB, FIN-WAIT-2) and events (OPEN, SEND, etc) associated with TCP state changes.

The implementation largely follows the functional specification at the end of RFC 793. Code comments extensively quote RFC 793 to make it easier to understand.

TCPConnection objects are not used alone – they are instantiated and managed by a TCP module.

TCPConnection "outsources" several tasks to objects subclassed from TCPSendQueue, TCPReceiveQueue and TCPAlgorithm; see overview of this with TCP documentation.

Connection variables (TCB) are kept in TCPStateVariables. TCPAlgorithm implementations can extend TCPStateVariables to add their own stuff (see TCPAlgorithm::createStateVariables() factory method.)

The "entry points" of TCPConnnection from TCP are:

All three methods follow a common structure:

  1. dispatch to specific methods. For example, processAppCommand() invokes one of process_OPEN_ACTIVE(), process_OPEN_PASSIVE() or process_SEND(), etc., and processTCPSegment() dispatches to processSegmentInListen(), processSegmentInSynSent() or processSegment1stThru8th(). Those methods will do the REAL JOB.
  2. after they return, we'll know the state machine event (TCPEventCode, TCP_E_xxx) for sure, so we can:
  3. invoke performStateTransition() which executes the necessary state transition (for example, TCP_E_RCV_SYN will take the state machine from TCP_S_LISTEN to TCP_S_SYN_RCVD). No other actions are taken in this step.
  4. if there was a state change (for example, we entered the TCP_S_ESTABLISHED state), performStateTransition() invokes stateEntered(), which performs some necessary housekeeping (cancel the CONN-ESTAB timer).

When the CLOSED state is reached, TCP will delete the TCPConnection object.

Constructor & Destructor Documentation

inet::tcp::TCPConnection::TCPConnection ( TCP mod,
int  appGateIndex,
int  connId 
)

The "normal" constructor.

184 {
185  tcpMain = _mod;
186  appGateIndex = _appGateIndex;
187  connId = _connId;
188 
189  char fsmname[24];
190  sprintf(fsmname, "fsm-%d", connId);
191  fsm.setName(fsmname);
192  fsm.setState(TCP_S_INIT);
193 
194  // queues and algorithm will be created on active or passive open
195 
196  the2MSLTimer = new cMessage("2MSL");
197  connEstabTimer = new cMessage("CONN-ESTAB");
198  finWait2Timer = new cMessage("FIN-WAIT-2");
199  synRexmitTimer = new cMessage("SYN-REXMIT");
200 
201  the2MSLTimer->setContextPointer(this);
202  connEstabTimer->setContextPointer(this);
203  finWait2Timer->setContextPointer(this);
204  synRexmitTimer->setContextPointer(this);
205 
206  // statistics
207  if (getTcpMain()->recordStatistics) {
208  sndWndVector = new cOutVector("send window");
209  rcvWndVector = new cOutVector("receive window");
210  rcvAdvVector = new cOutVector("advertised window");
211  sndNxtVector = new cOutVector("sent seq");
212  sndAckVector = new cOutVector("sent ack");
213  rcvSeqVector = new cOutVector("rcvd seq");
214  rcvAckVector = new cOutVector("rcvd ack");
215  unackedVector = new cOutVector("unacked bytes");
216  dupAcksVector = new cOutVector("rcvd dupAcks");
217  pipeVector = new cOutVector("pipe");
218  sndSacksVector = new cOutVector("sent sacks");
219  rcvSacksVector = new cOutVector("rcvd sacks");
220  rcvOooSegVector = new cOutVector("rcvd oooseg");
221  rcvNASegVector = new cOutVector("rcvd naseg");
222  sackedBytesVector = new cOutVector("rcvd sackedBytes");
223  tcpRcvQueueBytesVector = new cOutVector("tcpRcvQueueBytes");
224  tcpRcvQueueDropsVector = new cOutVector("tcpRcvQueueDrops");
225  }
226 }
cOutVector * rcvOooSegVector
Definition: TCPConnection.h:370
cOutVector * rcvSeqVector
Definition: TCPConnection.h:362
int appGateIndex
Definition: TCPConnection.h:320
cOutVector * sackedBytesVector
Definition: TCPConnection.h:373
cOutVector * sndNxtVector
Definition: TCPConnection.h:360
cOutVector * unackedVector
Definition: TCPConnection.h:364
TCP * getTcpMain()
Definition: TCPConnection.h:609
cFSM fsm
Definition: TCPConnection.h:333
cOutVector * sndAckVector
Definition: TCPConnection.h:361
Definition: TCPConnection.h:63
cOutVector * tcpRcvQueueDropsVector
Definition: TCPConnection.h:375
cMessage * the2MSLTimer
Definition: TCPConnection.h:351
TCP * tcpMain
Definition: TCPConnection.h:330
cOutVector * rcvAdvVector
Definition: TCPConnection.h:359
cOutVector * rcvAckVector
Definition: TCPConnection.h:363
cMessage * finWait2Timer
Definition: TCPConnection.h:353
cMessage * connEstabTimer
Definition: TCPConnection.h:352
cOutVector * rcvNASegVector
Definition: TCPConnection.h:371
cOutVector * tcpRcvQueueBytesVector
Definition: TCPConnection.h:374
cOutVector * sndWndVector
Definition: TCPConnection.h:357
cOutVector * dupAcksVector
Definition: TCPConnection.h:366
cOutVector * rcvSacksVector
Definition: TCPConnection.h:369
cOutVector * rcvWndVector
Definition: TCPConnection.h:358
cOutVector * sndSacksVector
Definition: TCPConnection.h:368
cMessage * synRexmitTimer
Definition: TCPConnection.h:354
int connId
Definition: TCPConnection.h:321
cOutVector * pipeVector
Definition: TCPConnection.h:367
inet::tcp::TCPConnection::TCPConnection ( )

Note: this default ctor is NOT used to create live connections, only temporary ones so that TCPMain can invoke their segmentArrivalWhileClosed().

Referenced by cloneListeningConnection().

173 {
174  // Note: this ctor is NOT used to create live connections, only
175  // temporary ones to invoke segmentArrivalWhileClosed() on
177 }
Definition: TCPCommand_m.h:255
TCPDataTransferMode transferMode
Definition: TCPConnection.h:341
inet::tcp::TCPConnection::~TCPConnection ( )
virtual

Destructor.

229 {
230  delete sendQueue;
231  delete rexmitQueue;
232  delete receiveQueue;
233  delete tcpAlgorithm;
234  delete state;
235 
236  if (the2MSLTimer)
237  delete cancelEvent(the2MSLTimer);
238  if (connEstabTimer)
239  delete cancelEvent(connEstabTimer);
240  if (finWait2Timer)
241  delete cancelEvent(finWait2Timer);
242  if (synRexmitTimer)
243  delete cancelEvent(synRexmitTimer);
244 
245  // statistics
246  delete sndWndVector;
247  delete rcvWndVector;
248  delete rcvAdvVector;
249  delete sndNxtVector;
250  delete sndAckVector;
251  delete rcvSeqVector;
252  delete rcvAckVector;
253  delete unackedVector;
254  delete dupAcksVector;
255  delete sndSacksVector;
256  delete rcvSacksVector;
257  delete rcvOooSegVector;
258  delete rcvNASegVector;
259  delete tcpRcvQueueBytesVector;
260  delete tcpRcvQueueDropsVector;
261  delete pipeVector;
262  delete sackedBytesVector;
263 }
cOutVector * rcvOooSegVector
Definition: TCPConnection.h:370
cOutVector * rcvSeqVector
Definition: TCPConnection.h:362
cOutVector * sackedBytesVector
Definition: TCPConnection.h:373
cOutVector * sndNxtVector
Definition: TCPConnection.h:360
cMessage * cancelEvent(cMessage *msg)
Utility: cancel a timer.
Definition: TCPConnection.h:529
cOutVector * unackedVector
Definition: TCPConnection.h:364
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
cOutVector * sndAckVector
Definition: TCPConnection.h:361
cOutVector * tcpRcvQueueDropsVector
Definition: TCPConnection.h:375
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
cMessage * the2MSLTimer
Definition: TCPConnection.h:351
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
cOutVector * rcvAdvVector
Definition: TCPConnection.h:359
cOutVector * rcvAckVector
Definition: TCPConnection.h:363
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
cMessage * finWait2Timer
Definition: TCPConnection.h:353
cMessage * connEstabTimer
Definition: TCPConnection.h:352
cOutVector * rcvNASegVector
Definition: TCPConnection.h:371
cOutVector * tcpRcvQueueBytesVector
Definition: TCPConnection.h:374
cOutVector * sndWndVector
Definition: TCPConnection.h:357
cOutVector * dupAcksVector
Definition: TCPConnection.h:366
cOutVector * rcvSacksVector
Definition: TCPConnection.h:369
cOutVector * rcvWndVector
Definition: TCPConnection.h:358
cOutVector * sndSacksVector
Definition: TCPConnection.h:368
cMessage * synRexmitTimer
Definition: TCPConnection.h:354
cOutVector * pipeVector
Definition: TCPConnection.h:367

Member Function Documentation

TCPSegment inet::tcp::TCPConnection::addSacks ( TCPSegment tcpseg)
protectedvirtual

Utility: adds SACKs to segments header options field.

Referenced by writeHeaderOptions().

442 {
443  uint options_len = 0;
444  uint used_options_len = tcpseg->getHeaderOptionArrayLength();
445  bool dsack_inserted = false; // set if dsack is subsets of a bigger sack block recently reported
446 
447  uint32 start = state->start_seqno;
448  uint32 end = state->end_seqno;
449 
450  // delete old sacks (below rcv_nxt), delete duplicates and print previous status of sacks_array:
451  auto it = state->sacks_array.begin();
452  EV_INFO << "Previous status of sacks_array: \n" << ((it != state->sacks_array.end()) ? "" : "\t EMPTY\n");
453 
454  while (it != state->sacks_array.end()) {
455  if (seqLE(it->getEnd(), state->rcv_nxt) || it->empty()) {
456  EV_DETAIL << "\t SACK in sacks_array: " << " " << it->str() << " delete now\n";
457  it = state->sacks_array.erase(it);
458  }
459  else {
460  EV_DETAIL << "\t SACK in sacks_array: " << " " << it->str() << endl;
461 
462  ASSERT(seqGE(it->getStart(), state->rcv_nxt));
463 
464  it++;
465  }
466  }
467 
468  if (used_options_len > TCP_OPTIONS_MAX_SIZE - TCP_OPTION_SACK_MIN_SIZE) {
469  EV_ERROR << "ERROR: Failed to addSacks - at least 10 free bytes needed for SACK - used_options_len=" << used_options_len << endl;
470 
471  //reset flags:
472  state->snd_sack = false;
473  state->snd_dsack = false;
474  state->start_seqno = 0;
475  state->end_seqno = 0;
476  return *tcpseg;
477  }
478 
479  if (start != end) {
480  if (state->snd_dsack) { // SequenceNo < rcv_nxt
481  // RFC 2883, page 3:
482  // "(3) The left edge of the D-SACK block specifies the first sequence
483  // number of the duplicate contiguous sequence, and the right edge of
484  // the D-SACK block specifies the sequence number immediately following
485  // the last sequence in the duplicate contiguous sequence."
486  if (seqLess(start, state->rcv_nxt) && seqLess(state->rcv_nxt, end))
487  end = state->rcv_nxt;
488 
489  dsack_inserted = true;
490  Sack nSack(start, end);
491  state->sacks_array.push_front(nSack);
492  EV_DETAIL << "inserted DSACK entry: " << nSack.str() << "\n";
493  }
494  else {
495  uint32 contStart = receiveQueue->getLE(start);
496  uint32 contEnd = receiveQueue->getRE(end);
497 
498  Sack newSack(contStart, contEnd);
499  state->sacks_array.push_front(newSack);
500  EV_DETAIL << "Inserted SACK entry: " << newSack.str() << "\n";
501  }
502 
503  // RFC 2883, page 3:
504  // "(3) The left edge of the D-SACK block specifies the first sequence
505  // number of the duplicate contiguous sequence, and the right edge of
506  // the D-SACK block specifies the sequence number immediately following
507  // the last sequence in the duplicate contiguous sequence."
508 
509  // RFC 2018, page 4:
510  // "* The first SACK block (i.e., the one immediately following the
511  // kind and length fields in the option) MUST specify the contiguous
512  // block of data containing the segment which triggered this ACK,
513  // unless that segment advanced the Acknowledgment Number field in
514  // the header. This assures that the ACK with the SACK option
515  // reflects the most recent change in the data receiver's buffer
516  // queue."
517 
518  // RFC 2018, page 4:
519  // "* The first SACK block (i.e., the one immediately following the
520  // kind and length fields in the option) MUST specify the contiguous
521  // block of data containing the segment which triggered this ACK,"
522 
523  // RFC 2883, page 3:
524  // "(4) If the D-SACK block reports a duplicate contiguous sequence from
525  // a (possibly larger) block of data in the receiver's data queue above
526  // the cumulative acknowledgement, then the second SACK block in that
527  // SACK option should specify that (possibly larger) block of data.
528  //
529  // (5) Following the SACK blocks described above for reporting duplicate
530  // segments, additional SACK blocks can be used for reporting additional
531  // blocks of data, as specified in RFC 2018."
532 
533  // RFC 2018, page 4:
534  // "* The SACK option SHOULD be filled out by repeating the most
535  // recently reported SACK blocks (based on first SACK blocks in
536  // previous SACK options) that are not subsets of a SACK block
537  // already included in the SACK option being constructed."
538 
539  it = state->sacks_array.begin();
540  if (dsack_inserted)
541  it++;
542 
543  for ( ; it != state->sacks_array.end(); it++) {
544  ASSERT(!it->empty());
545 
546  auto it2 = it;
547  it2++;
548  while (it2 != state->sacks_array.end()) {
549  if (it->contains(*it2)) {
550  EV_DETAIL << "sack matched, delete contained : a=" << it->str() << ", b=" << it2->str() << endl;
551  it2 = state->sacks_array.erase(it2);
552  }
553  else
554  it2++;
555  }
556  }
557  }
558 
559  uint n = state->sacks_array.size();
560 
561  uint maxnode = ((TCP_OPTIONS_MAX_SIZE - used_options_len) - 2) / 8; // 2: option header, 8: size of one sack entry
562 
563  if (n > maxnode)
564  n = maxnode;
565 
566  if (n == 0) {
567  if (dsack_inserted)
568  state->sacks_array.pop_front(); // delete DSACK entry
569 
570  // reset flags:
571  state->snd_sack = false;
572  state->snd_dsack = false;
573  state->start_seqno = 0;
574  state->end_seqno = 0;
575 
576  return *tcpseg;
577  }
578 
579  uint optArrSize = tcpseg->getHeaderOptionArraySize();
580 
581  uint optArrSizeAligned = optArrSize;
582 
583  while (used_options_len % 4 != 2) {
584  used_options_len++;
585  optArrSizeAligned++;
586  }
587 
588  while (optArrSize < optArrSizeAligned) {
589  tcpseg->addHeaderOption(new TCPOptionNop());
590  optArrSize++;
591  }
592 
593  ASSERT(used_options_len % 4 == 2);
594 
595  TCPOptionSack *option = new TCPOptionSack();
596  option->setLength(8 * n + 2);
597  option->setSackItemArraySize(n);
598 
599  // write sacks from sacks_array to options
600  uint counter = 0;
601 
602  for (it = state->sacks_array.begin(); it != state->sacks_array.end() && counter < n; it++) {
603  ASSERT(it->getStart() != it->getEnd());
604  option->setSackItem(counter++, *it);
605  }
606 
607  // independent of "n" we always need 2 padding bytes (NOP) to make: (used_options_len % 4 == 0)
608  options_len = used_options_len + 8 * n + 2; // 8 bytes for each SACK (n) + 2 bytes for kind&length
609 
610  ASSERT(options_len <= TCP_OPTIONS_MAX_SIZE); // Options length allowed? - maximum: 40 Bytes
611 
612  tcpseg->addHeaderOption(option);
613 
614  // update number of sent sacks
615  state->snd_sacks += n;
616 
617  if (sndSacksVector)
618  sndSacksVector->record(state->snd_sacks);
619 
620  EV_INFO << n << " SACK(s) added to header:\n";
621 
622  for (uint t = 0; t < n; t++) {
623  EV_INFO << t << ". SACK:" << " [" << option->getSackItem(t).getStart() << ".." << option->getSackItem(t).getEnd() << ")";
624 
625  if (t == 0) {
626  if (state->snd_dsack)
627  EV_INFO << " (D-SACK)";
628  else if (seqLE(option->getSackItem(t).getEnd(), state->rcv_nxt)) {
629  EV_INFO << " (received segment filled out a gap)";
630  state->snd_dsack = true; // Note: Set snd_dsack to delete first sack from sacks_array
631  }
632  }
633 
634  EV_INFO << endl;
635  }
636 
637  // RFC 2883, page 3:
638  // "(1) A D-SACK block is only used to report a duplicate contiguous
639  // sequence of data received by the receiver in the most recent packet.
640  //
641  // (2) Each duplicate contiguous sequence of data received is reported
642  // in at most one D-SACK block. (I.e., the receiver sends two identical
643  // D-SACK blocks in subsequent packets only if the receiver receives two
644  // duplicate segments.)//
645  //
646  // In case of d-sack: delete first sack (d-sack) and move old sacks by one to the left
647  if (dsack_inserted)
648  state->sacks_array.pop_front(); // delete DSACK entry
649 
650  // reset flags:
651  state->snd_sack = false;
652  state->snd_dsack = false;
653  state->start_seqno = 0;
654  state->end_seqno = 0;
655 
656  return *tcpseg;
657 }
bool seqGE(uint32 a, uint32 b)
Definition: TCPSegment.h:35
#define TCP_OPTION_SACK_MIN_SIZE
Definition: TCPConnection.h:129
uint32 start_seqno
Definition: TCPConnection.h:238
unsigned int uint
Definition: INETDefs.h:63
uint32 rcv_nxt
Definition: TCPConnection.h:174
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
bool snd_dsack
Definition: TCPConnection.h:241
virtual uint32 getLE(uint32 fromSeqNum)=0
Returns left edge of enqueued region.
#define TCP_OPTIONS_MAX_SIZE
Definition: TCPConnection.h:128
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
uint32 end_seqno
Definition: TCPConnection.h:239
bool snd_sack
Definition: TCPConnection.h:240
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 snd_sacks
Definition: TCPConnection.h:256
virtual uint32 getRE(uint32 toSeqNum)=0
Returns right edge of enqueued region.
cOutVector * sndSacksVector
Definition: TCPConnection.h:368
SackList sacks_array
Definition: TCPConnection.h:242
cMessage* inet::tcp::TCPConnection::cancelEvent ( cMessage *  msg)
inlineprotected

Utility: cancel a timer.

Referenced by processSegment1stThru8th(), and startSynRexmitTimer().

529 { return tcpMain->cancelEvent(msg); }
TCP * tcpMain
Definition: TCPConnection.h:330
TCPConnection * inet::tcp::TCPConnection::cloneListeningConnection ( )
protectedvirtual

Utility: clone a listening connection.

Used for forking.

Referenced by processSegmentInListen().

201 {
203 
204  conn->transferMode = transferMode;
205  // following code to be kept consistent with initConnection()
206  const char *sendQueueClass = sendQueue->getClassName();
207  conn->sendQueue = check_and_cast<TCPSendQueue *>(inet::utils::createOne(sendQueueClass));
208  conn->sendQueue->setConnection(conn);
209 
210  const char *receiveQueueClass = receiveQueue->getClassName();
211  conn->receiveQueue = check_and_cast<TCPReceiveQueue *>(inet::utils::createOne(receiveQueueClass));
212  conn->receiveQueue->setConnection(conn);
213 
214  // create SACK retransmit queue
215  conn->rexmitQueue = new TCPSACKRexmitQueue();
216  conn->rexmitQueue->setConnection(this);
217 
218  const char *tcpAlgorithmClass = tcpAlgorithm->getClassName();
219  conn->tcpAlgorithm = check_and_cast<TCPAlgorithm *>(inet::utils::createOne(tcpAlgorithmClass));
220  conn->tcpAlgorithm->setConnection(conn);
221 
222  conn->state = conn->tcpAlgorithm->getStateVariables();
224  conn->tcpAlgorithm->initialize();
225 
226  // put it into LISTEN, with our localAddr/localPort
227  conn->state->active = false;
228  conn->state->fork = true;
229  conn->localAddr = localAddr;
230  conn->localPort = localPort;
231  FSM_Goto(conn->fsm, TCP_S_LISTEN);
232 
233  return conn;
234 }
TCPDataTransferMode transferMode
Definition: TCPConnection.h:341
TCPConnection()
Note: this default ctor is NOT used to create live connections, only temporary ones so that TCPMain c...
Definition: TCPConnectionBase.cc:172
int appGateIndex
Definition: TCPConnection.h:320
virtual void configureStateVariables()
Utility: set snd_mss, rcv_wnd and sack in newly created state variables block.
Definition: TCPConnectionUtil.cc:357
virtual void setConnection(TCPConnection *_conn)
Set the connection that owns this queue.
Definition: TCPReceiveQueue.h:70
cObject * createOne(const char *className, const char *defaultNamespace)
Like cObjectFactory::createOne(), except it starts searching for the class in the given namespace...
Definition: INETUtils.cc:105
void setConnection(TCPConnection *_conn)
Assign this object to a TCPConnection.
Definition: TCPAlgorithm.h:66
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
TCP * tcpMain
Definition: TCPConnection.h:330
int localPort
Definition: TCPConnection.h:326
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
L3Address localAddr
Definition: TCPConnection.h:324
Definition: TCPConnection.h:65
virtual void setConnection(TCPConnection *_conn)
Set the connection that owns this queue.
Definition: TCPSendQueue.h:101
int connId
Definition: TCPConnection.h:321
void inet::tcp::TCPConnection::configureStateVariables ( )
protectedvirtual

Utility: set snd_mss, rcv_wnd and sack in newly created state variables block.

Referenced by cloneListeningConnection(), and initConnection().

358 {
359  long advertisedWindowPar = tcpMain->par("advertisedWindow").longValue();
360  state->ws_support = tcpMain->par("windowScalingSupport"); // if set, this means that current host supports WS (RFC 1323)
361  state->ws_manual_scale = tcpMain->par("windowScalingFactor"); // scaling factor (set manually) to help for TCP validation
362  if (!state->ws_support && (advertisedWindowPar > TCP_MAX_WIN || advertisedWindowPar <= 0))
363  throw cRuntimeError("Invalid advertisedWindow parameter: %ld", advertisedWindowPar);
364 
365  state->rcv_wnd = advertisedWindowPar;
366  state->rcv_adv = advertisedWindowPar;
367 
368  if (state->ws_support && advertisedWindowPar > TCP_MAX_WIN) {
369  state->rcv_wnd = TCP_MAX_WIN; // we cannot to guarantee that the other end is also supporting the Window Scale (header option) (RFC 1322)
370  state->rcv_adv = TCP_MAX_WIN; // therefore TCP_MAX_WIN is used as initial value for rcv_wnd and rcv_adv
371  }
372 
373  state->maxRcvBuffer = advertisedWindowPar;
374  state->delayed_acks_enabled = tcpMain->par("delayedAcksEnabled"); // delayed ACK algorithm (RFC 1122) enabled/disabled
375  state->nagle_enabled = tcpMain->par("nagleEnabled"); // Nagle's algorithm (RFC 896) enabled/disabled
376  state->limited_transmit_enabled = tcpMain->par("limitedTransmitEnabled"); // Limited Transmit algorithm (RFC 3042) enabled/disabled
377  state->increased_IW_enabled = tcpMain->par("increasedIWEnabled"); // Increased Initial Window (RFC 3390) enabled/disabled
378  state->snd_mss = tcpMain->par("mss").longValue(); // Maximum Segment Size (RFC 793)
379  state->ts_support = tcpMain->par("timestampSupport"); // if set, this means that current host supports TS (RFC 1323)
380  state->sack_support = tcpMain->par("sackSupport"); // if set, this means that current host supports SACK (RFC 2018, 2883, 3517)
381 
382  if (state->sack_support) {
383  std::string algorithmName1 = "TCPReno";
384  std::string algorithmName2 = tcpMain->par("tcpAlgorithmClass");
385 
386  if (algorithmName1 != algorithmName2) { // TODO add additional checks for new SACK supporting algorithms here once they are implemented
387  EV_DEBUG << "If you want to use TCP SACK please set tcpAlgorithmClass to TCPReno\n";
388 
389  ASSERT(false);
390  }
391  }
392 }
int ws_manual_scale
Definition: TCPConnection.h:218
bool ws_support
Definition: TCPConnection.h:216
uint32 rcv_adv
Definition: TCPConnection.h:178
bool nagle_enabled
Definition: TCPConnection.h:198
bool sack_support
Definition: TCPConnection.h:234
#define TCP_MAX_WIN
Definition: TCPConnection.h:125
bool increased_IW_enabled
Definition: TCPConnection.h:201
uint32 snd_mss
Definition: TCPConnection.h:159
TCP * tcpMain
Definition: TCPConnection.h:330
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 maxRcvBuffer
Definition: TCPConnection.h:262
bool delayed_acks_enabled
Definition: TCPConnection.h:199
uint32 rcv_wnd
Definition: TCPConnection.h:175
bool ts_support
Definition: TCPConnection.h:225
bool limited_transmit_enabled
Definition: TCPConnection.h:200
uint32 inet::tcp::TCPConnection::convertSimtimeToTS ( simtime_t  simtime)
static

Utility: converts a given simtime to a timestamp (TS).

Referenced by inet::tcp::TCPBaseAlg::rttMeasurementCompleteUsingTS(), and writeHeaderOptions().

1415 {
1416  ASSERT(SimTime::getScaleExp() <= -3);
1417 
1418  uint32 timestamp = (uint32)(simtime.inUnit(SIMTIME_MS));
1419  return timestamp;
1420 }
uint32_t uint32
Definition: Compat.h:30
simtime_t inet::tcp::TCPConnection::convertTSToSimtime ( uint32  timestamp)
static

Utility: converts a given timestamp (TS) to a simtime.

Referenced by inet::tcp::TCPBaseAlg::rttMeasurementCompleteUsingTS().

1423 {
1424  ASSERT(SimTime::getScaleExp() <= -3);
1425 
1426  simtime_t simtime(timestamp, SIMTIME_MS);
1427  return simtime;
1428 }
TCPSegment * inet::tcp::TCPConnection::createTCPSegment ( const char *  name)
virtual

Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.

Override it if you need to subclass TCPSegment.

Referenced by inet::tcp::TCPVirtualDataSendQueue::createSegmentWithBytes(), sendAck(), sendFin(), sendRst(), sendRstAck(), sendSegment(), sendSyn(), and sendSynAck().

284 {
285  return new TCPSegment(name);
286 }
const char * inet::tcp::TCPConnection::eventName ( int  event)
static

Utility: returns name of TCP_E_xxx constants.

69 {
70 #define CASE(x) case x: \
71  s = #x + 6; break
72  const char *s = "unknown";
73  switch (event) {
93  }
94  return s;
95 #undef CASE
96 }
Definition: TCPConnection.h:96
Definition: TCPConnection.h:99
Definition: TCPConnection.h:88
#define CASE(x)
Definition: TCPConnection.h:107
Definition: TCPConnection.h:90
Definition: TCPConnection.h:86
Definition: TCPConnection.h:97
Definition: TCPConnection.h:87
Definition: TCPConnection.h:100
Definition: TCPConnection.h:102
Definition: TCPConnection.h:109
Definition: TCPConnection.h:89
Definition: TCPConnection.h:91
Definition: TCPConnection.h:104
value< double, units::s > s
Definition: Units.h:1049
Definition: TCPConnection.h:101
Definition: TCPConnection.h:108
Definition: TCPConnection.h:92
Definition: TCPConnection.h:98
Definition: TCPConnection.h:82
int inet::tcp::TCPConnection::getFsmState ( ) const
inline
603 { return fsm.getState(); }
cFSM fsm
Definition: TCPConnection.h:333
L3Address inet::tcp::TCPConnection::getLocalAddress ( ) const
inline
588 { return localAddr; }
L3Address localAddr
Definition: TCPConnection.h:324
int inet::tcp::TCPConnection::getLocalPort ( ) const
inline
587 { return localPort; }
int localPort
Definition: TCPConnection.h:326
TCPReceiveQueue* inet::tcp::TCPConnection::getReceiveQueue ( )
inline
607 { return receiveQueue; }
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
L3Address inet::tcp::TCPConnection::getRemoteAddress ( ) const
inline
591 { return remoteAddr; }
L3Address remoteAddr
Definition: TCPConnection.h:325
int inet::tcp::TCPConnection::getRemotePort ( ) const
inline
590 { return remotePort; }
int remotePort
Definition: TCPConnection.h:327
TCPSACKRexmitQueue* inet::tcp::TCPConnection::getRexmitQueue ( )
inline
606 { return rexmitQueue; }
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
TCPSendQueue* inet::tcp::TCPConnection::getSendQueue ( )
inline
605 { return sendQueue; }
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables* inet::tcp::TCPConnection::getState ( )
inline
604 { return state; }
TCPStateVariables * state
Definition: TCPConnection.h:336
TCPAlgorithm* inet::tcp::TCPConnection::getTcpAlgorithm ( )
inline
608 { return tcpAlgorithm; }
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
TCP* inet::tcp::TCPConnection::getTcpMain ( )
inline
uint32 inet::tcp::TCPConnection::getTSecr ( TCPSegment tcpseg) const
protectedvirtual

Utility: get TSecr from segments TS header option.

Referenced by processAckInEstabEtc().

1237 {
1238  for (uint i = 0; i < tcpseg->getHeaderOptionArraySize(); i++) {
1239  const TCPOption *option = tcpseg->getHeaderOption(i);
1240  if (option->getKind() == TCPOPTION_TIMESTAMP)
1241  return check_and_cast<const TCPOptionTimestamp *>(option)->getEchoedTimestamp();
1242  }
1243 
1244  return 0;
1245 }
unsigned int uint
Definition: INETDefs.h:63
Definition: TCPSegment_m.h:118
uint32 inet::tcp::TCPConnection::getTSval ( TCPSegment tcpseg) const
protectedvirtual

Utility: get TSval from segments TS header option.

Referenced by processSegment1stThru8th().

1226 {
1227  for (uint i = 0; i < tcpseg->getHeaderOptionArraySize(); i++) {
1228  const TCPOption *option = tcpseg->getHeaderOption(i);
1229  if (option->getKind() == TCPOPTION_TIMESTAMP)
1230  return check_and_cast<const TCPOptionTimestamp *>(option)->getSenderTimestamp();
1231  }
1232 
1233  return 0;
1234 }
unsigned int uint
Definition: INETDefs.h:63
Definition: TCPSegment_m.h:118
bool inet::tcp::TCPConnection::hasEnoughSpaceForSegmentInReceiveQueue ( TCPSegment tcpseg)
virtual

Utility: returns true when receive queue has enough space for store the tcpseg.

Referenced by processSegment1stThru8th(), processSegmentInListen(), and processSegmentInSynSent().

123 {
124  //TODO must rewrite it
125  //return (state->freeRcvBuffer >= tcpseg->getPayloadLength()); // enough freeRcvBuffer in rcvQueue for new segment?
126 
127  uint32 firstSeq = receiveQueue->getFirstSeqNo();
128  return seqLE(firstSeq, tcpseg->getSequenceNo()) && seqLE(tcpseg->getSequenceNo() + tcpseg->getPayloadLength(), firstSeq + state->maxRcvBuffer);
129 }
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 maxRcvBuffer
Definition: TCPConnection.h:262
virtual uint32 getFirstSeqNo()=0
Returns the minimum of first byte seq.no.
const char * inet::tcp::TCPConnection::indicationName ( int  code)
static

Utility: returns name of TCP_I_xxx constants.

Referenced by sendEstabIndicationToApp(), and sendIndicationToApp().

99 {
100 #define CASE(x) case x: \
101  s = #x + 6; break
102  const char *s = "unknown";
103  switch (code) {
104  CASE(TCP_I_DATA);
114  }
115  return s;
116 #undef CASE
117 }
Definition: TCPCommand_m.h:102
Definition: TCPCommand_m.h:101
Definition: TCPCommand_m.h:100
Definition: TCPCommand_m.h:104
Definition: TCPCommand_m.h:99
#define CASE(x)
value< double, units::s > s
Definition: Units.h:1049
Definition: TCPCommand_m.h:106
Definition: TCPCommand_m.h:98
Definition: TCPCommand_m.h:107
Definition: TCPCommand_m.h:103
Definition: TCPCommand_m.h:105
void inet::tcp::TCPConnection::initConnection ( TCPOpenCommand openCmd)
protectedvirtual

Utility: creates send/receive queues and tcpAlgorithm.

Referenced by process_OPEN_ACTIVE(), and process_OPEN_PASSIVE().

328 {
329  transferMode = (TCPDataTransferMode)(openCmd->getDataTransferMode());
330  // create send queue
332  sendQueue->setConnection(this);
333 
334  // create receive queue
337 
338  // create SACK retransmit queue
339  rexmitQueue = new TCPSACKRexmitQueue();
340  rexmitQueue->setConnection(this);
341 
342  // create algorithm
343  const char *tcpAlgorithmClass = openCmd->getTcpAlgorithmClass();
344 
345  if (!tcpAlgorithmClass || !tcpAlgorithmClass[0])
346  tcpAlgorithmClass = tcpMain->par("tcpAlgorithmClass");
347 
348  tcpAlgorithm = check_and_cast<TCPAlgorithm *>(inet::utils::createOne(tcpAlgorithmClass));
350 
351  // create state block
355 }
TCPDataTransferMode transferMode
Definition: TCPConnection.h:341
virtual void initialize()
Should be redefined to initialize the object: create timers, etc.
Definition: TCPAlgorithm.h:84
virtual TCPReceiveQueue * createReceiveQueue(TCPDataTransferMode transferModeP)
To be called from TCPConnection: create a new receive queue.
Definition: TCP.cc:514
virtual void configureStateVariables()
Utility: set snd_mss, rcv_wnd and sack in newly created state variables block.
Definition: TCPConnectionUtil.cc:357
virtual void setConnection(TCPConnection *_conn)
Set the connection that owns this queue.
Definition: TCPReceiveQueue.h:70
TCPDataTransferMode
Enum generated from inet/transportlayer/contract/tcp/TCPCommand.msg:120 by nedtool.
Definition: TCPCommand_m.h:253
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
virtual void setConnection(TCPConnection *_conn)
Set the connection that owns this queue.
Definition: TCPSACKRexmitQueue.h:66
cObject * createOne(const char *className, const char *defaultNamespace)
Like cObjectFactory::createOne(), except it starts searching for the class in the given namespace...
Definition: INETUtils.cc:105
virtual TCPSendQueue * createSendQueue(TCPDataTransferMode transferModeP)
To be called from TCPConnection: create a new send queue.
Definition: TCP.cc:497
void setConnection(TCPConnection *_conn)
Assign this object to a TCPConnection.
Definition: TCPAlgorithm.h:66
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
TCP * tcpMain
Definition: TCPConnection.h:330
TCPStateVariables * getStateVariables()
Creates and returns the TCP state variables.
Definition: TCPAlgorithm.h:71
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void setConnection(TCPConnection *_conn)
Set the connection that owns this queue.
Definition: TCPSendQueue.h:101
bool inet::tcp::TCPConnection::isLost ( uint32  seqNum)
virtual

For SACK TCP.

RFC 3517, page 3: "This routine returns whether the given sequence number is considered to be lost. The routine returns true when either DupThresh discontiguous SACKed sequences have arrived above 'SeqNum' or (DupThresh * SMSS) bytes with sequence numbers greater than 'SeqNum' have been SACKed. Otherwise, the routine returns false."

Referenced by nextSeg(), and setPipe().

136 {
137  ASSERT(state->sack_enabled);
138 
139  // RFC 3517, page 3: "This routine returns whether the given sequence number is
140  // considered to be lost. The routine returns true when either
141  // DupThresh discontiguous SACKed sequences have arrived above
142  // 'SeqNum' or (DupThresh * SMSS) bytes with sequence numbers greater
143  // than 'SeqNum' have been SACKed. Otherwise, the routine returns
144  // false."
145  ASSERT(seqGE(seqNum, state->snd_una)); // HighAck = snd_una
146 
147  bool isLost = (rexmitQueue->getNumOfDiscontiguousSacks(seqNum) >= DUPTHRESH // DUPTHRESH = 3
149 
150  return isLost;
151 }
virtual uint32 getAmountOfSackedBytes(uint32 seqNum) const
Returns amount of sacked bytes above seqNum.
Definition: TCPSACKRexmitQueue.cc:325
bool seqGE(uint32 a, uint32 b)
Definition: TCPSegment.h:35
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
virtual uint32 getNumOfDiscontiguousSacks(uint32 seqNum) const
Returns the number of discontiguous sacked regions (SACKed sequences) above seqNum.
Definition: TCPSACKRexmitQueue.cc:346
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
#define DUPTHRESH
Definition: TCPConnection.h:126
uint32 snd_una
Definition: TCPConnection.h:164
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual bool isLost(uint32 seqNum)
For SACK TCP.
Definition: TCPConnectionSackUtil.cc:135
bool inet::tcp::TCPConnection::isSegmentAcceptable ( TCPSegment tcpseg) const
protectedvirtual

Utility: check if segment is acceptable (all bytes are in receive window)

Referenced by processSegment1stThru8th().

406 {
407  // check that segment entirely falls in receive window
408  // RFC 793, page 69:
409  // "There are four cases for the acceptability test for an incoming segment:
410  // Segment Receive Test
411  // Length Window
412  // ------- ------- -------------------------------------------
413  // 0 0 SEG.SEQ = RCV.NXT
414  // 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
415  // >0 0 not acceptable
416  // >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
417  // or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND"
418  uint32 len = tcpseg->getPayloadLength();
419  uint32 seqNo = tcpseg->getSequenceNo();
420  uint32 ackNo = tcpseg->getAckNo();
421  uint32 rcvWndEnd = state->rcv_nxt + state->rcv_wnd;
422  bool ret;
423 
424  if (len == 0) {
425  if (state->rcv_wnd == 0)
426  ret = (seqNo == state->rcv_nxt);
427  else // rcv_wnd > 0
428 // ret = seqLE(state->rcv_nxt, seqNo) && seqLess(seqNo, rcvWndEnd);
429  ret = seqLE(state->rcv_nxt, seqNo) && seqLE(seqNo, rcvWndEnd); // Accept an ACK on end of window
430  }
431  else { // len > 0
432  if (state->rcv_wnd == 0)
433  ret = false;
434  else // rcv_wnd > 0
435  ret = (seqLE(state->rcv_nxt, seqNo) && seqLess(seqNo, rcvWndEnd))
436  || (seqLess(state->rcv_nxt, seqNo + len) && seqLE(seqNo + len, rcvWndEnd)); // Accept an ACK on end of window
437  }
438 
439  // RFC 793, page 25:
440  // "A new acknowledgment (called an "acceptable ack"), is one for which
441  // the inequality below holds:
442  // SND.UNA < SEG.ACK =< SND.NXT"
443  if (!ret && len == 0) {
444  if (!state->afterRto)
445  ret = (seqLess(state->snd_una, ackNo) && seqLE(ackNo, state->snd_nxt));
446  else
447  ret = (seqLess(state->snd_una, ackNo) && seqLE(ackNo, state->snd_max)); // after RTO snd_nxt is reduced therefore we need to use snd_max instead of snd_nxt here
448  }
449 
450  if (!ret)
451  EV_WARN << "Not Acceptable segment. seqNo=" << seqNo << " ackNo=" << ackNo << " len=" << len << " rcv_nxt="
452  << state->rcv_nxt << " rcv_wnd=" << state->rcv_wnd << " afterRto=" << state->afterRto << "\n";
453 
454  return ret;
455 }
uint16_t len
Definition: TCP_NSC.cc:85
uint32 rcv_nxt
Definition: TCPConnection.h:174
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
uint32 snd_nxt
Definition: TCPConnection.h:165
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 rcv_wnd
Definition: TCPConnection.h:175
bool afterRto
Definition: TCPConnection.h:213
uint32 snd_max
Definition: TCPConnection.h:166
bool inet::tcp::TCPConnection::isSendQueueEmpty ( )
virtual

Utility: checks if send queue is empty (no data to send).

Referenced by inet::tcp::TCPBaseAlg::sendData().

1431 {
1432  return sendQueue->getBytesAvailable(state->snd_nxt) == 0;
1433 }
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
bool inet::tcp::TCPConnection::nextSeg ( uint32 seqNum)
virtual

For SACK TCP.

RFC 3517, page 3: "This routine uses the scoreboard data structure maintained by the Update() function to determine what to transmit based on the SACK information that has arrived from the data receiver (and hence been marked in the scoreboard). NextSeg () MUST return the sequence number range of the next segment that is to be transmitted..." Returns true if a valid sequence number (for the next segment) is found and returns false if no segment should be send.

Referenced by sendDataDuringLossRecoveryPhase().

222 {
223  ASSERT(state->sack_enabled);
224 
225  // RFC 3517, page 5: "This routine uses the scoreboard data structure maintained by the
226  // Update() function to determine what to transmit based on the SACK
227  // information that has arrived from the data receiver (and hence
228  // been marked in the scoreboard). NextSeg () MUST return the
229  // sequence number range of the next segment that is to be
230  // transmitted, per the following rules:"
231 
233  uint32 highestSackedSeqNum = rexmitQueue->getHighestSackedSeqNum();
234  uint32 shift = state->snd_mss;
235  bool sacked = false; // required for rexmitQueue->checkSackBlock()
236  bool rexmitted = false; // required for rexmitQueue->checkSackBlock()
237 
238  seqNum = 0;
239 
240  if (state->ts_enabled)
241  shift -= TCP_OPTION_TS_SIZE;
242 
243  // RFC 3517, page 5: "(1) If there exists a smallest unSACKed sequence number 'S2' that
244  // meets the following three criteria for determining loss, the
245  // sequence range of one segment of up to SMSS octets starting
246  // with S2 MUST be returned.
247  //
248  // (1.a) S2 is greater than HighRxt.
249  //
250  // (1.b) S2 is less than the highest octet covered by any
251  // received SACK.
252  //
253  // (1.c) IsLost (S2) returns true."
254 
255  // Note: state->highRxt == RFC.HighRxt + 1
256  for (uint32 s2 = state->highRxt;
257  seqLess(s2, state->snd_max) && seqLess(s2, highestSackedSeqNum);
258  s2 += shift
259  )
260  {
261  rexmitQueue->checkSackBlock(s2, shift, sacked, rexmitted);
262 
263  if (!sacked) {
264  if (isLost(s2)) { // 1.a and 1.b are true, see above "for" statement
265  seqNum = s2;
266 
267  return true;
268  }
269 
270  break; // !isLost(x) --> !isLost(x + d)
271  }
272  }
273 
274  // RFC 3517, page 5: "(2) If no sequence number 'S2' per rule (1) exists but there
275  // exists available unsent data and the receiver's advertised
276  // window allows, the sequence range of one segment of up to SMSS
277  // octets of previously unsent data starting with sequence number
278  // HighData+1 MUST be returned."
279  {
280  // check how many unsent bytes we have
282  ulong maxWindow = state->snd_wnd;
283  // effectiveWindow: number of bytes we're allowed to send now
284  ulong effectiveWin = maxWindow - state->pipe;
285 
286  if (buffered > 0 && effectiveWin >= state->snd_mss) {
287  seqNum = state->snd_max; // HighData = snd_max
288 
289  return true;
290  }
291  }
292 
293  // RFC 3517, pages 5 and 6: "(3) If the conditions for rules (1) and (2) fail, but there exists
294  // an unSACKed sequence number 'S3' that meets the criteria for
295  // detecting loss given in steps (1.a) and (1.b) above
296  // (specifically excluding step (1.c)) then one segment of up to
297  // SMSS octets starting with S3 MAY be returned.
298  //
299  // Note that rule (3) is a sort of retransmission "last resort".
300  // It allows for retransmission of sequence numbers even when the
301  // sender has less certainty a segment has been lost than as with
302  // rule (1). Retransmitting segments via rule (3) will help
303  // sustain TCP's ACK clock and therefore can potentially help
304  // avoid retransmission timeouts. However, in sending these
305  // segments the sender has two copies of the same data considered
306  // to be in the network (and also in the Pipe estimate). When an
307  // ACK or SACK arrives covering this retransmitted segment, the
308  // sender cannot be sure exactly how much data left the network
309  // (one of the two transmissions of the packet or both
310  // transmissions of the packet). Therefore the sender may
311  // underestimate Pipe by considering both segments to have left
312  // the network when it is possible that only one of the two has.
313  //
314  // We believe that the triggering of rule (3) will be rare and
315  // that the implications are likely limited to corner cases
316  // relative to the entire recovery algorithm. Therefore we leave
317  // the decision of whether or not to use rule (3) to
318  // implementors."
319  {
320  for (uint32 s3 = state->highRxt;
321  seqLess(s3, state->snd_max) && seqLess(s3, highestSackedSeqNum);
322  s3 += shift
323  )
324  {
325  rexmitQueue->checkSackBlock(s3, shift, sacked, rexmitted);
326 
327  if (!sacked) {
328  // 1.a and 1.b are true, see above "for" statement
329  seqNum = s3;
330 
331  return true;
332  }
333  }
334  }
335 
336  // RFC 3517, page 6: "(4) If the conditions for each of (1), (2), and (3) are not met,
337  // then NextSeg () MUST indicate failure, and no segment is
338  // returned."
339  seqNum = 0;
340 
341  return false;
342 }
bool ts_enabled
Definition: TCPConnection.h:226
uint32 pipe
Definition: TCPConnection.h:244
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
virtual void checkSackBlock(uint32 seqNum, uint32 &length, bool &sacked, bool &rexmitted) const
Definition: TCPSACKRexmitQueue.cc:373
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
#define TCP_OPTION_TS_SIZE
Definition: TCPConnection.h:130
uint32 snd_wnd
Definition: TCPConnection.h:167
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
virtual uint32 getHighestSackedSeqNum() const
Returns the highest sequence number sacked by data receiver.
Definition: TCPSACKRexmitQueue.cc:257
uint32_t uint32
Definition: Compat.h:30
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
unsigned long ulong
Definition: INETDefs.h:64
virtual bool isLost(uint32 seqNum)
For SACK TCP.
Definition: TCPConnectionSackUtil.cc:135
uint32 highRxt
Definition: TCPConnection.h:243
uint32 snd_max
Definition: TCPConnection.h:166
virtual uint32 getHighestRexmittedSeqNum() const
Returns the highest sequence number rexmitted by data sender.
Definition: TCPSACKRexmitQueue.cc:267
const char * inet::tcp::TCPConnection::optionName ( int  option)
static

Utility: returns name of TCPOPTION_xxx constants.

Referenced by printSegmentBrief(), and readHeaderOptions().

120 {
121  switch (option) {
123  return "EOL";
124 
126  return "NOP";
127 
129  return "MSS";
130 
132  return "WS";
133 
135  return "SACK_PERMITTED";
136 
137  case TCPOPTION_SACK:
138  return "SACK";
139 
140  case TCPOPTION_TIMESTAMP:
141  return "TS";
142 
143  default:
144  return "unknown";
145  }
146 }
Definition: TCPSegment_m.h:114
Definition: TCPSegment_m.h:112
Definition: TCPSegment_m.h:117
Definition: TCPSegment_m.h:118
Definition: TCPSegment_m.h:113
Definition: TCPSegment_m.h:116
Definition: TCPSegment_m.h:115
bool inet::tcp::TCPConnection::performStateTransition ( const TCPEventCode event)
protectedvirtual

Implemements the pure TCP state machine.

404 {
405  ASSERT(fsm.getState() != TCP_S_CLOSED); // closed connections should be deleted immediately
406 
407  if (event == TCP_E_IGNORE) { // e.g. discarded segment
408  EV_DETAIL << "Staying in state: " << stateName(fsm.getState()) << " (no FSM event)\n";
409  return true;
410  }
411 
412  // state machine
413  // TBD add handling of connection timeout event (KEEP-ALIVE), with transition to CLOSED
414  // Note: empty "default:" lines are for gcc's benefit which would otherwise spit warnings
415  int oldState = fsm.getState();
416 
417  switch (fsm.getState()) {
418  case TCP_S_INIT:
419  switch (event) {
420  case TCP_E_OPEN_PASSIVE:
421  FSM_Goto(fsm, TCP_S_LISTEN);
422  break;
423 
424  case TCP_E_OPEN_ACTIVE:
425  FSM_Goto(fsm, TCP_S_SYN_SENT);
426  break;
427 
428  default:
429  break;
430  }
431  break;
432 
433  case TCP_S_LISTEN:
434  switch (event) {
435  case TCP_E_OPEN_ACTIVE:
436  FSM_Goto(fsm, TCP_S_SYN_SENT);
437  break;
438 
439  case TCP_E_SEND:
440  FSM_Goto(fsm, TCP_S_SYN_SENT);
441  break;
442 
443  case TCP_E_CLOSE:
444  FSM_Goto(fsm, TCP_S_CLOSED);
445  break;
446 
447  case TCP_E_ABORT:
448  FSM_Goto(fsm, TCP_S_CLOSED);
449  break;
450 
451  case TCP_E_RCV_SYN:
452  FSM_Goto(fsm, TCP_S_SYN_RCVD);
453  break;
454 
455  default:
456  break;
457  }
458  break;
459 
460  case TCP_S_SYN_RCVD:
461  switch (event) {
462  case TCP_E_CLOSE:
463  FSM_Goto(fsm, TCP_S_FIN_WAIT_1);
464  break;
465 
466  case TCP_E_ABORT:
467  FSM_Goto(fsm, TCP_S_CLOSED);
468  break;
469 
471  FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN);
472  break;
473 
474  case TCP_E_RCV_RST:
475  FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN);
476  break;
477 
478  case TCP_E_RCV_ACK:
479  FSM_Goto(fsm, TCP_S_ESTABLISHED);
480  break;
481 
482  case TCP_E_RCV_FIN:
483  FSM_Goto(fsm, TCP_S_CLOSE_WAIT);
484  break;
485 
486  case TCP_E_RCV_UNEXP_SYN:
487  FSM_Goto(fsm, TCP_S_CLOSED);
488  break;
489 
490  default:
491  break;
492  }
493  break;
494 
495  case TCP_S_SYN_SENT:
496  switch (event) {
497  case TCP_E_CLOSE:
498  FSM_Goto(fsm, TCP_S_CLOSED);
499  break;
500 
501  case TCP_E_ABORT:
502  FSM_Goto(fsm, TCP_S_CLOSED);
503  break;
504 
506  FSM_Goto(fsm, TCP_S_CLOSED);
507  break;
508 
509  case TCP_E_RCV_RST:
510  FSM_Goto(fsm, TCP_S_CLOSED);
511  break;
512 
513  case TCP_E_RCV_SYN_ACK:
514  FSM_Goto(fsm, TCP_S_ESTABLISHED);
515  break;
516 
517  case TCP_E_RCV_SYN:
518  FSM_Goto(fsm, TCP_S_SYN_RCVD);
519  break;
520 
521  default:
522  break;
523  }
524  break;
525 
526  case TCP_S_ESTABLISHED:
527  switch (event) {
528  case TCP_E_CLOSE:
529  FSM_Goto(fsm, TCP_S_FIN_WAIT_1);
530  break;
531 
532  case TCP_E_ABORT:
533  FSM_Goto(fsm, TCP_S_CLOSED);
534  break;
535 
536  case TCP_E_RCV_FIN:
537  FSM_Goto(fsm, TCP_S_CLOSE_WAIT);
538  break;
539 
540  case TCP_E_RCV_RST:
541  FSM_Goto(fsm, TCP_S_CLOSED);
542  break;
543 
544  case TCP_E_RCV_UNEXP_SYN:
545  FSM_Goto(fsm, TCP_S_CLOSED);
546  break;
547 
548  default:
549  break;
550  }
551  break;
552 
553  case TCP_S_CLOSE_WAIT:
554  switch (event) {
555  case TCP_E_CLOSE:
556  FSM_Goto(fsm, TCP_S_LAST_ACK);
557  break;
558 
559  case TCP_E_ABORT:
560  FSM_Goto(fsm, TCP_S_CLOSED);
561  break;
562 
563  case TCP_E_RCV_RST:
564  FSM_Goto(fsm, TCP_S_CLOSED);
565  break;
566 
567  case TCP_E_RCV_UNEXP_SYN:
568  FSM_Goto(fsm, TCP_S_CLOSED);
569  break;
570 
571  default:
572  break;
573  }
574  break;
575 
576  case TCP_S_LAST_ACK:
577  switch (event) {
578  case TCP_E_ABORT:
579  FSM_Goto(fsm, TCP_S_CLOSED);
580  break;
581 
582  case TCP_E_RCV_ACK:
583  FSM_Goto(fsm, TCP_S_CLOSED);
584  break;
585 
586  case TCP_E_RCV_RST:
587  FSM_Goto(fsm, TCP_S_CLOSED);
588  break;
589 
590  case TCP_E_RCV_UNEXP_SYN:
591  FSM_Goto(fsm, TCP_S_CLOSED);
592  break;
593 
594  default:
595  break;
596  }
597  break;
598 
599  case TCP_S_FIN_WAIT_1:
600  switch (event) {
601  case TCP_E_ABORT:
602  FSM_Goto(fsm, TCP_S_CLOSED);
603  break;
604 
605  case TCP_E_RCV_FIN:
606  FSM_Goto(fsm, TCP_S_CLOSING);
607  break;
608 
609  case TCP_E_RCV_ACK:
610  FSM_Goto(fsm, TCP_S_FIN_WAIT_2);
611  break;
612 
613  case TCP_E_RCV_FIN_ACK:
614  FSM_Goto(fsm, TCP_S_TIME_WAIT);
615  break;
616 
617  case TCP_E_RCV_RST:
618  FSM_Goto(fsm, TCP_S_CLOSED);
619  break;
620 
621  case TCP_E_RCV_UNEXP_SYN:
622  FSM_Goto(fsm, TCP_S_CLOSED);
623  break;
624 
625  default:
626  break;
627  }
628  break;
629 
630  case TCP_S_FIN_WAIT_2:
631  switch (event) {
632  case TCP_E_ABORT:
633  FSM_Goto(fsm, TCP_S_CLOSED);
634  break;
635 
636  case TCP_E_RCV_FIN:
637  FSM_Goto(fsm, TCP_S_TIME_WAIT);
638  break;
639 
641  FSM_Goto(fsm, TCP_S_CLOSED);
642  break;
643 
644  case TCP_E_RCV_RST:
645  FSM_Goto(fsm, TCP_S_CLOSED);
646  break;
647 
648  case TCP_E_RCV_UNEXP_SYN:
649  FSM_Goto(fsm, TCP_S_CLOSED);
650  break;
651 
652  default:
653  break;
654  }
655  break;
656 
657  case TCP_S_CLOSING:
658  switch (event) {
659  case TCP_E_ABORT:
660  FSM_Goto(fsm, TCP_S_CLOSED);
661  break;
662 
663  case TCP_E_RCV_ACK:
664  FSM_Goto(fsm, TCP_S_TIME_WAIT);
665  break;
666 
667  case TCP_E_RCV_RST:
668  FSM_Goto(fsm, TCP_S_CLOSED);
669  break;
670 
671  case TCP_E_RCV_UNEXP_SYN:
672  FSM_Goto(fsm, TCP_S_CLOSED);
673  break;
674 
675  default:
676  break;
677  }
678  break;
679 
680  case TCP_S_TIME_WAIT:
681  switch (event) {
682  case TCP_E_ABORT:
683  FSM_Goto(fsm, TCP_S_CLOSED);
684  break;
685 
686  case TCP_E_TIMEOUT_2MSL:
687  FSM_Goto(fsm, TCP_S_CLOSED);
688  break;
689 
690  case TCP_E_RCV_RST:
691  FSM_Goto(fsm, TCP_S_CLOSED);
692  break;
693 
694  case TCP_E_RCV_UNEXP_SYN:
695  FSM_Goto(fsm, TCP_S_CLOSED);
696  break;
697 
698  default:
699  break;
700  }
701  break;
702 
703  case TCP_S_CLOSED:
704  break;
705  }
706 
707  if (oldState != fsm.getState()) {
708  EV_INFO << "Transition: " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n";
709  EV_DEBUG_C("testing") << tcpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (on " << eventName(event) << ")\n";
710 
711  // cancel timers, etc.
712  stateEntered(fsm.getState(), oldState, event);
713  }
714  else {
715  EV_DETAIL << "Staying in state: " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n";
716  }
717 
718  return fsm.getState() != TCP_S_CLOSED;
719 }
Definition: TCPConnection.h:68
Definition: TCPConnection.h:69
Definition: TCPConnection.h:99
Definition: TCPConnection.h:70
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:74
Definition: TCPConnection.h:66
Definition: TCPConnection.h:72
Definition: TCPConnection.h:63
Definition: TCPConnection.h:88
Definition: TCPConnection.h:107
Definition: TCPConnection.h:90
bool active
Definition: TCPConnection.h:156
Definition: TCPConnection.h:86
Definition: TCPConnection.h:97
Definition: TCPConnection.h:87
Definition: TCPConnection.h:100
Definition: TCPConnection.h:102
Definition: TCPConnection.h:109
TCP * tcpMain
Definition: TCPConnection.h:330
Definition: TCPConnection.h:89
static const char * eventName(int event)
Utility: returns name of TCP_E_xxx constants.
Definition: TCPConnectionUtil.cc:68
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:104
Definition: TCPConnection.h:71
Definition: TCPConnection.h:65
Definition: TCPConnection.h:67
Definition: TCPConnection.h:101
Definition: TCPConnection.h:108
virtual void stateEntered(int state, int oldState, TCPEventCode event)
Perform cleanup necessary when entering a new state, e.g.
Definition: TCPConnectionBase.cc:721
Definition: TCPConnection.h:64
Definition: TCPConnection.h:73
Definition: TCPConnection.h:98
Definition: TCPConnection.h:82
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
TCPEventCode inet::tcp::TCPConnection::preanalyseAppCommandEvent ( int  commandCode)
protectedvirtual

Maps app command codes (msg kind of app command msgs) to TCP_E_xxx event codes.

372 {
373  switch (commandCode) {
374  case TCP_C_OPEN_ACTIVE:
375  return TCP_E_OPEN_ACTIVE;
376 
377  case TCP_C_OPEN_PASSIVE:
378  return TCP_E_OPEN_PASSIVE;
379 
380  case TCP_C_SEND:
381  return TCP_E_SEND;
382 
383  case TCP_C_CLOSE:
384  return TCP_E_CLOSE;
385 
386  case TCP_C_ABORT:
387  return TCP_E_ABORT;
388 
389  case TCP_C_STATUS:
390  return TCP_E_STATUS;
391 
394 
395  case TCP_C_READ:
396  return TCP_E_READ;
397 
398  default:
399  throw cRuntimeError(tcpMain, "Unknown message kind in app command");
400  }
401 }
Definition: TCPCommand_m.h:61
Definition: TCPCommand_m.h:67
Definition: TCPCommand_m.h:63
Definition: TCPConnection.h:88
Definition: TCPConnection.h:90
Definition: TCPConnection.h:86
Definition: TCPConnection.h:87
Definition: TCPCommand_m.h:66
Definition: TCPCommand_m.h:68
TCP * tcpMain
Definition: TCPConnection.h:330
Definition: TCPConnection.h:89
Definition: TCPCommand_m.h:62
Definition: TCPConnection.h:91
Definition: TCPCommand_m.h:64
Definition: TCPConnection.h:93
Definition: TCPCommand_m.h:65
Definition: TCPConnection.h:92
void inet::tcp::TCPConnection::printConnBrief ( ) const
virtual

Utility: prints local/remote addr/port and app gate index/connId.

149 {
150  EV_DETAIL << "Connection "
151  << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort
152  << " on app[" << appGateIndex << "], connId=" << connId
153  << " in " << stateName(fsm.getState())
154  << "\n";
155 }
L3Address remoteAddr
Definition: TCPConnection.h:325
int appGateIndex
Definition: TCPConnection.h:320
cFSM fsm
Definition: TCPConnection.h:333
int localPort
Definition: TCPConnection.h:326
L3Address localAddr
Definition: TCPConnection.h:324
int remotePort
Definition: TCPConnection.h:327
int connId
Definition: TCPConnection.h:321
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
void inet::tcp::TCPConnection::printSegmentBrief ( TCPSegment tcpseg)
static

Utility: prints important header fields.

Referenced by process_RCV_SEGMENT(), segmentArrivalWhileClosed(), and sendToIP().

158 {
159  EV_STATICCONTEXT;
160  EV_INFO << "." << tcpseg->getSrcPort() << " > ";
161  EV_INFO << "." << tcpseg->getDestPort() << ": ";
162 
163  if (tcpseg->getSynBit())
164  EV_INFO << (tcpseg->getAckBit() ? "SYN+ACK " : "SYN ");
165 
166  if (tcpseg->getFinBit())
167  EV_INFO << "FIN(+ACK) ";
168 
169  if (tcpseg->getRstBit())
170  EV_INFO << (tcpseg->getAckBit() ? "RST+ACK " : "RST ");
171 
172  if (tcpseg->getPshBit())
173  EV_INFO << "PSH ";
174 
175  if (tcpseg->getPayloadLength() > 0 || tcpseg->getSynBit()) {
176  EV_INFO << "[" << tcpseg->getSequenceNo() << ".." << (tcpseg->getSequenceNo() + tcpseg->getPayloadLength()) << ") ";
177  EV_INFO << "(l=" << tcpseg->getPayloadLength() << ") ";
178  }
179 
180  if (tcpseg->getAckBit())
181  EV_INFO << "ack " << tcpseg->getAckNo() << " ";
182 
183  EV_INFO << "win " << tcpseg->getWindow() << " ";
184 
185  if (tcpseg->getUrgBit())
186  EV_INFO << "urg " << tcpseg->getUrgentPointer() << " ";
187 
188  if (tcpseg->getHeaderLength() > TCP_HEADER_OCTETS) { // Header options present? TCP_HEADER_OCTETS = 20
189  EV_INFO << "options ";
190 
191  for (uint i = 0; i < tcpseg->getHeaderOptionArraySize(); i++) {
192  const TCPOption *option = tcpseg->getHeaderOption(i);
193  short kind = option->getKind();
194  EV_INFO << optionName(kind) << " ";
195  }
196  }
197  EV_INFO << "\n";
198 }
unsigned int uint
Definition: INETDefs.h:63
#define TCP_HEADER_OCTETS
Definition: TCPSegment_m.h:50
static const char * optionName(int option)
Utility: returns name of TCPOPTION_xxx constants.
Definition: TCPConnectionUtil.cc:119
void inet::tcp::TCPConnection::process_ABORT ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
236 {
237  delete tcpCommand;
238  delete msg;
239 
240  //
241  // The ABORT event will automatically take the connection to the CLOSED
242  // state, flush queues etc -- no need to do it here. Also, we don't need to
243  // send notification to the user, they know what's going on.
244  //
245  switch (fsm.getState()) {
246  case TCP_S_INIT:
247  throw cRuntimeError("Error processing command ABORT: connection not open");
248 
249  case TCP_S_SYN_RCVD:
250  case TCP_S_ESTABLISHED:
251  case TCP_S_FIN_WAIT_1:
252  case TCP_S_FIN_WAIT_2:
253  case TCP_S_CLOSE_WAIT:
254  //"
255  // Send a reset segment:
256  //
257  // <SEQ=SND.NXT><CTL=RST>
258  //"
260  break;
261  }
262 }
Definition: TCPConnection.h:68
Definition: TCPConnection.h:69
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:72
Definition: TCPConnection.h:63
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:71
Definition: TCPConnection.h:67
virtual void sendRst(uint32 seqNo)
Utility: sends RST.
Definition: TCPConnectionUtil.cc:504
void inet::tcp::TCPConnection::process_CLOSE ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
176 {
177  delete tcpCommand;
178  delete msg;
179 
180  switch (fsm.getState()) {
181  case TCP_S_INIT:
182  throw cRuntimeError(tcpMain, "Error processing command CLOSE: connection not open");
183 
184  case TCP_S_LISTEN:
185  // Nothing to do here
186  break;
187 
188  case TCP_S_SYN_SENT:
189  // Delete the TCB and return "error: closing" responses to any
190  // queued SENDs, or RECEIVEs.
191  break;
192 
193  case TCP_S_SYN_RCVD:
194  case TCP_S_ESTABLISHED:
195  case TCP_S_CLOSE_WAIT:
196  //
197  // SYN_RCVD processing (ESTABLISHED and CLOSE_WAIT are similar):
198  //"
199  // If no SENDs have been issued and there is no pending data to send,
200  // then form a FIN segment and send it, and enter FIN-WAIT-1 state;
201  // otherwise queue for processing after entering ESTABLISHED state.
202  //"
203  if (state->snd_max == sendQueue->getBufferEndSeq()) {
204  EV_DETAIL << "No outstanding SENDs, sending FIN right away, advancing snd_nxt over the FIN\n";
206  sendFin();
208  state->snd_max = ++state->snd_nxt;
209 
210  if (unackedVector)
211  unackedVector->record(state->snd_max - state->snd_una);
212 
213  // state transition will automatically take us to FIN_WAIT_1 (or LAST_ACK)
214  }
215  else {
216  EV_DETAIL << "SEND of " << (sendQueue->getBufferEndSeq() - state->snd_max)
217  << " bytes pending, deferring sending of FIN\n";
218  event = TCP_E_IGNORE;
219  }
220  state->send_fin = true;
222  break;
223 
224  case TCP_S_FIN_WAIT_1:
225  case TCP_S_FIN_WAIT_2:
226  case TCP_S_CLOSING:
227  case TCP_S_LAST_ACK:
228  case TCP_S_TIME_WAIT:
229  // RFC 793 is not entirely clear on how to handle a duplicate close request.
230  // Here we treat it as an error.
231  throw cRuntimeError(tcpMain, "Duplicate CLOSE command: connection already closing");
232  }
233 }
bool send_fin
Definition: TCPConnection.h:190
virtual void restartRexmitTimer()=0
Restart REXMIT timer.
Definition: TCPConnection.h:68
Definition: TCPConnection.h:69
Definition: TCPConnection.h:70
cOutVector * unackedVector
Definition: TCPConnection.h:364
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:74
Definition: TCPConnection.h:66
Definition: TCPConnection.h:72
Definition: TCPConnection.h:63
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendFin()
Utility: sends FIN.
Definition: TCPConnectionUtil.cc:562
uint32 snd_fin_seq
Definition: TCPConnection.h:191
TCP * tcpMain
Definition: TCPConnection.h:330
uint32 snd_una
Definition: TCPConnection.h:164
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:71
Definition: TCPConnection.h:65
Definition: TCPConnection.h:67
virtual uint32 getBufferEndSeq()=0
Returns the sequence number of the last byte stored in the buffer plus one.
Definition: TCPConnection.h:73
Definition: TCPConnection.h:82
uint32 snd_max
Definition: TCPConnection.h:166
void inet::tcp::TCPConnection::process_OPEN_ACTIVE ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
36 {
37  TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
38  L3Address localAddr, remoteAddr;
39  int localPort, remotePort;
40 
41  switch (fsm.getState()) {
42  case TCP_S_INIT:
43  initConnection(openCmd);
44 
45  // store local/remote socket
46  state->active = true;
47  localAddr = openCmd->getLocalAddr();
48  remoteAddr = openCmd->getRemoteAddr();
49  localPort = openCmd->getLocalPort();
50  remotePort = openCmd->getRemotePort();
51 
52  if (remoteAddr.isUnspecified() || remotePort == -1)
53  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: remote address and port must be specified");
54 
55  if (localPort == -1) {
56  localPort = tcpMain->getEphemeralPort();
57  EV_DETAIL << "Assigned ephemeral port " << localPort << "\n";
58  }
59 
60  EV_DETAIL << "OPEN: " << localAddr << ":" << localPort << " --> " << remoteAddr << ":" << remotePort << "\n";
61 
62  tcpMain->addSockPair(this, localAddr, remoteAddr, localPort, remotePort);
63 
64  // send initial SYN
66  sendSyn();
69  break;
70 
71  default:
72  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: connection already exists");
73  }
74 
75  delete openCmd;
76  delete msg;
77 }
L3Address remoteAddr
Definition: TCPConnection.h:325
virtual void initConnection(TCPOpenCommand *openCmd)
Utility: creates send/receive queues and tcpAlgorithm.
Definition: TCPConnectionUtil.cc:327
cFSM fsm
Definition: TCPConnection.h:333
virtual ushort getEphemeralPort()
To be called from TCPConnection: reserves an ephemeral port for the connection.
Definition: TCP.cc:370
Definition: TCPConnection.h:63
bool active
Definition: TCPConnection.h:156
virtual void addSockPair(TCPConnection *conn, L3Address localAddr, L3Address remoteAddr, int localPort, int remotePort)
To be called from TCPConnection when a new connection gets created, during processing of OPEN_ACTIVE ...
Definition: TCP.cc:391
TCP * tcpMain
Definition: TCPConnection.h:330
int localPort
Definition: TCPConnection.h:326
TCPStateVariables * state
Definition: TCPConnection.h:336
L3Address localAddr
Definition: TCPConnection.h:324
int remotePort
Definition: TCPConnection.h:327
virtual void startSynRexmitTimer()
Utility: start SYN-REXMIT timer.
Definition: TCPConnectionRcvSegment.cc:1311
cMessage * connEstabTimer
Definition: TCPConnection.h:352
#define TCP_TIMEOUT_CONN_ESTAB
Definition: TCPConnection.h:117
void scheduleTimeout(cMessage *msg, simtime_t timeout)
Utility: start a timer.
Definition: TCPConnection.h:524
virtual void sendSyn()
Utility: send SYN.
Definition: TCPConnectionUtil.cc:457
virtual void selectInitialSeqNum()
Utility: generates ISS and initializes corresponding state variables.
Definition: TCPConnectionUtil.cc:394
void inet::tcp::TCPConnection::process_OPEN_PASSIVE ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
80 {
81  TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
82  L3Address localAddr;
83  int localPort;
84 
85  switch (fsm.getState()) {
86  case TCP_S_INIT:
87  initConnection(openCmd);
88 
89  // store local/remote socket
90  state->active = false;
91  state->fork = openCmd->getFork();
92  localAddr = openCmd->getLocalAddr();
93  localPort = openCmd->getLocalPort();
94 
95  if (localPort == -1)
96  throw cRuntimeError(tcpMain, "Error processing command OPEN_PASSIVE: local port must be specified");
97 
98  EV_DETAIL << "Starting to listen on: " << localAddr << ":" << localPort << "\n";
99 
100  tcpMain->addSockPair(this, localAddr, L3Address(), localPort, -1);
101  break;
102 
103  default:
104  throw cRuntimeError(tcpMain, "Error processing command OPEN_PASSIVE: connection already exists");
105  }
106 
107  delete openCmd;
108  delete msg;
109 }
virtual void initConnection(TCPOpenCommand *openCmd)
Utility: creates send/receive queues and tcpAlgorithm.
Definition: TCPConnectionUtil.cc:327
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:63
bool fork
Definition: TCPConnection.h:157
bool active
Definition: TCPConnection.h:156
virtual void addSockPair(TCPConnection *conn, L3Address localAddr, L3Address remoteAddr, int localPort, int remotePort)
To be called from TCPConnection when a new connection gets created, during processing of OPEN_ACTIVE ...
Definition: TCP.cc:391
TCP * tcpMain
Definition: TCPConnection.h:330
int localPort
Definition: TCPConnection.h:326
TCPStateVariables * state
Definition: TCPConnection.h:336
L3Address localAddr
Definition: TCPConnection.h:324
void inet::tcp::TCPConnection::process_QUEUE_BYTES_LIMIT ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
302 {
303  if (state == nullptr)
304  throw cRuntimeError("Called process_QUEUE_BYTES_LIMIT on uninitialized TCPConnection!");
305 
306  state->sendQueueLimit = tcpCommand->getUserId(); // Set queue size limit
307  EV << "state->sendQueueLimit set to " << state->sendQueueLimit << "\n";
308  delete msg;
309  delete tcpCommand;
310 }
uint32 sendQueueLimit
Definition: TCPConnection.h:251
TCPStateVariables * state
Definition: TCPConnection.h:336
TCPEventCode inet::tcp::TCPConnection::process_RCV_SEGMENT ( TCPSegment tcpseg,
L3Address  src,
L3Address  dest 
)
protectedvirtual

Process incoming TCP segment.

Returns a specific event code (e.g. TCP_E_RCV_SYN) which will drive the state machine.

90 {
91  EV_INFO << "Seg arrived: ";
92  printSegmentBrief(tcpseg);
93  EV_DETAIL << "TCB: " << state->info() << "\n";
94 
95  if (rcvSeqVector)
96  rcvSeqVector->record(tcpseg->getSequenceNo());
97 
98  if (rcvAckVector)
99  rcvAckVector->record(tcpseg->getAckNo());
100 
101  //
102  // Note: this code is organized exactly as RFC 793, section "3.9 Event
103  // Processing", subsection "SEGMENT ARRIVES".
104  //
105  TCPEventCode event;
106 
107  if (fsm.getState() == TCP_S_LISTEN) {
108  event = processSegmentInListen(tcpseg, src, dest);
109  }
110  else if (fsm.getState() == TCP_S_SYN_SENT) {
111  event = processSegmentInSynSent(tcpseg, src, dest);
112  }
113  else {
114  // RFC 793 steps "first check sequence number", "second check the RST bit", etc
115  event = processSegment1stThru8th(tcpseg);
116  }
117 
118  delete tcpseg;
119  return event;
120 }
cOutVector * rcvSeqVector
Definition: TCPConnection.h:362
cFSM fsm
Definition: TCPConnection.h:333
virtual TCPEventCode processSegmentInSynSent(TCPSegment *tcpseg, L3Address src, L3Address dest)
Definition: TCPConnectionRcvSegment.cc:872
Definition: TCPConnection.h:66
TCPEventCode
Definition: TCPConnection.h:81
virtual TCPEventCode processSegment1stThru8th(TCPSegment *tcpseg)
Definition: TCPConnectionRcvSegment.cc:131
static void printSegmentBrief(TCPSegment *tcpseg)
Utility: prints important header fields.
Definition: TCPConnectionUtil.cc:157
cOutVector * rcvAckVector
Definition: TCPConnection.h:363
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual std::string info() const override
Definition: TCPConnectionBase.cc:122
virtual TCPEventCode processSegmentInListen(TCPSegment *tcpseg, L3Address src, L3Address dest)
Definition: TCPConnectionRcvSegment.cc:737
Definition: TCPConnection.h:65
void inet::tcp::TCPConnection::process_READ_REQUEST ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
162 {
163  delete msg;
164  cMessage *dataMsg;
165  while ((dataMsg = receiveQueue->extractBytesUpTo(state->rcv_nxt)) != nullptr)
166  {
167  dataMsg->setKind(TCP_I_DATA);
168  TCPCommand *cmd = new TCPCommand();
169  cmd->setConnId(connId);
170  dataMsg->setControlInfo(cmd);
171  sendToApp(dataMsg);
172  }
173 }
uint32 rcv_nxt
Definition: TCPConnection.h:174
virtual cPacket * extractBytesUpTo(uint32 seq)=0
Should create a packet to be passed up to the app, up to (but NOT including) the given sequence no (u...
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPCommand_m.h:98
virtual void sendToApp(cMessage *msg)
Utility: sends packet to application.
Definition: TCPConnectionUtil.cc:322
int connId
Definition: TCPConnection.h:321
void inet::tcp::TCPConnection::process_SEND ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
112 {
113  TCPSendCommand *sendCommand = check_and_cast<TCPSendCommand *>(tcpCommand);
114 
115  // FIXME how to support PUSH? One option is to treat each SEND as a unit of data,
116  // and set PSH at SEND boundaries
117  switch (fsm.getState()) {
118  case TCP_S_INIT:
119  throw cRuntimeError(tcpMain, "Error processing command SEND: connection not open");
120 
121  case TCP_S_LISTEN:
122  EV_DETAIL << "SEND command turns passive open into active open, sending initial SYN\n";
123  state->active = true;
125  sendSyn();
128  sendQueue->enqueueAppData(PK(msg)); // queue up for later
129  EV_DETAIL << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n";
130  break;
131 
132  case TCP_S_SYN_RCVD:
133  case TCP_S_SYN_SENT:
134  EV_DETAIL << "Queueing up data for sending later.\n";
135  sendQueue->enqueueAppData(PK(msg)); // queue up for later
136  EV_DETAIL << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n";
137  break;
138 
139  case TCP_S_ESTABLISHED:
140  case TCP_S_CLOSE_WAIT:
141  sendQueue->enqueueAppData(PK(msg));
142  EV_DETAIL << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue, plus "
143  << (state->snd_max - state->snd_una) << " bytes unacknowledged\n";
145  break;
146 
147  case TCP_S_LAST_ACK:
148  case TCP_S_FIN_WAIT_1:
149  case TCP_S_FIN_WAIT_2:
150  case TCP_S_CLOSING:
151  case TCP_S_TIME_WAIT:
152  throw cRuntimeError(tcpMain, "Error processing command SEND: connection closing");
153  }
154 
156  state->queueUpdate = false;
157 
158  delete sendCommand; // msg itself has been taken by the sendQueue
159 }
virtual void enqueueAppData(cPacket *msg)=0
Called on SEND app command, it inserts in the queue the data the user wants to send.
Definition: TCPConnection.h:68
Definition: TCPConnection.h:69
uint32 sendQueueLimit
Definition: TCPConnection.h:251
Definition: TCPConnection.h:70
cFSM fsm
Definition: TCPConnection.h:333
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
Definition: TCPConnection.h:74
Definition: TCPConnection.h:66
Definition: TCPConnection.h:72
Definition: TCPConnection.h:63
bool active
Definition: TCPConnection.h:156
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
TCP * tcpMain
Definition: TCPConnection.h:330
uint32 snd_una
Definition: TCPConnection.h:164
virtual void sendCommandInvoked()=0
Called after user sent TCP_C_SEND command to us.
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
bool queueUpdate
Definition: TCPConnection.h:252
virtual void startSynRexmitTimer()
Utility: start SYN-REXMIT timer.
Definition: TCPConnectionRcvSegment.cc:1311
cMessage * connEstabTimer
Definition: TCPConnection.h:352
#define PK(msg)
Definition: INETDefs.h:92
Definition: TCPConnection.h:71
Definition: TCPConnection.h:65
Definition: TCPConnection.h:67
#define TCP_TIMEOUT_CONN_ESTAB
Definition: TCPConnection.h:117
void scheduleTimeout(cMessage *msg, simtime_t timeout)
Utility: start a timer.
Definition: TCPConnection.h:524
Definition: TCPConnection.h:73
uint32 snd_max
Definition: TCPConnection.h:166
virtual void sendSyn()
Utility: send SYN.
Definition: TCPConnectionUtil.cc:457
virtual void selectInitialSeqNum()
Utility: generates ISS and initializes corresponding state variables.
Definition: TCPConnectionUtil.cc:394
void inet::tcp::TCPConnection::process_STATUS ( TCPEventCode event,
TCPCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
265 {
266  delete tcpCommand; // but reuse msg for reply
267 
268  if (fsm.getState() == TCP_S_INIT)
269  throw cRuntimeError("Error processing command STATUS: connection not open");
270 
271  TCPStatusInfo *statusInfo = new TCPStatusInfo();
272 
273  statusInfo->setState(fsm.getState());
274  statusInfo->setStateName(stateName(fsm.getState()));
275 
276  statusInfo->setLocalAddr(localAddr);
277  statusInfo->setRemoteAddr(remoteAddr);
278  statusInfo->setLocalPort(localPort);
279  statusInfo->setRemotePort(remotePort);
280 
281  statusInfo->setSnd_mss(state->snd_mss);
282  statusInfo->setSnd_una(state->snd_una);
283  statusInfo->setSnd_nxt(state->snd_nxt);
284  statusInfo->setSnd_max(state->snd_max);
285  statusInfo->setSnd_wnd(state->snd_wnd);
286  statusInfo->setSnd_up(state->snd_up);
287  statusInfo->setSnd_wl1(state->snd_wl1);
288  statusInfo->setSnd_wl2(state->snd_wl2);
289  statusInfo->setIss(state->iss);
290  statusInfo->setRcv_nxt(state->rcv_nxt);
291  statusInfo->setRcv_wnd(state->rcv_wnd);
292  statusInfo->setRcv_up(state->rcv_up);
293  statusInfo->setIrs(state->irs);
294  statusInfo->setFin_ack_rcvd(state->fin_ack_rcvd);
295 
296  msg->setControlInfo(statusInfo);
297  msg->setKind(TCP_I_STATUS);
298  sendToApp(msg);
299 }
uint32 snd_wl1
Definition: TCPConnection.h:169
uint32 rcv_up
Definition: TCPConnection.h:176
L3Address remoteAddr
Definition: TCPConnection.h:325
uint32 rcv_nxt
Definition: TCPConnection.h:174
cFSM fsm
Definition: TCPConnection.h:333
bool fin_ack_rcvd
Definition: TCPConnection.h:188
Definition: TCPConnection.h:63
uint32 snd_wnd
Definition: TCPConnection.h:167
uint32 snd_mss
Definition: TCPConnection.h:159
uint32 snd_nxt
Definition: TCPConnection.h:165
uint32 snd_wl2
Definition: TCPConnection.h:170
uint32 snd_up
Definition: TCPConnection.h:168
uint32 snd_una
Definition: TCPConnection.h:164
int localPort
Definition: TCPConnection.h:326
TCPStateVariables * state
Definition: TCPConnection.h:336
L3Address localAddr
Definition: TCPConnection.h:324
uint32 iss
Definition: TCPConnection.h:171
int remotePort
Definition: TCPConnection.h:327
uint32 irs
Definition: TCPConnection.h:177
Definition: TCPCommand_m.h:106
uint32 rcv_wnd
Definition: TCPConnection.h:175
virtual void sendToApp(cMessage *msg)
Utility: sends packet to application.
Definition: TCPConnectionUtil.cc:322
uint32 snd_max
Definition: TCPConnection.h:166
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
void inet::tcp::TCPConnection::process_TIMEOUT_2MSL ( )
protectedvirtual
1275 {
1276  //"
1277  // If the time-wait timeout expires on a connection delete the TCB,
1278  // enter the CLOSED state and return.
1279  //"
1280  switch (fsm.getState()) {
1281  case TCP_S_TIME_WAIT:
1282  // Nothing to do here. The TIMEOUT_2MSL event will automatically take
1283  // the connection to CLOSED. We already notified the user
1284  // (TCP_I_CLOSED) when we entered the TIME_WAIT state from CLOSING,
1285  // FIN_WAIT_1 or FIN_WAIT_2.
1286  break;
1287 
1288  default:
1289  // We should not receive this timeout in this state.
1290  throw cRuntimeError(tcpMain,
1291  "Internal error: received time-wait (2MSL) timeout in state %s",
1292  stateName(fsm.getState()));
1293  }
1294 }
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:74
TCP * tcpMain
Definition: TCPConnection.h:330
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
void inet::tcp::TCPConnection::process_TIMEOUT_CONN_ESTAB ( )
protectedvirtual
1255 {
1256  switch (fsm.getState()) {
1257  case TCP_S_SYN_RCVD:
1258  case TCP_S_SYN_SENT:
1259  // Nothing to do here. TIMEOUT_CONN_ESTAB event will automatically
1260  // take the connection to LISTEN or CLOSED, and cancel SYN-REXMIT timer.
1261  if (state->active) {
1262  // notify user if we're on the active side
1264  }
1265  break;
1266 
1267  default:
1268  // We should not receive this timeout in this state.
1269  throw cRuntimeError(tcpMain, "Internal error: received CONN_ESTAB timeout in state %s",
1270  stateName(fsm.getState()));
1271  }
1272 }
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TCPConnectionUtil.cc:293
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:66
bool active
Definition: TCPConnection.h:156
TCP * tcpMain
Definition: TCPConnection.h:330
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:67
Definition: TCPCommand_m.h:105
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
void inet::tcp::TCPConnection::process_TIMEOUT_FIN_WAIT_2 ( )
protectedvirtual
1297 {
1298  switch (fsm.getState()) {
1299  case TCP_S_FIN_WAIT_2:
1300  // Nothing to do here. The TIMEOUT_FIN_WAIT_2 event will automatically take
1301  // the connection to CLOSED.
1302  break;
1303 
1304  default:
1305  // We should not receive this timeout in this state.
1306  throw cRuntimeError(tcpMain, "Internal error: received FIN_WAIT_2 timeout in state %s",
1307  stateName(fsm.getState()));
1308  }
1309 }
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:72
TCP * tcpMain
Definition: TCPConnection.h:330
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
void inet::tcp::TCPConnection::process_TIMEOUT_SYN_REXMIT ( TCPEventCode event)
protectedvirtual
1323 {
1325  EV_INFO << "Retransmission count during connection setup exceeds " << MAX_SYN_REXMIT_COUNT << ", giving up\n";
1326  // Note ABORT will take the connection to closed, and cancel CONN-ESTAB timer as well
1327  event = TCP_E_ABORT;
1328  return;
1329  }
1330 
1331  EV_INFO << "Performing retransmission #" << state->syn_rexmit_count << "\n";
1332 
1333  // resend what's needed
1334  switch (fsm.getState()) {
1335  case TCP_S_SYN_SENT:
1336  sendSyn();
1337  break;
1338 
1339  case TCP_S_SYN_RCVD:
1340  sendSynAck();
1341  break;
1342 
1343  default:
1344  throw cRuntimeError(tcpMain, "Internal error: SYN-REXMIT timer expired while in state %s",
1345  stateName(fsm.getState()));
1346  }
1347 
1348  // reschedule timer
1349  state->syn_rexmit_timeout *= 2;
1350 
1353 
1355 }
simtime_t syn_rexmit_timeout
Definition: TCPConnection.h:183
#define TCP_TIMEOUT_SYN_REXMIT_MAX
Definition: TCPConnection.h:121
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:66
#define MAX_SYN_REXMIT_COUNT
Definition: TCPConnection.h:124
Definition: TCPConnection.h:90
virtual void sendSynAck()
Utility: send SYN+ACK.
Definition: TCPConnectionUtil.cc:481
TCP * tcpMain
Definition: TCPConnection.h:330
int syn_rexmit_count
Definition: TCPConnection.h:182
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:67
void scheduleTimeout(cMessage *msg, simtime_t timeout)
Utility: start a timer.
Definition: TCPConnection.h:524
virtual void sendSyn()
Utility: send SYN.
Definition: TCPConnectionUtil.cc:457
cMessage * synRexmitTimer
Definition: TCPConnection.h:354
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
bool inet::tcp::TCPConnection::processAckInEstabEtc ( TCPSegment tcpseg)
protectedvirtual

Referenced by processSegment1stThru8th().

1113 {
1114  EV_DETAIL << "Processing ACK in a data transfer state\n";
1115 
1116  //
1117  //"
1118  // If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
1119  // Any segments on the retransmission queue which are thereby
1120  // entirely acknowledged are removed. Users should receive
1121  // positive acknowledgments for buffers which have been SENT and
1122  // fully acknowledged (i.e., SEND buffer should be returned with
1123  // "ok" response). If the ACK is a duplicate
1124  // (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks
1125  // something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
1126  // drop the segment, and return.
1127  //
1128  // If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
1129  // updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
1130  // SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
1131  // SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
1132  //
1133  // Note that SND.WND is an offset from SND.UNA, that SND.WL1
1134  // records the sequence number of the last segment used to update
1135  // SND.WND, and that SND.WL2 records the acknowledgment number of
1136  // the last segment used to update SND.WND. The check here
1137  // prevents using old segments to update the window.
1138  //"
1139  // Note: should use SND.MAX instead of SND.NXT in above checks
1140  //
1141  if (seqGE(state->snd_una, tcpseg->getAckNo())) {
1142  //
1143  // duplicate ACK? A received TCP segment is a duplicate ACK if all of
1144  // the following apply:
1145  // (1) snd_una == ackNo
1146  // (2) segment contains no data
1147  // (3) there's unacked data (snd_una != snd_max)
1148  //
1149  // Note: ssfnet uses additional constraint "window is the same as last
1150  // received (not an update)" -- we don't do that because window updates
1151  // are ignored anyway if neither seqNo nor ackNo has changed.
1152  //
1153  if (state->snd_una == tcpseg->getAckNo() && tcpseg->getPayloadLength() == 0 && state->snd_una != state->snd_max) {
1154  state->dupacks++;
1155 
1156  if (dupAcksVector)
1157  dupAcksVector->record(state->dupacks);
1158 
1159  // we need to update send window even if the ACK is a dupACK, because rcv win
1160  // could have been changed if faulty data receiver is not respecting the "do not shrink window" rule
1161  updateWndInfo(tcpseg);
1162 
1164  }
1165  else {
1166  // if doesn't qualify as duplicate ACK, just ignore it.
1167  if (tcpseg->getPayloadLength() == 0) {
1168  if (state->snd_una != tcpseg->getAckNo())
1169  EV_DETAIL << "Old ACK: ackNo < snd_una\n";
1170  else if (state->snd_una == state->snd_max)
1171  EV_DETAIL << "ACK looks duplicate but we have currently no unacked data (snd_una == snd_max)\n";
1172  }
1173 
1174  // reset counter
1175  state->dupacks = 0;
1176 
1177  if (dupAcksVector)
1178  dupAcksVector->record(state->dupacks);
1179  }
1180  }
1181  else if (seqLE(tcpseg->getAckNo(), state->snd_max)) {
1182  // ack in window.
1183  uint32 old_snd_una = state->snd_una;
1184  state->snd_una = tcpseg->getAckNo();
1185 
1186  if (unackedVector)
1187  unackedVector->record(state->snd_max - state->snd_una);
1188 
1189  // after retransmitting a lost segment, we may get an ack well ahead of snd_nxt
1190  if (seqLess(state->snd_nxt, state->snd_una))
1191  state->snd_nxt = state->snd_una;
1192 
1193  // RFC 1323, page 36:
1194  // "If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
1195  // Also compute a new estimate of round-trip time. If Snd.TS.OK
1196  // bit is on, use my.TSclock - SEG.TSecr; otherwise use the
1197  // elapsed time since the first segment in the retransmission
1198  // queue was sent. Any segments on the retransmission queue
1199  // which are thereby entirely acknowledged."
1200  if (state->ts_enabled)
1202  // Note: If TS is disabled the RTT measurement is completed in TCPBaseAlg::receivedDataAck()
1203 
1204  uint32 discardUpToSeq = state->snd_una;
1205 
1206  // our FIN acked?
1207  if (state->send_fin && tcpseg->getAckNo() == state->snd_fin_seq + 1) {
1208  // set flag that our FIN has been acked
1209  EV_DETAIL << "ACK acks our FIN\n";
1210  state->fin_ack_rcvd = true;
1211  discardUpToSeq--; // the FIN sequence number is not real data
1212  }
1213 
1214  // acked data no longer needed in send queue
1215  sendQueue->discardUpTo(discardUpToSeq);
1216 
1217  // acked data no longer needed in rexmit queue
1218  if (state->sack_enabled)
1219  rexmitQueue->discardUpTo(discardUpToSeq);
1220 
1221  updateWndInfo(tcpseg);
1222 
1223  // if segment contains data, wait until data has been forwarded to app before sending ACK,
1224  // otherwise we would use an old ACKNo
1225  if (tcpseg->getPayloadLength() == 0 && fsm.getState() != TCP_S_SYN_RCVD) {
1226  // notify
1227  tcpAlgorithm->receivedDataAck(old_snd_una);
1228 
1229  // in the receivedDataAck we need the old value
1230  state->dupacks = 0;
1231 
1232  if (dupAcksVector)
1233  dupAcksVector->record(state->dupacks);
1234  }
1235  }
1236  else {
1237  ASSERT(seqGreater(tcpseg->getAckNo(), state->snd_max)); // from if-ladder
1238 
1239  // send an ACK, drop the segment, and return.
1240  tcpAlgorithm->receivedAckForDataNotYetSent(tcpseg->getAckNo());
1241  state->dupacks = 0;
1242 
1243  if (dupAcksVector)
1244  dupAcksVector->record(state->dupacks);
1245 
1246  return false; // means "drop"
1247  }
1248 
1249  return true;
1250 }
bool ts_enabled
Definition: TCPConnection.h:226
bool seqGE(uint32 a, uint32 b)
Definition: TCPSegment.h:35
bool send_fin
Definition: TCPConnection.h:190
virtual uint32 getTSecr(TCPSegment *tcpseg) const
Utility: get TSecr from segments TS header option.
Definition: TCPConnectionUtil.cc:1236
cOutVector * unackedVector
Definition: TCPConnection.h:364
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
cFSM fsm
Definition: TCPConnection.h:333
virtual void rttMeasurementCompleteUsingTS(uint32 echoedTS)=0
Converting uint32 echoedTS to simtime_t and calling rttMeasurementComplete() to update state vars wit...
bool fin_ack_rcvd
Definition: TCPConnection.h:188
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
virtual void updateWndInfo(TCPSegment *tcpseg, bool doAlways=false)
Utility: update window information (snd_wnd, snd_wl1, snd_wl2)
Definition: TCPConnectionUtil.cc:1309
bool sack_enabled
Definition: TCPConnection.h:235
uint32 snd_nxt
Definition: TCPConnection.h:165
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
virtual void receivedAckForDataNotYetSent(uint32 seq)=0
Called after we received an ACK for data not yet sent.
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
uint32 dupacks
Definition: TCPConnection.h:255
uint32 snd_fin_seq
Definition: TCPConnection.h:191
virtual void discardUpTo(uint32 seqNum)=0
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed...
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void discardUpTo(uint32 seqNum)
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed...
Definition: TCPSACKRexmitQueue.cc:65
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
Definition: TCPConnection.h:67
virtual void receivedDuplicateAck()=0
Called after we received a duplicate ACK (that is: ackNo == snd_una, no data in segment, segment doesn&#39;t carry window update, and also, we have unacked data).
cOutVector * dupAcksVector
Definition: TCPConnection.h:366
virtual void receivedDataAck(uint32 firstSeqAcked)=0
Called after we received an ACK which acked some data (that is, we could advance snd_una).
uint32 snd_max
Definition: TCPConnection.h:166
bool inet::tcp::TCPConnection::processAppCommand ( cMessage *  msg)
virtual

Process commands from the application.

Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).

Referenced by inet::tcp::TCP::handleMessage().

322 {
323  printConnBrief();
324 
325  // first do actions
326  TCPCommand *tcpCommand = (TCPCommand *)(msg->removeControlInfo());
327  TCPEventCode event = preanalyseAppCommandEvent(msg->getKind());
328  EV_INFO << "App command: " << eventName(event) << "\n";
329 
330  switch (event) {
331  case TCP_E_OPEN_ACTIVE:
332  process_OPEN_ACTIVE(event, tcpCommand, msg);
333  break;
334 
335  case TCP_E_OPEN_PASSIVE:
336  process_OPEN_PASSIVE(event, tcpCommand, msg);
337  break;
338 
339  case TCP_E_SEND:
340  process_SEND(event, tcpCommand, msg);
341  break;
342 
343  case TCP_E_CLOSE:
344  process_CLOSE(event, tcpCommand, msg);
345  break;
346 
347  case TCP_E_ABORT:
348  process_ABORT(event, tcpCommand, msg);
349  break;
350 
351  case TCP_E_STATUS:
352  process_STATUS(event, tcpCommand, msg);
353  break;
354 
356  process_QUEUE_BYTES_LIMIT(event, tcpCommand, msg);
357  break;
358 
359  case TCP_E_READ:
360  process_READ_REQUEST(event, tcpCommand, msg);
361  break;
362 
363  default:
364  throw cRuntimeError(tcpMain, "wrong event code");
365  }
366 
367  // then state transitions
368  return performStateTransition(event);
369 }
virtual void printConnBrief() const
Utility: prints local/remote addr/port and app gate index/connId.
Definition: TCPConnectionUtil.cc:148
virtual void process_READ_REQUEST(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:161
virtual void process_QUEUE_BYTES_LIMIT(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:301
virtual void process_SEND(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:111
virtual bool performStateTransition(const TCPEventCode &event)
Implemements the pure TCP state machine.
Definition: TCPConnectionBase.cc:403
Definition: TCPConnection.h:88
TCPEventCode
Definition: TCPConnection.h:81
virtual TCPEventCode preanalyseAppCommandEvent(int commandCode)
Maps app command codes (msg kind of app command msgs) to TCP_E_xxx event codes.
Definition: TCPConnectionBase.cc:371
Definition: TCPConnection.h:90
Definition: TCPConnection.h:86
Definition: TCPConnection.h:87
TCP * tcpMain
Definition: TCPConnection.h:330
Definition: TCPConnection.h:89
virtual void process_OPEN_PASSIVE(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:79
virtual void process_CLOSE(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:175
virtual void process_ABORT(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:235
Definition: TCPConnection.h:91
static const char * eventName(int event)
Utility: returns name of TCP_E_xxx constants.
Definition: TCPConnectionUtil.cc:68
virtual void process_OPEN_ACTIVE(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:35
Definition: TCPConnection.h:93
Definition: TCPConnection.h:92
virtual void process_STATUS(TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Definition: TCPConnectionEventProc.cc:264
bool inet::tcp::TCPConnection::processMSSOption ( TCPSegment tcpseg,
const TCPOptionMaxSegmentSize option 
)
protectedvirtual

Referenced by readHeaderOptions().

940 {
941  if (option.getLength() != 4) {
942  EV_ERROR << "ERROR: MSS option length incorrect\n";
943  return false;
944  }
945 
946  if (fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) {
947  EV_ERROR << "ERROR: TCP Header Option MSS received, but in unexpected state\n";
948  return false;
949  }
950 
951  // RFC 2581, page 1:
952  // "The SMSS is the size of the largest segment that the sender can transmit.
953  // This value can be based on the maximum transmission unit of the network,
954  // the path MTU discovery [MD90] algorithm, RMSS (see next item), or other
955  // factors. The size does not include the TCP/IP headers and options."
956  //
957  // "The RMSS is the size of the largest segment the receiver is willing to accept.
958  // This is the value specified in the MSS option sent by the receiver during
959  // connection startup. Or, if the MSS option is not used, 536 bytes [Bra89].
960  // The size does not include the TCP/IP headers and options."
961  //
962  //
963  // The value of snd_mss (SMSS) is set to the minimum of snd_mss (local parameter) and
964  // the value specified in the MSS option received during connection startup.
965  state->snd_mss = std::min(state->snd_mss, (uint32)option.getMaxSegmentSize());
966 
967  if (state->snd_mss == 0)
968  state->snd_mss = 536;
969 
970  EV_INFO << "TCP Header Option MSS(=" << option.getMaxSegmentSize() << ") received, SMSS is set to " << state->snd_mss << "\n";
971  return true;
972 }
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SCTPAssociation.h:270
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:66
uint32 snd_mss
Definition: TCPConnection.h:159
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:65
TCPEventCode inet::tcp::TCPConnection::processRstInSynReceived ( TCPSegment tcpseg)
protectedvirtual

Referenced by processSegment1stThru8th().

1082 {
1083  EV_DETAIL << "Processing RST in SYN_RCVD\n";
1084 
1085  //"
1086  // If this connection was initiated with a passive OPEN (i.e.,
1087  // came from the LISTEN state), then return this connection to
1088  // LISTEN state and return. The user need not be informed. If
1089  // this connection was initiated with an active OPEN (i.e., came
1090  // from SYN-SENT state) then the connection was refused, signal
1091  // the user "connection refused". In either case, all segments
1092  // on the retransmission queue should be removed. And in the
1093  // active OPEN case, enter the CLOSED state and delete the TCB,
1094  // and return.
1095  //"
1096 
1097  sendQueue->discardUpTo(sendQueue->getBufferEndSeq()); // flush send queue
1098 
1099  if (state->sack_enabled)
1100  rexmitQueue->discardUpTo(rexmitQueue->getBufferEndSeq()); // flush rexmit queue
1101 
1102  if (state->active) {
1103  // signal "connection refused"
1105  }
1106 
1107  // on RCV_RST, FSM will go either to LISTEN or to CLOSED, depending on state->active
1108  // FIXME if this was a forked connection, it should rather close than go back to listening (otherwise we'd now have two listening connections with the original one!)
1109  return TCP_E_RCV_RST;
1110 }
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TCPConnectionUtil.cc:293
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
bool active
Definition: TCPConnection.h:156
bool sack_enabled
Definition: TCPConnection.h:235
Definition: TCPConnection.h:102
virtual void discardUpTo(uint32 seqNum)=0
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed...
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void discardUpTo(uint32 seqNum)
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed...
Definition: TCPSACKRexmitQueue.cc:65
virtual uint32 getBufferEndSeq() const
Returns the sequence number of the last byte stored in the buffer plus one.
Definition: TCPSACKRexmitQueue.h:97
virtual uint32 getBufferEndSeq()=0
Returns the sequence number of the last byte stored in the buffer plus one.
Definition: TCPCommand_m.h:103
bool inet::tcp::TCPConnection::processSACKOption ( TCPSegment tcpseg,
const TCPOptionSack option 
)
protectedvirtual

Referenced by readHeaderOptions().

40 {
41  if (option.getLength() % 8 != 2) {
42  EV_ERROR << "ERROR: option length incorrect\n";
43  return false;
44  }
45 
46  uint n = option.getSackItemArraySize();
47  ASSERT(option.getLength() == 2 + n*8);
48 
49  if (!state->sack_enabled) {
50  EV_ERROR << "ERROR: " << n << " SACK(s) received, but sack_enabled is set to false\n";
51  return false;
52  }
53 
54  if (fsm.getState() != TCP_S_SYN_RCVD && fsm.getState() != TCP_S_ESTABLISHED
55  && fsm.getState() != TCP_S_FIN_WAIT_1 && fsm.getState() != TCP_S_FIN_WAIT_2)
56  {
57  EV_ERROR << "ERROR: TCP Header Option SACK received, but in unexpected state\n";
58  return false;
59  }
60 
61  if (n > 0) { // sacks present?
62  EV_INFO << n << " SACK(s) received:\n";
63  for (uint i = 0; i < n; i++) {
64  Sack tmp;
65  tmp.setStart(option.getSackItem(i).getStart());
66  tmp.setEnd(option.getSackItem(i).getEnd());
67 
68  EV_INFO << (i + 1) << ". SACK: " << tmp.str() << endl;
69 
70  // check for D-SACK
71  if (i == 0 && seqLE(tmp.getEnd(), tcpseg->getAckNo())) {
72  // RFC 2883, page 8:
73  // "In order for the sender to check that the first (D)SACK block of an
74  // acknowledgement in fact acknowledges duplicate data, the sender
75  // should compare the sequence space in the first SACK block to the
76  // cumulative ACK which is carried IN THE SAME PACKET. If the SACK
77  // sequence space is less than this cumulative ACK, it is an indication
78  // that the segment identified by the SACK block has been received more
79  // than once by the receiver. An implementation MUST NOT compare the
80  // sequence space in the SACK block to the TCP state variable snd.una
81  // (which carries the total cumulative ACK), as this may result in the
82  // wrong conclusion if ACK packets are reordered."
83  EV_DETAIL << "Received D-SACK below cumulative ACK=" << tcpseg->getAckNo()
84  << " D-SACK: " << tmp.str() << endl;
85  // Note: RFC 2883 does not specify what should be done in this case.
86  // RFC 2883, page 9:
87  // "5. Detection of Duplicate Packets
88  // (...) This document does not specify what action a TCP implementation should
89  // take in these cases. The extension to the SACK option simply enables
90  // the sender to detect each of these cases.(...)"
91  }
92  else if (i == 0 && n > 1 && seqGreater(tmp.getEnd(), tcpseg->getAckNo())) {
93  // RFC 2883, page 8:
94  // "If the sequence space in the first SACK block is greater than the
95  // cumulative ACK, then the sender next compares the sequence space in
96  // the first SACK block with the sequence space in the second SACK
97  // block, if there is one. This comparison can determine if the first
98  // SACK block is reporting duplicate data that lies above the cumulative
99  // ACK."
100  Sack tmp2(option.getSackItem(1).getStart(), option.getSackItem(1).getEnd());
101 
102  if (tmp2.contains(tmp)) {
103  EV_DETAIL << "Received D-SACK above cumulative ACK=" << tcpseg->getAckNo()
104  << " D-SACK: " << tmp.str()
105  << ", SACK: " << tmp2.str() << endl;
106  // Note: RFC 2883 does not specify what should be done in this case.
107  // RFC 2883, page 9:
108  // "5. Detection of Duplicate Packets
109  // (...) This document does not specify what action a TCP implementation should
110  // take in these cases. The extension to the SACK option simply enables
111  // the sender to detect each of these cases.(...)"
112  }
113  }
114 
115  if (seqGreater(tmp.getEnd(), tcpseg->getAckNo()) && seqGreater(tmp.getEnd(), state->snd_una))
116  rexmitQueue->setSackedBit(tmp.getStart(), tmp.getEnd());
117  else
118  EV_DETAIL << "Received SACK below total cumulative ACK snd_una=" << state->snd_una << "\n";
119  }
120  state->rcv_sacks += n; // total counter, no current number
121 
122  if (rcvSacksVector)
123  rcvSacksVector->record(state->rcv_sacks);
124 
125  // update scoreboard
126  state->sackedBytes_old = state->sackedBytes; // needed for RFC 3042 to check if last dupAck contained new sack information
128 
129  if (sackedBytesVector)
131  }
132  return true;
133 }
Definition: TCPConnection.h:68
cOutVector * sackedBytesVector
Definition: TCPConnection.h:373
uint32 sackedBytes
Definition: TCPConnection.h:246
unsigned int uint
Definition: INETDefs.h:63
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:72
bool sack_enabled
Definition: TCPConnection.h:235
virtual void setSackedBit(uint32 fromSeqNum, uint32 toSeqNum)
Called when data sender received selective acknowledgments.
Definition: TCPSACKRexmitQueue.cc:188
uint32 sackedBytes_old
Definition: TCPConnection.h:247
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
uint32 snd_una
Definition: TCPConnection.h:164
uint32 rcv_sacks
Definition: TCPConnection.h:257
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:71
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
Definition: TCPConnection.h:67
cOutVector * rcvSacksVector
Definition: TCPConnection.h:369
virtual uint32 getTotalAmountOfSackedBytes() const
Returns total amount of sacked bytes.
Definition: TCPSACKRexmitQueue.cc:313
bool inet::tcp::TCPConnection::processSACKPermittedOption ( TCPSegment tcpseg,
const TCPOptionSackPermitted option 
)
protectedvirtual

Referenced by readHeaderOptions().

1048 {
1049  if (option.getLength() != 2) {
1050  EV_ERROR << "ERROR: length incorrect\n";
1051  return false;
1052  }
1053 
1054  if (fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) {
1055  EV_ERROR << "ERROR: TCP Header Option SACK_PERMITTED received, but in unexpected state\n";
1056  return false;
1057  }
1058 
1059  state->rcv_sack_perm = true;
1061  EV_INFO << "TCP Header Option SACK_PERMITTED received, SACK (sack_enabled) is set to " << state->sack_enabled << "\n";
1062  return true;
1063 }
bool sack_support
Definition: TCPConnection.h:234
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:66
bool sack_enabled
Definition: TCPConnection.h:235
bool rcv_sack_perm
Definition: TCPConnection.h:237
bool snd_sack_perm
Definition: TCPConnection.h:236
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:65
TCPEventCode inet::tcp::TCPConnection::processSegment1stThru8th ( TCPSegment tcpseg)
protectedvirtual

Referenced by process_RCV_SEGMENT().

132 {
133  //
134  // RFC 793: first check sequence number
135  //
136 
137  bool acceptable = true;
138 
139  if (tcpseg->getHeaderLength() > TCP_HEADER_OCTETS) { // Header options present? TCP_HEADER_OCTETS = 20
140  // PAWS
141  if (state->ts_enabled) {
142  uint32 tsval = getTSval(tcpseg);
143  if (tsval != 0 && seqLess(tsval, state->ts_recent) &&
144  (simTime() - state->time_last_data_sent) > PAWS_IDLE_TIME_THRESH) // PAWS_IDLE_TIME_THRESH = 24 days
145  {
146  EV_DETAIL << "PAWS: Segment is not acceptable, TSval=" << tsval << " in "
147  << stateName(fsm.getState()) << " state received: dropping segment\n";
148  acceptable = false;
149  }
150  }
151 
152  readHeaderOptions(tcpseg);
153  }
154 
155  if (acceptable)
156  acceptable = isSegmentAcceptable(tcpseg);
157 
158  if (!acceptable) {
159  //"
160  // If an incoming segment is not acceptable, an acknowledgment
161  // should be sent in reply (unless the RST bit is set, if so drop
162  // the segment and return):
163  //
164  // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
165  //"
166  if (tcpseg->getRstBit()) {
167  EV_DETAIL << "RST with unacceptable seqNum: dropping\n";
168  }
169  else {
170  if (tcpseg->getSynBit()) {
171  EV_DETAIL << "SYN with unacceptable seqNum in " << stateName(fsm.getState()) << " state received (SYN duplicat?)\n";
172  }
173  else if (tcpseg->getPayloadLength() > 0 && state->sack_enabled && seqLess((tcpseg->getSequenceNo() + tcpseg->getPayloadLength()), state->rcv_nxt)) {
174  state->start_seqno = tcpseg->getSequenceNo();
175  state->end_seqno = tcpseg->getSequenceNo() + tcpseg->getPayloadLength();
176  state->snd_dsack = true;
177  EV_DETAIL << "SND_D-SACK SET (dupseg rcvd)\n";
178  }
179 
180  EV_DETAIL << "Segment seqNum not acceptable, sending ACK with current receive seq\n";
181  // RFC 2018, page 4:
182  // "The receiver SHOULD send an ACK for every valid segment that arrives
183  // containing new data, and each of these "duplicate" ACKs SHOULD bear a
184  // SACK option."
185  //
186  // The received segment is not "valid" therefore the ACK will not bear a SACK option, if snd_dsack (D-SACK) is not set.
187  sendAck();
188  }
189 
190  state->rcv_naseg++;
191 
192  if (rcvNASegVector)
193  rcvNASegVector->record(state->rcv_naseg);
194 
195  return TCP_E_IGNORE;
196  }
197 
198  //
199  // RFC 793: second check the RST bit,
200  //
201  if (tcpseg->getRstBit()) {
202  // Note: if we come from LISTEN, processSegmentInListen() has already handled RST.
203  switch (fsm.getState()) {
204  case TCP_S_SYN_RCVD:
205  //"
206  // If this connection was initiated with a passive OPEN (i.e.,
207  // came from the LISTEN state), then return this connection to
208  // LISTEN state and return. The user need not be informed. If
209  // this connection was initiated with an active OPEN (i.e., came
210  // from SYN-SENT state) then the connection was refused, signal
211  // the user "connection refused". In either case, all segments
212  // on the retransmission queue should be removed. And in the
213  // active OPEN case, enter the CLOSED state and delete the TCB,
214  // and return.
215  //"
216  return processRstInSynReceived(tcpseg);
217 
218  case TCP_S_ESTABLISHED:
219  case TCP_S_FIN_WAIT_1:
220  case TCP_S_FIN_WAIT_2:
221  case TCP_S_CLOSE_WAIT:
222  //"
223  // If the RST bit is set then, any outstanding RECEIVEs and SEND
224  // should receive "reset" responses. All segment queues should be
225  // flushed. Users should also receive an unsolicited general
226  // "connection reset" signal.
227  //
228  // Enter the CLOSED state, delete the TCB, and return.
229  //"
230  EV_DETAIL << "RST: performing connection reset, closing connection\n";
232  return TCP_E_RCV_RST; // this will trigger state transition
233 
234  case TCP_S_CLOSING:
235  case TCP_S_LAST_ACK:
236  case TCP_S_TIME_WAIT:
237  //"
238  // enter the CLOSED state, delete the TCB, and return.
239  //"
240  EV_DETAIL << "RST: closing connection\n";
241  return TCP_E_RCV_RST; // this will trigger state transition
242 
243  default:
244  ASSERT(0);
245  break;
246  }
247  }
248 
249  // RFC 793: third check security and precedence
250  // This step is ignored.
251 
252  //
253  // RFC 793: fourth, check the SYN bit,
254  //
255  if (tcpseg->getSynBit()) {
256  //"
257  // If the SYN is in the window it is an error, send a reset, any
258  // outstanding RECEIVEs and SEND should receive "reset" responses,
259  // all segment queues should be flushed, the user should also
260  // receive an unsolicited general "connection reset" signal, enter
261  // the CLOSED state, delete the TCB, and return.
262  //
263  // If the SYN is not in the window this step would not be reached
264  // and an ack would have been sent in the first step (sequence
265  // number check).
266  //"
267 
268  ASSERT(isSegmentAcceptable(tcpseg)); // assert SYN is in the window
269  EV_DETAIL << "SYN is in the window: performing connection reset, closing connection\n";
271  return TCP_E_RCV_UNEXP_SYN;
272  }
273 
274  //
275  // RFC 793: fifth check the ACK field,
276  //
277  if (!tcpseg->getAckBit()) {
278  // if the ACK bit is off drop the segment and return
279  EV_INFO << "ACK not set, dropping segment\n";
280  return TCP_E_IGNORE;
281  }
282 
283  uint32 old_snd_una = state->snd_una;
284 
285  TCPEventCode event = TCP_E_IGNORE;
286 
287  if (fsm.getState() == TCP_S_SYN_RCVD) {
288  //"
289  // If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state
290  // and continue processing.
291  //
292  // If the segment acknowledgment is not acceptable, form a
293  // reset segment,
294  //
295  // <SEQ=SEG.ACK><CTL=RST>
296  //
297  // and send it.
298  //"
299  if (!seqLE(state->snd_una, tcpseg->getAckNo()) || !seqLE(tcpseg->getAckNo(), state->snd_nxt)) {
300  sendRst(tcpseg->getAckNo());
301  return TCP_E_IGNORE;
302  }
303 
304  // notify tcpAlgorithm and app layer
305  tcpAlgorithm->established(false);
307 
308  // This will trigger transition to ESTABLISHED. Timers and notifying
309  // app will be taken care of in stateEntered().
310  event = TCP_E_RCV_ACK;
311  }
312 
313  uint32 old_snd_nxt = state->snd_nxt; // later we'll need to see if snd_nxt changed
314  // Note: If one of the last data segments is lost while already in LAST-ACK state (e.g. if using TCPEchoApps)
315  // TCP must be able to process acceptable acknowledgments, however please note RFC 793, page 73:
316  // "LAST-ACK STATE
317  // The only thing that can arrive in this state is an
318  // acknowledgment of our FIN. If our FIN is now acknowledged,
319  // delete the TCB, enter the CLOSED state, and return."
320  if (fsm.getState() == TCP_S_SYN_RCVD || fsm.getState() == TCP_S_ESTABLISHED ||
321  fsm.getState() == TCP_S_FIN_WAIT_1 || fsm.getState() == TCP_S_FIN_WAIT_2 ||
322  fsm.getState() == TCP_S_CLOSE_WAIT || fsm.getState() == TCP_S_CLOSING ||
323  fsm.getState() == TCP_S_LAST_ACK)
324  {
325  //
326  // ESTABLISHED processing:
327  //"
328  // If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
329  // Any segments on the retransmission queue which are thereby
330  // entirely acknowledged are removed. Users should receive
331  // positive acknowledgments for buffers which have been SENT and
332  // fully acknowledged (i.e., SEND buffer should be returned with
333  // "ok" response). If the ACK is a duplicate
334  // (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks
335  // something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
336  // drop the segment, and return.
337  //
338  // If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
339  // updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
340  // SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
341  // SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
342  //
343  // Note that SND.WND is an offset from SND.UNA, that SND.WL1
344  // records the sequence number of the last segment used to update
345  // SND.WND, and that SND.WL2 records the acknowledgment number of
346  // the last segment used to update SND.WND. The check here
347  // prevents using old segments to update the window.
348  //"
349  bool ok = processAckInEstabEtc(tcpseg);
350 
351  if (!ok)
352  return TCP_E_IGNORE; // if acks something not yet sent, drop it
353  }
354 
355  if ((fsm.getState() == TCP_S_FIN_WAIT_1 && state->fin_ack_rcvd)) {
356  //"
357  // FIN-WAIT-1 STATE
358  // In addition to the processing for the ESTABLISHED state, if
359  // our FIN is now acknowledged then enter FIN-WAIT-2 and continue
360  // processing in that state.
361  //"
362  event = TCP_E_RCV_ACK; // will trigger transition to FIN-WAIT-2
363  }
364 
365  if (fsm.getState() == TCP_S_FIN_WAIT_2) {
366  //"
367  // FIN-WAIT-2 STATE
368  // In addition to the processing for the ESTABLISHED state, if
369  // the retransmission queue is empty, the user's CLOSE can be
370  // acknowledged ("ok") but do not delete the TCB.
371  //"
372  // nothing to do here (in our model, used commands don't need to be
373  // acknowledged)
374  }
375 
376  if (fsm.getState() == TCP_S_CLOSING) {
377  //"
378  // In addition to the processing for the ESTABLISHED state, if
379  // the ACK acknowledges our FIN then enter the TIME-WAIT state,
380  // otherwise ignore the segment.
381  //"
382  if (state->fin_ack_rcvd) {
383  EV_INFO << "Our FIN acked -- can go to TIME_WAIT now\n";
384  event = TCP_E_RCV_ACK; // will trigger transition to TIME-WAIT
386 
387  // we're entering TIME_WAIT, so we can signal CLOSED the user
388  // (the only thing left to do is wait until the 2MSL timer expires)
389  }
390  }
391 
392  if (fsm.getState() == TCP_S_LAST_ACK) {
393  //"
394  // The only thing that can arrive in this state is an
395  // acknowledgment of our FIN. If our FIN is now acknowledged,
396  // delete the TCB, enter the CLOSED state, and return.
397  //"
398  if (state->send_fin && tcpseg->getAckNo() == state->snd_fin_seq + 1) {
399  EV_INFO << "Last ACK arrived\n";
400  return TCP_E_RCV_ACK; // will trigger transition to CLOSED
401  }
402  }
403 
404  if (fsm.getState() == TCP_S_TIME_WAIT) {
405  //"
406  // The only thing that can arrive in this state is a
407  // retransmission of the remote FIN. Acknowledge it, and restart
408  // the 2 MSL timeout.
409  //"
410  // And we are staying in the TIME_WAIT state.
411  //
412  sendAck();
415  }
416 
417  //
418  // RFC 793: sixth, check the URG bit,
419  //
420  if (tcpseg->getUrgBit() && (fsm.getState() == TCP_S_ESTABLISHED ||
421  fsm.getState() == TCP_S_FIN_WAIT_1 || fsm.getState() == TCP_S_FIN_WAIT_2))
422  {
423  //"
424  // If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal
425  // the user that the remote side has urgent data if the urgent
426  // pointer (RCV.UP) is in advance of the data consumed. If the
427  // user has already been signaled (or is still in the "urgent
428  // mode") for this continuous sequence of urgent data, do not
429  // signal the user again.
430  //"
431 
432  // TBD: URG currently not supported
433  }
434 
435  //
436  // RFC 793: seventh, process the segment text,
437  //
438  uint32 old_rcv_nxt = state->rcv_nxt; // if rcv_nxt changes, we need to send/schedule an ACK
439 
440  if (fsm.getState() == TCP_S_SYN_RCVD || fsm.getState() == TCP_S_ESTABLISHED ||
441  fsm.getState() == TCP_S_FIN_WAIT_1 || fsm.getState() == TCP_S_FIN_WAIT_2)
442  {
443  //"
444  // Once in the ESTABLISHED state, it is possible to deliver segment
445  // text to user RECEIVE buffers. Text from segments can be moved
446  // into buffers until either the buffer is full or the segment is
447  // empty. If the segment empties and carries an PUSH flag, then
448  // the user is informed, when the buffer is returned, that a PUSH
449  // has been received.
450  //
451  // When the TCP takes responsibility for delivering the data to the
452  // user it must also acknowledge the receipt of the data.
453  //
454  // Once the TCP takes responsibility for the data it advances
455  // RCV.NXT over the data accepted, and adjusts RCV.WND as
456  // apporopriate to the current buffer availability. The total of
457  // RCV.NXT and RCV.WND should not be reduced.
458  //
459  // Please note the window management suggestions in section 3.7.
460  //
461  // Send an acknowledgment of the form:
462  //
463  // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
464  //
465  // This acknowledgment should be piggybacked on a segment being
466  // transmitted if possible without incurring undue delay.
467  //"
468 
469  if (tcpseg->getPayloadLength() > 0) {
470  // check for full sized segment
471  if (tcpseg->getPayloadLength() == state->snd_mss || tcpseg->getPayloadLength() + tcpseg->getHeaderLength() - TCP_HEADER_OCTETS == state->snd_mss)
473 
474  // check for persist probe
475  if (tcpseg->getPayloadLength() == 1)
476  state->ack_now = true; // TODO how to check if it is really a persist probe?
477 
478  tcpseg->truncateSegment(state->rcv_nxt, state->rcv_nxt + state->rcv_wnd);
479 
481 
482  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpseg)) { // enough freeRcvBuffer in rcvQueue for new segment?
483  EV_DETAIL << "Processing segment text in a data transfer state\n";
484 
485  // insert into receive buffers. If this segment is contiguous with
486  // previously received ones (seqNo == rcv_nxt), rcv_nxt can be increased;
487  // otherwise it stays the same but the data must be cached nevertheless
488  // (to avoid "Failure to retain above-sequence data" problem, RFC 2525
489  // section 2.5).
490 
491  uint32 old_usedRcvBuffer = state->usedRcvBuffer;
493 
494  if (seqGreater(state->snd_una, old_snd_una)) {
495  // notify
496  tcpAlgorithm->receivedDataAck(old_snd_una);
497 
498  // in the receivedDataAck we need the old value
499  state->dupacks = 0;
500 
501  if (dupAcksVector)
502  dupAcksVector->record(state->dupacks);
503  }
504 
505  // out-of-order segment?
506  if (old_rcv_nxt == state->rcv_nxt) {
507  state->rcv_oooseg++;
508 
509  if (rcvOooSegVector)
510  rcvOooSegVector->record(state->rcv_oooseg);
511 
512  // RFC 2018, page 4:
513  // "The receiver SHOULD send an ACK for every valid segment that arrives
514  // containing new data, and each of these "duplicate" ACKs SHOULD bear a
515  // SACK option."
516  if (state->sack_enabled) {
517  // store start and end sequence numbers of current oooseg in state variables
518  state->start_seqno = tcpseg->getSequenceNo();
519  state->end_seqno = tcpseg->getSequenceNo() + tcpseg->getPayloadLength();
520 
521  if (old_usedRcvBuffer == receiveQueue->getAmountOfBufferedBytes()) { // D-SACK
522  state->snd_dsack = true;
523  EV_DETAIL << "SND_D-SACK SET (old_rcv_nxt == rcv_nxt duplicated oooseg rcvd)\n";
524  }
525  else { // SACK
526  state->snd_sack = true;
527  EV_DETAIL << "SND_SACK SET (old_rcv_nxt == rcv_nxt oooseg rcvd)\n";
528  }
529  }
530 
532  }
533  else {
534  // forward data to app
535  //
536  // FIXME observe PSH bit
537  //
538  // FIXME we should implement socket READ command, and pass up only
539  // as many bytes as requested. rcv_wnd should be decreased
540  // accordingly!
541  //
542  cMessage *msg = nullptr;
543 
545  msg = new cMessage("Data Notification");
546  msg->setKind(TCP_I_DATA_NOTIFICATION); // TBD currently we never send TCP_I_URGENT_DATA
547  TCPCommand *cmd = new TCPCommand();
548  cmd->setConnId(connId);
549  msg->setControlInfo(cmd);
550  sendToApp(msg);
551  } else {
552  while ((msg = receiveQueue->extractBytesUpTo(state->rcv_nxt)) != nullptr) {
553  msg->setKind(TCP_I_DATA); // TBD currently we never send TCP_I_URGENT_DATA
554  TCPCommand *cmd = new TCPCommand();
555  cmd->setConnId(connId);
556  msg->setControlInfo(cmd);
557  sendToApp(msg);
558  }
559  }
560 
561  // if this segment "filled the gap" until the previously arrived segment
562  // that carried a FIN (i.e.rcv_nxt == rcv_fin_seq), we have to advance
563  // rcv_nxt over the FIN.
564  if (state->fin_rcvd && state->rcv_nxt == state->rcv_fin_seq) {
565  state->ack_now = true; // although not mentioned in [Stevens, W.R.: TCP/IP Illustrated, Volume 2, page 861] seems like we have to set ack_now
566  EV_DETAIL << "All segments arrived up to the FIN segment, advancing rcv_nxt over the FIN\n";
567  state->rcv_nxt = state->rcv_fin_seq + 1;
568  // state transitions will be done in the state machine, here we just set
569  // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
570  event = TCP_E_RCV_FIN;
571 
572  switch (fsm.getState()) {
573  case TCP_S_FIN_WAIT_1:
574  if (state->fin_ack_rcvd) {
575  event = TCP_E_RCV_FIN_ACK;
576  // start the time-wait timer, turn off the other timers
579 
580  // we're entering TIME_WAIT, so we can signal CLOSED the user
581  // (the only thing left to do is wait until the 2MSL timer expires)
582  }
583  break;
584 
585  case TCP_S_FIN_WAIT_2:
586  // Start the time-wait timer, turn off the other timers.
589 
590  // we're entering TIME_WAIT, so we can signal CLOSED the user
591  // (the only thing left to do is wait until the 2MSL timer expires)
592  break;
593 
594  case TCP_S_TIME_WAIT:
595  // Restart the 2 MSL time-wait timeout.
598  break;
599 
600  default:
601  break;
602  }
603  }
604  }
605  }
606  else { // not enough freeRcvBuffer in rcvQueue for new segment
607  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
608 
611 
612  // if the ACK bit is off drop the segment and return
613  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
614  return TCP_E_IGNORE;
615  }
616  }
617  }
618 
619  //
620  // RFC 793: eighth, check the FIN bit,
621  //
622  if (tcpseg->getFinBit()) {
623  state->ack_now = true;
624 
625  //"
626  // If the FIN bit is set, signal the user "connection closing" and
627  // return any pending RECEIVEs with same message, advance RCV.NXT
628  // over the FIN, and send an acknowledgment for the FIN. Note that
629  // FIN implies PUSH for any segment text not yet delivered to the
630  // user.
631  //"
632 
633  // Note: seems like RFC 793 is not entirely correct here: if the
634  // segment is "above sequence" (ie. RCV.NXT < SEG.SEQ), we cannot
635  // advance RCV.NXT over the FIN. Instead we remember this sequence
636  // number and do it later.
637  uint32 fin_seq = (uint32)tcpseg->getSequenceNo() + (uint32)tcpseg->getPayloadLength();
638 
639  if (state->rcv_nxt == fin_seq) {
640  // advance rcv_nxt over FIN now
641  EV_INFO << "FIN arrived, advancing rcv_nxt over the FIN\n";
642  state->rcv_nxt++;
643  // state transitions will be done in the state machine, here we just set
644  // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
645  event = TCP_E_RCV_FIN;
646 
647  switch (fsm.getState()) {
648  case TCP_S_FIN_WAIT_1:
649  if (state->fin_ack_rcvd) {
650  event = TCP_E_RCV_FIN_ACK;
651  // start the time-wait timer, turn off the other timers
654 
655  // we're entering TIME_WAIT, so we can signal CLOSED the user
656  // (the only thing left to do is wait until the 2MSL timer expires)
657  }
658  break;
659 
660  case TCP_S_FIN_WAIT_2:
661  // Start the time-wait timer, turn off the other timers.
664 
665  // we're entering TIME_WAIT, so we can signal CLOSED the user
666  // (the only thing left to do is wait until the 2MSL timer expires)
667  break;
668 
669  case TCP_S_TIME_WAIT:
670  // Restart the 2 MSL time-wait timeout.
673  break;
674 
675  default:
676  break;
677  }
678  }
679  else {
680  // we'll have to do it later (when an arriving segment "fills the gap")
681  EV_DETAIL << "FIN segment above sequence, storing sequence number of FIN\n";
682  state->fin_rcvd = true;
683  state->rcv_fin_seq = fin_seq;
684  }
685 
686  // TBD do PUSH stuff
687  }
688 
689  if (old_rcv_nxt != state->rcv_nxt) {
690  // if rcv_nxt changed, either because we received segment text or we
691  // received a FIN that needs to be acked (or both), we need to send or
692  // schedule an ACK.
693  if (state->sack_enabled) {
694  if (receiveQueue->getQueueLength() != 0) {
695  // RFC 2018, page 4:
696  // "If sent at all, SACK options SHOULD be included in all ACKs which do
697  // not ACK the highest sequence number in the data receiver's queue."
698  state->start_seqno = tcpseg->getSequenceNo();
699  state->end_seqno = tcpseg->getSequenceNo() + tcpseg->getPayloadLength();
700  state->snd_sack = true;
701  EV_DETAIL << "SND_SACK SET (rcv_nxt changed, but receiveQ is not empty)\n";
702  state->ack_now = true; // although not mentioned in [Stevens, W.R.: TCP/IP Illustrated, Volume 2, page 861] seems like we have to set ack_now
703  }
704  }
705 
706  // tcpAlgorithm decides when and how to do ACKs
708  }
709 
710  if ((fsm.getState() == TCP_S_ESTABLISHED || fsm.getState() == TCP_S_SYN_RCVD) &&
712  {
713  // if the user issued the CLOSE command a long time ago and we've just
714  // managed to send off FIN, we simulate a CLOSE command now (we had to
715  // defer it at that time because we still had data in the send queue.)
716  // This CLOSE will take us into the FIN_WAIT_1 state.
717  EV_DETAIL << "Now we can do the CLOSE which was deferred a while ago\n";
718  event = TCP_E_CLOSE;
719  }
720 
721  if (fsm.getState() == TCP_S_CLOSE_WAIT && state->send_fin &&
722  state->snd_nxt == state->snd_fin_seq + 1 && old_snd_nxt != state->snd_nxt)
723  {
724  // if we're in CLOSE_WAIT and we just got to sent our long-pending FIN,
725  // we simulate a CLOSE command now (we had to defer it at that time because
726  // we still had data in the send queue.) This CLOSE will take us into the
727  // LAST_ACK state.
728  EV_DETAIL << "Now we can do the CLOSE which was deferred a while ago\n";
729  event = TCP_E_CLOSE;
730  }
731 
732  return event;
733 }
bool ts_enabled
Definition: TCPConnection.h:226
bool send_fin
Definition: TCPConnection.h:190
#define TCP_TIMEOUT_2MSL
Definition: TCPConnection.h:119
virtual void sendAck()
Utility: send ACK.
Definition: TCPConnectionUtil.cc:543
cOutVector * rcvOooSegVector
Definition: TCPConnection.h:370
uint32 full_sized_segment_counter
Definition: TCPConnection.h:203
virtual TCPEventCode processRstInSynReceived(TCPSegment *tcpseg)
Definition: TCPConnectionRcvSegment.cc:1081
virtual uint32 getTSval(TCPSegment *tcpseg) const
Utility: get TSval from segments TS header option.
Definition: TCPConnectionUtil.cc:1225
virtual bool processAckInEstabEtc(TCPSegment *tcpseg)
Definition: TCPConnectionRcvSegment.cc:1112
Definition: TCPConnection.h:68
Definition: TCPConnection.h:69
bool useDataNotification
Definition: TCP.h:161
virtual uint32 getAmountOfBufferedBytes()=0
Returns the number of bytes (out-of-order-segments) currently buffered in queue.
virtual void receiveSeqChanged()=0
Called after rcv_nxt got advanced, either because we received in-sequence data ("text" in RFC 793 lin...
uint32 start_seqno
Definition: TCPConnection.h:238
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TCPConnectionUtil.cc:293
virtual bool hasEnoughSpaceForSegmentInReceiveQueue(TCPSegment *tcpseg)
Utility: returns true when receive queue has enough space for store the tcpseg.
Definition: TCPConnectionRcvSegment.cc:122
Definition: TCPCommand_m.h:104
Definition: TCPCommand_m.h:108
uint32 rcv_nxt
Definition: TCPConnection.h:174
cMessage * cancelEvent(cMessage *msg)
Utility: cancel a timer.
Definition: TCPConnection.h:529
virtual uint32 insertBytesFromSegment(TCPSegment *tcpseg)=0
Called when a TCP segment arrives, it should extract the payload from the segment and store it in the...
Definition: TCPConnection.h:70
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:74
bool fin_ack_rcvd
Definition: TCPConnection.h:188
Definition: TCPConnection.h:72
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
virtual bool isSegmentAcceptable(TCPSegment *tcpseg) const
Utility: check if segment is acceptable (all bytes are in receive window)
Definition: TCPConnectionUtil.cc:405
uint32 rcv_oooseg
Definition: TCPConnection.h:258
virtual void updateRcvQueueVars()
Utility: update receiver queue related variables and statistics - called before setting rcv_wnd...
Definition: TCPConnectionUtil.cc:1247
bool snd_dsack
Definition: TCPConnection.h:241
TCPEventCode
Definition: TCPConnection.h:81
virtual void readHeaderOptions(TCPSegment *tcpseg)
Utility: readHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are impleme...
Definition: TCPConnectionUtil.cc:887
virtual cPacket * extractBytesUpTo(uint32 seq)=0
Should create a packet to be passed up to the app, up to (but NOT including) the given sequence no (u...
cOutVector * tcpRcvQueueDropsVector
Definition: TCPConnection.h:375
uint32 rcv_naseg
Definition: TCPConnection.h:259
uint32 snd_mss
Definition: TCPConnection.h:159
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
bool sack_enabled
Definition: TCPConnection.h:235
Definition: TCPConnection.h:97
virtual void sendEstabIndicationToApp()
Utility: sends TCP_I_ESTABLISHED indication with TCPConnectInfo to application.
Definition: TCPConnectionUtil.cc:305
Definition: TCPConnection.h:100
Definition: TCPConnection.h:102
cMessage * the2MSLTimer
Definition: TCPConnection.h:351
uint32 snd_nxt
Definition: TCPConnection.h:165
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
#define TCP_HEADER_OCTETS
Definition: TCPSegment_m.h:50
uint32 end_seqno
Definition: TCPConnection.h:239
uint32 dupacks
Definition: TCPConnection.h:255
bool snd_sack
Definition: TCPConnection.h:240
uint32 snd_fin_seq
Definition: TCPConnection.h:191
TCP * tcpMain
Definition: TCPConnection.h:330
uint32 snd_una
Definition: TCPConnection.h:164
Definition: TCPConnection.h:89
uint32_t uint32
Definition: Compat.h:30
uint32 tcpRcvQueueDrops
Definition: TCPConnection.h:265
bool ack_now
Definition: TCPConnection.h:204
virtual uint32 getQueueLength()=0
Returns the number of blocks currently buffered in queue.
TCPStateVariables * state
Definition: TCPConnection.h:336
bool fin_rcvd
Definition: TCPConnection.h:193
virtual void receivedOutOfOrderSegment()=0
Called after receiving data which are in the window, but not at its left edge (seq != rcv_nxt)...
Definition: TCPConnection.h:104
cMessage * finWait2Timer
Definition: TCPConnection.h:353
cOutVector * rcvNASegVector
Definition: TCPConnection.h:371
Definition: TCPConnection.h:71
virtual void established(bool active)=0
Called when the connection is going to ESTABLISHED from SYN_SENT or SYN_RCVD.
simtime_t time_last_data_sent
Definition: TCPConnection.h:231
uint32 ts_recent
Definition: TCPConnection.h:229
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
Definition: TCPConnection.h:67
Definition: TCPConnection.h:101
Definition: TCPCommand_m.h:98
void scheduleTimeout(cMessage *msg, simtime_t timeout)
Utility: start a timer.
Definition: TCPConnection.h:524
uint32 rcv_wnd
Definition: TCPConnection.h:175
cOutVector * dupAcksVector
Definition: TCPConnection.h:366
Definition: TCPConnection.h:73
virtual void receivedDataAck(uint32 firstSeqAcked)=0
Called after we received an ACK which acked some data (that is, we could advance snd_una).
virtual void sendToApp(cMessage *msg)
Utility: sends packet to application.
Definition: TCPConnectionUtil.cc:322
uint32 usedRcvBuffer
Definition: TCPConnection.h:263
uint32 rcv_fin_seq
Definition: TCPConnection.h:194
#define PAWS_IDLE_TIME_THRESH
Definition: TCPConnection.h:131
virtual void sendRst(uint32 seqNo)
Utility: sends RST.
Definition: TCPConnectionUtil.cc:504
Definition: TCPConnection.h:82
int connId
Definition: TCPConnection.h:321
if(!(yy_init))
Definition: lexer.cc:1644
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
TCPEventCode inet::tcp::TCPConnection::processSegmentInListen ( TCPSegment tcpseg,
L3Address  src,
L3Address  dest 
)
protectedvirtual

Referenced by process_RCV_SEGMENT().

738 {
739  EV_DETAIL << "Processing segment in LISTEN\n";
740 
741  //"
742  // first check for an RST
743  // An incoming RST should be ignored. Return.
744  //"
745  if (tcpseg->getRstBit()) {
746  EV_INFO << "RST bit set: dropping segment\n";
747  return TCP_E_IGNORE;
748  }
749 
750  //"
751  // second check for an ACK
752  // Any acknowledgment is bad if it arrives on a connection still in
753  // the LISTEN state. An acceptable reset segment should be formed
754  // for any arriving ACK-bearing segment. The RST should be
755  // formatted as follows:
756  //
757  // <SEQ=SEG.ACK><CTL=RST>
758  //
759  // Return.
760  //"
761  if (tcpseg->getAckBit()) {
762  EV_INFO << "ACK bit set: dropping segment and sending RST\n";
763  sendRst(tcpseg->getAckNo(), destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
764  return TCP_E_IGNORE;
765  }
766 
767  //"
768  // third check for a SYN
769  //"
770  if (tcpseg->getSynBit()) {
771  if (tcpseg->getFinBit()) {
772  // Looks like implementations vary on how to react to SYN+FIN.
773  // Some treat it as plain SYN (and reply with SYN+ACK), some send RST+ACK.
774  // Let's just do the former here.
775  EV_INFO << "SYN+FIN received: ignoring FIN\n";
776  }
777 
778  EV_DETAIL << "SYN bit set: filling in foreign socket and sending SYN+ACK\n";
779 
780  //"
781  // If the listen was not fully specified (i.e., the foreign socket was not
782  // fully specified), then the unspecified fields should be filled in now.
783  //"
784  //
785  // Also, we may need to fork, in order to leave another connection
786  // LISTENing on the port. Note: forking will change our connId.
787  //
788  if (state->fork) {
789  TCPConnection *conn = cloneListeningConnection(); // "conn" is the clone which will stay LISTENing, while "this" gets updated with the remote address
790  tcpMain->addForkedConnection(this, conn, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
791  EV_DETAIL << "Connection forked: this connection got new connId=" << connId << ", "
792  "spinoff keeps LISTENing with connId=" << conn->connId << "\n";
793  }
794  else {
795  tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
796  }
797 
798  //"
799  // Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other
800  // control or text should be queued for processing later. ISS
801  // should be selected and a SYN segment sent of the form:
802  //
803  // <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
804  //
805  // SND.NXT is set to ISS+1 and SND.UNA to ISS. The connection
806  // state should be changed to SYN-RECEIVED.
807  //"
808  state->rcv_nxt = tcpseg->getSequenceNo() + 1;
810 
811  if (rcvAdvVector)
812  rcvAdvVector->record(state->rcv_adv);
813 
814  state->irs = tcpseg->getSequenceNo();
815  receiveQueue->init(state->rcv_nxt); // FIXME may init twice...
817 
818  // although not mentioned in RFC 793, seems like we have to pick up
819  // initial snd_wnd from the segment here.
820  updateWndInfo(tcpseg, true);
821 
822  if (tcpseg->getHeaderLength() > TCP_HEADER_OCTETS) // Header options present? TCP_HEADER_OCTETS = 20
823  readHeaderOptions(tcpseg);
824 
825  state->ack_now = true;
826  sendSynAck();
828 
829  if (!connEstabTimer->isScheduled())
831 
832  //"
833  // Note that any other incoming control or data (combined with SYN)
834  // will be processed in the SYN-RECEIVED state, but processing of SYN
835  // and ACK should not be repeated.
836  //"
837  // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
838  // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
839  // so there's only URG and PSH left to handle.
840  //
841  if (tcpseg->getPayloadLength() > 0) {
843 
844  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpseg)) { // enough freeRcvBuffer in rcvQueue for new segment?
846  }
847  else { // not enough freeRcvBuffer in rcvQueue for new segment
848  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
849 
852 
853  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
854  return TCP_E_IGNORE;
855  }
856  }
857 
858  if (tcpseg->getUrgBit() || tcpseg->getPshBit())
859  EV_DETAIL << "Ignoring URG and PSH bits in SYN\n"; // TBD
860 
861  return TCP_E_RCV_SYN; // this will take us to SYN_RCVD
862  }
863 
864  //"
865  // fourth other text or control
866  // So you are unlikely to get here, but if you do, drop the segment, and return.
867  //"
868  EV_WARN << "Unexpected segment: dropping it\n";
869  return TCP_E_IGNORE;
870 }
virtual TCPConnection * cloneListeningConnection()
Utility: clone a listening connection.
Definition: TCPConnectionUtil.cc:200
TCPConnection()
Note: this default ctor is NOT used to create live connections, only temporary ones so that TCPMain c...
Definition: TCPConnectionBase.cc:172
uint32 rcv_adv
Definition: TCPConnection.h:178
virtual void init(uint32 startSeq)=0
Set initial receive sequence number.
virtual bool hasEnoughSpaceForSegmentInReceiveQueue(TCPSegment *tcpseg)
Utility: returns true when receive queue has enough space for store the tcpseg.
Definition: TCPConnectionRcvSegment.cc:122
uint32 rcv_nxt
Definition: TCPConnection.h:174
virtual uint32 insertBytesFromSegment(TCPSegment *tcpseg)=0
Called when a TCP segment arrives, it should extract the payload from the segment and store it in the...
bool fork
Definition: TCPConnection.h:157
virtual void updateRcvQueueVars()
Utility: update receiver queue related variables and statistics - called before setting rcv_wnd...
Definition: TCPConnectionUtil.cc:1247
virtual void readHeaderOptions(TCPSegment *tcpseg)
Utility: readHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are impleme...
Definition: TCPConnectionUtil.cc:887
virtual void updateWndInfo(TCPSegment *tcpseg, bool doAlways=false)
Utility: update window information (snd_wnd, snd_wl1, snd_wl2)
Definition: TCPConnectionUtil.cc:1309
cOutVector * tcpRcvQueueDropsVector
Definition: TCPConnection.h:375
virtual void addForkedConnection(TCPConnection *conn, TCPConnection *newConn, L3Address localAddr, L3Address remoteAddr, int localPort, int remotePort)
Update conn&#39;s socket pair, and register newConn (which&#39;ll keep LISTENing).
Definition: TCP.cc:445
virtual void updateSockPair(TCPConnection *conn, L3Address localAddr, L3Address remoteAddr, int localPort, int remotePort)
To be called from TCPConnection when socket pair (key for TcpConnMap) changes (e.g.
Definition: TCP.cc:420
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
virtual void sendSynAck()
Utility: send SYN+ACK.
Definition: TCPConnectionUtil.cc:481
#define TCP_HEADER_OCTETS
Definition: TCPSegment_m.h:50
TCP * tcpMain
Definition: TCPConnection.h:330
cOutVector * rcvAdvVector
Definition: TCPConnection.h:359
uint32 tcpRcvQueueDrops
Definition: TCPConnection.h:265
bool ack_now
Definition: TCPConnection.h:204
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void startSynRexmitTimer()
Utility: start SYN-REXMIT timer.
Definition: TCPConnectionRcvSegment.cc:1311
cMessage * connEstabTimer
Definition: TCPConnection.h:352
uint32 irs
Definition: TCPConnection.h:177
#define TCP_TIMEOUT_CONN_ESTAB
Definition: TCPConnection.h:117
void scheduleTimeout(cMessage *msg, simtime_t timeout)
Utility: start a timer.
Definition: TCPConnection.h:524
uint32 rcv_wnd
Definition: TCPConnection.h:175
virtual void sendRst(uint32 seqNo)
Utility: sends RST.
Definition: TCPConnectionUtil.cc:504
Definition: TCPConnection.h:98
Definition: TCPConnection.h:82
virtual void selectInitialSeqNum()
Utility: generates ISS and initializes corresponding state variables.
Definition: TCPConnectionUtil.cc:394
int connId
Definition: TCPConnection.h:321
TCPEventCode inet::tcp::TCPConnection::processSegmentInSynSent ( TCPSegment tcpseg,
L3Address  src,
L3Address  dest 
)
protectedvirtual

Referenced by process_RCV_SEGMENT().

873 {
874  EV_DETAIL << "Processing segment in SYN_SENT\n";
875 
876  //"
877  // first check the ACK bit
878  //
879  // If the ACK bit is set
880  //
881  // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless
882  // the RST bit is set, if so drop the segment and return)
883  //
884  // <SEQ=SEG.ACK><CTL=RST>
885  //
886  // and discard the segment. Return.
887  //
888  // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable.
889  //"
890  if (tcpseg->getAckBit()) {
891  if (seqLE(tcpseg->getAckNo(), state->iss) || seqGreater(tcpseg->getAckNo(), state->snd_nxt)) {
892  if (tcpseg->getRstBit())
893  EV_DETAIL << "ACK+RST bit set but wrong AckNo, ignored\n";
894  else {
895  EV_DETAIL << "ACK bit set but wrong AckNo, sending RST\n";
896  sendRst(tcpseg->getAckNo(), destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
897  }
898  return TCP_E_IGNORE;
899  }
900 
901  EV_DETAIL << "ACK bit set, AckNo acceptable\n";
902  }
903 
904  //"
905  // second check the RST bit
906  //
907  // If the RST bit is set
908  //
909  // If the ACK was acceptable then signal the user "error:
910  // connection reset", drop the segment, enter CLOSED state,
911  // delete TCB, and return. Otherwise (no ACK) drop the segment
912  // and return.
913  //"
914  if (tcpseg->getRstBit()) {
915  if (tcpseg->getAckBit()) {
916  EV_DETAIL << "RST+ACK: performing connection reset\n";
918 
919  return TCP_E_RCV_RST;
920  }
921  else {
922  EV_DETAIL << "RST without ACK: dropping segment\n";
923 
924  return TCP_E_IGNORE;
925  }
926  }
927 
928  //"
929  // third check the security and precedence -- not done
930  //
931  // fourth check the SYN bit
932  //
933  // This step should be reached only if the ACK is ok, or there is
934  // no ACK, and it the segment did not contain a RST.
935  //
936  // If the SYN bit is on and the security/compartment and precedence
937  // are acceptable then,
938  //"
939  if (tcpseg->getSynBit()) {
940  //
941  // RCV.NXT is set to SEG.SEQ+1, IRS is set to
942  // SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there
943  // is an ACK), and any segments on the retransmission queue which
944  // are thereby acknowledged should be removed.
945  //
946  state->rcv_nxt = tcpseg->getSequenceNo() + 1;
948 
949  if (rcvAdvVector)
950  rcvAdvVector->record(state->rcv_adv);
951 
952  state->irs = tcpseg->getSequenceNo();
954 
955  if (tcpseg->getAckBit()) {
956  state->snd_una = tcpseg->getAckNo();
958 
959  if (state->sack_enabled)
961 
962  // although not mentioned in RFC 793, seems like we have to pick up
963  // initial snd_wnd from the segment here.
964  updateWndInfo(tcpseg, true);
965  }
966 
967  // this also seems to be a good time to learn our local IP address
968  // (was probably unspecified at connection open)
969  tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
970 
971  //"
972  // If SND.UNA > ISS (our SYN has been ACKed), change the connection
973  // state to ESTABLISHED, form an ACK segment
974  //
975  // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
976  //
977  // and send it. Data or controls which were queued for
978  // transmission may be included. If there are other controls or
979  // text in the segment then continue processing at the sixth step
980  // below where the URG bit is checked, otherwise return.
981  //"
982  if (seqGreater(state->snd_una, state->iss)) {
983  EV_INFO << "SYN+ACK bits set, connection established.\n";
984 
985  // RFC says "continue processing at the sixth step below where
986  // the URG bit is checked". Those steps deal with: URG, segment text
987  // (and PSH), and FIN.
988  // Now: URG and PSH we don't support yet; in SYN+FIN we ignore FIN;
989  // with segment text we just take it easy and put it in the receiveQueue
990  // -- we'll forward it to the user when more data arrives.
991  if (tcpseg->getFinBit())
992  EV_DETAIL << "SYN+ACK+FIN received: ignoring FIN\n";
993 
994  if (tcpseg->getPayloadLength() > 0) {
996 
997  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpseg)) { // enough freeRcvBuffer in rcvQueue for new segment?
998  receiveQueue->insertBytesFromSegment(tcpseg); // TBD forward to app, etc.
999  }
1000  else { // not enough freeRcvBuffer in rcvQueue for new segment
1001  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
1002 
1005 
1006  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
1007  return TCP_E_IGNORE;
1008  }
1009  }
1010 
1011  if (tcpseg->getUrgBit() || tcpseg->getPshBit())
1012  EV_DETAIL << "Ignoring URG and PSH bits in SYN+ACK\n"; // TBD
1013 
1014  if (tcpseg->getHeaderLength() > TCP_HEADER_OCTETS) // Header options present? TCP_HEADER_OCTETS = 20
1015  readHeaderOptions(tcpseg);
1016 
1017  // notify tcpAlgorithm (it has to send ACK of SYN) and app layer
1018  state->ack_now = true;
1019  tcpAlgorithm->established(true);
1022 
1023  // This will trigger transition to ESTABLISHED. Timers and notifying
1024  // app will be taken care of in stateEntered().
1025  return TCP_E_RCV_SYN_ACK;
1026  }
1027 
1028  //"
1029  // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment
1030  //
1031  // <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
1032  //
1033  // and send it. If there are other controls or text in the
1034  // segment, queue them for processing after the ESTABLISHED state
1035  // has been reached, return.
1036  //"
1037  EV_INFO << "SYN bit set: sending SYN+ACK\n";
1039  sendSynAck();
1041 
1042  // Note: code below is similar to processing SYN in LISTEN.
1043 
1044  // For consistency with that code, we ignore SYN+FIN here
1045  if (tcpseg->getFinBit())
1046  EV_DETAIL << "SYN+FIN received: ignoring FIN\n";
1047 
1048  // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
1049  // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
1050  // so there's only URG and PSH left to handle.
1051  if (tcpseg->getPayloadLength() > 0) {
1053 
1054  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpseg)) { // enough freeRcvBuffer in rcvQueue for new segment?
1055  receiveQueue->insertBytesFromSegment(tcpseg); // TBD forward to app, etc.
1056  }
1057  else { // not enough freeRcvBuffer in rcvQueue for new segment
1058  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
1059 
1062 
1063  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
1064  return TCP_E_IGNORE;
1065  }
1066  }
1067 
1068  if (tcpseg->getUrgBit() || tcpseg->getPshBit())
1069  EV_DETAIL << "Ignoring URG and PSH bits in SYN\n"; // TBD
1070 
1071  return TCP_E_RCV_SYN;
1072  }
1073 
1074  //"
1075  // fifth, if neither of the SYN or RST bits is set then drop the
1076  // segment and return.
1077  //"
1078  return TCP_E_IGNORE;
1079 }
uint32 rcv_adv
Definition: TCPConnection.h:178
virtual void init(uint32 startSeq)=0
Set initial receive sequence number.
Definition: TCPConnection.h:99
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TCPConnectionUtil.cc:293
virtual bool hasEnoughSpaceForSegmentInReceiveQueue(TCPSegment *tcpseg)
Utility: returns true when receive queue has enough space for store the tcpseg.
Definition: TCPConnectionRcvSegment.cc:122
Definition: TCPCommand_m.h:104
uint32 rcv_nxt
Definition: TCPConnection.h:174
virtual uint32 insertBytesFromSegment(TCPSegment *tcpseg)=0
Called when a TCP segment arrives, it should extract the payload from the segment and store it in the...
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
virtual void updateRcvQueueVars()
Utility: update receiver queue related variables and statistics - called before setting rcv_wnd...
Definition: TCPConnectionUtil.cc:1247
virtual void readHeaderOptions(TCPSegment *tcpseg)
Utility: readHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are impleme...
Definition: TCPConnectionUtil.cc:887
virtual void updateWndInfo(TCPSegment *tcpseg, bool doAlways=false)
Utility: update window information (snd_wnd, snd_wl1, snd_wl2)
Definition: TCPConnectionUtil.cc:1309
cOutVector * tcpRcvQueueDropsVector
Definition: TCPConnection.h:375
virtual void updateSockPair(TCPConnection *conn, L3Address localAddr, L3Address remoteAddr, int localPort, int remotePort)
To be called from TCPConnection when socket pair (key for TcpConnMap) changes (e.g.
Definition: TCP.cc:420
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
bool sack_enabled
Definition: TCPConnection.h:235
virtual void sendSynAck()
Utility: send SYN+ACK.
Definition: TCPConnectionUtil.cc:481
virtual void sendEstabIndicationToApp()
Utility: sends TCP_I_ESTABLISHED indication with TCPConnectInfo to application.
Definition: TCPConnectionUtil.cc:305
Definition: TCPConnection.h:102
uint32 snd_nxt
Definition: TCPConnection.h:165
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
#define TCP_HEADER_OCTETS
Definition: TCPSegment_m.h:50
virtual void discardUpTo(uint32 seqNum)=0
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed...
TCP * tcpMain
Definition: TCPConnection.h:330
uint32 snd_una
Definition: TCPConnection.h:164
cOutVector * rcvAdvVector
Definition: TCPConnection.h:359
uint32 tcpRcvQueueDrops
Definition: TCPConnection.h:265
bool ack_now
Definition: TCPConnection.h:204
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 iss
Definition: TCPConnection.h:171
virtual void startSynRexmitTimer()
Utility: start SYN-REXMIT timer.
Definition: TCPConnectionRcvSegment.cc:1311
static simsignal_t tcpConnectionAddedSignal
Definition: TCP.h:97
uint32 irs
Definition: TCPConnection.h:177
virtual void discardUpTo(uint32 seqNum)
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed...
Definition: TCPSACKRexmitQueue.cc:65
virtual void established(bool active)=0
Called when the connection is going to ESTABLISHED from SYN_SENT or SYN_RCVD.
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
uint32 rcv_wnd
Definition: TCPConnection.h:175
virtual void sendRst(uint32 seqNo)
Utility: sends RST.
Definition: TCPConnectionUtil.cc:504
Definition: TCPConnection.h:98
Definition: TCPConnection.h:82
uint32 snd_max
Definition: TCPConnection.h:166
bool inet::tcp::TCPConnection::processTCPSegment ( TCPSegment tcpSeg,
L3Address  srcAddr,
L3Address  destAddr 
)
virtual

Process incoming TCP segment.

Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).

Referenced by inet::tcp::TCP::handleMessage().

299 {
300  printConnBrief();
301  if (!localAddr.isUnspecified()) {
302  ASSERT(localAddr == segDestAddr);
303  ASSERT(localPort == tcpseg->getDestPort());
304  }
305 
306  if (!remoteAddr.isUnspecified()) {
307  ASSERT(remoteAddr == segSrcAddr);
308  ASSERT(remotePort == tcpseg->getSrcPort());
309  }
310 
311  if (tryFastRoute(tcpseg))
312  return true;
313 
314  // first do actions
315  TCPEventCode event = process_RCV_SEGMENT(tcpseg, segSrcAddr, segDestAddr);
316 
317  // then state transitions
318  return performStateTransition(event);
319 }
L3Address remoteAddr
Definition: TCPConnection.h:325
virtual void printConnBrief() const
Utility: prints local/remote addr/port and app gate index/connId.
Definition: TCPConnectionUtil.cc:148
virtual TCPEventCode process_RCV_SEGMENT(TCPSegment *tcpseg, L3Address src, L3Address dest)
Process incoming TCP segment.
Definition: TCPConnectionRcvSegment.cc:89
virtual bool tryFastRoute(TCPSegment *tcpseg)
Shortcut to process most common case as fast as possible.
Definition: TCPConnectionRcvSegment.cc:33
virtual bool performStateTransition(const TCPEventCode &event)
Implemements the pure TCP state machine.
Definition: TCPConnectionBase.cc:403
TCPEventCode
Definition: TCPConnection.h:81
bool isUnspecified() const
Definition: L3Address.cc:133
int localPort
Definition: TCPConnection.h:326
L3Address localAddr
Definition: TCPConnection.h:324
int remotePort
Definition: TCPConnection.h:327
bool inet::tcp::TCPConnection::processTimer ( cMessage *  msg)
virtual

Process self-messages (timers).

Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).

Referenced by inet::tcp::TCP::handleMessage().

266 {
267  printConnBrief();
268  EV_DETAIL << msg->getName() << " timer expired\n";
269 
270  // first do actions
271  TCPEventCode event;
272 
273  if (msg == the2MSLTimer) {
274  event = TCP_E_TIMEOUT_2MSL;
276  }
277  else if (msg == connEstabTimer) {
278  event = TCP_E_TIMEOUT_CONN_ESTAB;
280  }
281  else if (msg == finWait2Timer) {
282  event = TCP_E_TIMEOUT_FIN_WAIT_2;
284  }
285  else if (msg == synRexmitTimer) {
286  event = TCP_E_IGNORE;
288  }
289  else {
290  event = TCP_E_IGNORE;
291  tcpAlgorithm->processTimer(msg, event);
292  }
293 
294  // then state transitions
295  return performStateTransition(event);
296 }
virtual void processTimer(cMessage *timer, TCPEventCode &event)=0
Place to process timers specific to this TCPAlgorithm class.
virtual void printConnBrief() const
Utility: prints local/remote addr/port and app gate index/connId.
Definition: TCPConnectionUtil.cc:148
virtual void process_TIMEOUT_FIN_WAIT_2()
Definition: TCPConnectionRcvSegment.cc:1296
virtual void process_TIMEOUT_2MSL()
Definition: TCPConnectionRcvSegment.cc:1274
virtual bool performStateTransition(const TCPEventCode &event)
Implemements the pure TCP state machine.
Definition: TCPConnectionBase.cc:403
TCPEventCode
Definition: TCPConnection.h:81
Definition: TCPConnection.h:107
cMessage * the2MSLTimer
Definition: TCPConnection.h:351
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
Definition: TCPConnection.h:109
virtual void process_TIMEOUT_CONN_ESTAB()
Definition: TCPConnectionRcvSegment.cc:1254
cMessage * finWait2Timer
Definition: TCPConnection.h:353
cMessage * connEstabTimer
Definition: TCPConnection.h:352
Definition: TCPConnection.h:108
virtual void process_TIMEOUT_SYN_REXMIT(TCPEventCode &event)
Definition: TCPConnectionRcvSegment.cc:1322
Definition: TCPConnection.h:82
cMessage * synRexmitTimer
Definition: TCPConnection.h:354
bool inet::tcp::TCPConnection::processTSOption ( TCPSegment tcpseg,
const TCPOptionTimestamp option 
)
protectedvirtual

Referenced by readHeaderOptions().

1000 {
1001  if (option.getLength() != 10) {
1002  EV_ERROR << "ERROR: length incorrect\n";
1003  return false;
1004  }
1005 
1006  if ((!state->ts_enabled && fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) ||
1007  (state->ts_enabled && fsm.getState() != TCP_S_SYN_RCVD && fsm.getState() != TCP_S_ESTABLISHED &&
1008  fsm.getState() != TCP_S_FIN_WAIT_1 && fsm.getState() != TCP_S_FIN_WAIT_2))
1009  {
1010  EV_ERROR << "ERROR: TCP Header Option TS received, but in unexpected state\n";
1011  return false;
1012  }
1013 
1014  if (!state->ts_enabled) {
1015  state->rcv_initial_ts = true;
1017  EV_INFO << "TCP Header Option TS(TSval=" << option.getSenderTimestamp() << ", TSecr=" << option.getEchoedTimestamp() << ") received, TS (ts_enabled) is set to " << state->ts_enabled << "\n";
1018  }
1019  else
1020  EV_INFO << "TCP Header Option TS(TSval=" << option.getSenderTimestamp() << ", TSecr=" << option.getEchoedTimestamp() << ") received\n";
1021 
1022  // RFC 1323, page 35:
1023  // "Check whether the segment contains a Timestamps option and bit
1024  // Snd.TS.OK is on. If so:
1025  // If SEG.TSval < TS.Recent, then test whether connection has
1026  // been idle less than 24 days; if both are true, then the
1027  // segment is not acceptable; follow steps below for an
1028  // unacceptable segment.
1029  // If SEG.SEQ is equal to Last.ACK.sent, then save SEG.[TSval] in
1030  // variable TS.Recent."
1031  if (state->ts_enabled) {
1032  if (seqLess(option.getSenderTimestamp(), state->ts_recent)) {
1033  if ((simTime() - state->time_last_data_sent) > PAWS_IDLE_TIME_THRESH) { // PAWS_IDLE_TIME_THRESH = 24 days
1034  EV_DETAIL << "PAWS: Segment is not acceptable, TSval=" << option.getSenderTimestamp() << " in " << stateName(fsm.getState()) << " state received: dropping segment\n";
1035  return false;
1036  }
1037  }
1038  else if (seqLE(tcpseg->getSequenceNo(), state->last_ack_sent)) { // Note: test is modified according to the latest proposal of the [email protected] list (Braden 1993/04/26)
1039  state->ts_recent = option.getSenderTimestamp();
1040  EV_DETAIL << "Updating ts_recent from segment: new ts_recent=" << state->ts_recent << "\n";
1041  }
1042  }
1043 
1044  return true;
1045 }
bool ts_enabled
Definition: TCPConnection.h:226
Definition: TCPConnection.h:68
uint32 last_ack_sent
Definition: TCPConnection.h:230
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:66
Definition: TCPConnection.h:72
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
bool rcv_initial_ts
Definition: TCPConnection.h:228
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
bool snd_initial_ts
Definition: TCPConnection.h:227
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:71
simtime_t time_last_data_sent
Definition: TCPConnection.h:231
Definition: TCPConnection.h:65
uint32 ts_recent
Definition: TCPConnection.h:229
Definition: TCPConnection.h:67
#define PAWS_IDLE_TIME_THRESH
Definition: TCPConnection.h:131
bool ts_support
Definition: TCPConnection.h:225
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TCPConnectionUtil.cc:45
bool inet::tcp::TCPConnection::processWSOption ( TCPSegment tcpseg,
const TCPOptionWindowScale option 
)
protectedvirtual

Referenced by readHeaderOptions().

975 {
976  if (option.getLength() != 3) {
977  EV_ERROR << "ERROR: length incorrect\n";
978  return false;
979  }
980 
981  if (fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) {
982  EV_ERROR << "ERROR: TCP Header Option WS received, but in unexpected state\n";
983  return false;
984  }
985 
986  state->rcv_ws = true;
988  state->snd_wnd_scale = option.getWindowScale();
989  EV_INFO << "TCP Header Option WS(=" << state->snd_wnd_scale << ") received, WS (ws_enabled) is set to " << state->ws_enabled << "\n";
990 
991  if (state->snd_wnd_scale > 14) { // RFC 1323, page 11: "the shift count must be limited to 14"
992  EV_ERROR << "ERROR: TCP Header Option WS received but shift count value is exceeding 14\n";
993  state->snd_wnd_scale = 14;
994  }
995 
996  return true;
997 }
bool ws_support
Definition: TCPConnection.h:216
uint snd_wnd_scale
Definition: TCPConnection.h:222
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:66
bool ws_enabled
Definition: TCPConnection.h:217
bool snd_ws
Definition: TCPConnection.h:219
bool rcv_ws
Definition: TCPConnection.h:220
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:65
void inet::tcp::TCPConnection::readHeaderOptions ( TCPSegment tcpseg)
protectedvirtual

Utility: readHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implemented)

Referenced by processSegment1stThru8th(), processSegmentInListen(), and processSegmentInSynSent().

888 {
889  EV_INFO << "TCP Header Option(s) received:\n";
890 
891  for (uint i = 0; i < tcpseg->getHeaderOptionArraySize(); i++) {
892  const TCPOption *option = tcpseg->getHeaderOption(i);
893  short kind = option->getKind();
894  short length = option->getLength();
895  bool ok = true;
896 
897  EV_DETAIL << "Option type " << kind << " (" << optionName(kind) << "), length " << length << "\n";
898 
899  switch (kind) {
900  case TCPOPTION_END_OF_OPTION_LIST: // EOL=0
901  case TCPOPTION_NO_OPERATION: // NOP=1
902  if (length != 1) {
903  EV_ERROR << "ERROR: option length incorrect\n";
904  ok = false;
905  }
906  break;
907 
908  case TCPOPTION_MAXIMUM_SEGMENT_SIZE: // MSS=2
909  ok = processMSSOption(tcpseg, *check_and_cast<const TCPOptionMaxSegmentSize *>(option));
910  break;
911 
912  case TCPOPTION_WINDOW_SCALE: // WS=3
913  ok = processWSOption(tcpseg, *check_and_cast<const TCPOptionWindowScale *>(option));
914  break;
915 
916  case TCPOPTION_SACK_PERMITTED: // SACK_PERMITTED=4
917  ok = processSACKPermittedOption(tcpseg, *check_and_cast<const TCPOptionSackPermitted *>(option));
918  break;
919 
920  case TCPOPTION_SACK: // SACK=5
921  ok = processSACKOption(tcpseg, *check_and_cast<const TCPOptionSack *>(option));
922  break;
923 
924  case TCPOPTION_TIMESTAMP: // TS=8
925  ok = processTSOption(tcpseg, *check_and_cast<const TCPOptionTimestamp *>(option));
926  break;
927 
928  // TODO add new TCPOptions here once they are implemented
929  // TODO delegate to TCPAlgorithm as well -- it may want to recognized additional options
930 
931  default:
932  EV_ERROR << "ERROR: Unsupported TCP option kind " << kind << "\n";
933  break;
934  }
935  (void)ok; // unused
936  }
937 }
Definition: TCPSegment_m.h:114
Definition: TCPSegment_m.h:112
Definition: TCPSegment_m.h:117
unsigned int uint
Definition: INETDefs.h:63
Definition: TCPSegment_m.h:118
virtual bool processTSOption(TCPSegment *tcpseg, const TCPOptionTimestamp &option)
Definition: TCPConnectionUtil.cc:999
static const char * optionName(int option)
Utility: returns name of TCPOPTION_xxx constants.
Definition: TCPConnectionUtil.cc:119
Definition: TCPSegment_m.h:113
virtual bool processSACKOption(TCPSegment *tcpseg, const TCPOptionSack &option)
Definition: TCPConnectionSackUtil.cc:39
virtual bool processSACKPermittedOption(TCPSegment *tcpseg, const TCPOptionSackPermitted &option)
Definition: TCPConnectionUtil.cc:1047
virtual bool processWSOption(TCPSegment *tcpseg, const TCPOptionWindowScale &option)
Definition: TCPConnectionUtil.cc:974
Definition: TCPSegment_m.h:116
Definition: TCPSegment_m.h:115
virtual bool processMSSOption(TCPSegment *tcpseg, const TCPOptionMaxSegmentSize &option)
Definition: TCPConnectionUtil.cc:939
void inet::tcp::TCPConnection::retransmitData ( )
virtual

Utility: retransmit all from snd_una to snd_max.

Referenced by inet::tcp::DumbTCP::processTimer().

850 {
851  // retransmit everything from snd_una
853 
854  uint32 bytesToSend = state->snd_max - state->snd_nxt;
855 
856  // FIN (without user data) needs to be resent
857  if (bytesToSend == 0 && state->send_fin && state->snd_fin_seq == sendQueue->getBufferEndSeq()) {
859  EV_DETAIL << "No outstanding DATA, resending FIN, advancing snd_nxt over the FIN\n";
861  sendFin();
862  state->snd_max = ++state->snd_nxt;
863 
864  if (unackedVector)
865  unackedVector->record(state->snd_max - state->snd_una);
866  return;
867  }
868 
869  ASSERT(bytesToSend != 0);
870 
871  // TBD - avoid to send more than allowed - check cwnd and rwnd before retransmitting data!
872  while (bytesToSend > 0) {
873  uint32 bytes = std::min(bytesToSend, state->snd_mss);
874  bytes = std::min(bytes, (uint32)(sendQueue->getBytesAvailable(state->snd_nxt)));
875  sendSegment(bytes);
876 
877  // Do not send packets after the FIN.
878  // fixes bug that occurs in examples/inet/bulktransfer at event #64043 T=13.861159213744
879  if (state->send_fin && state->snd_nxt == state->snd_fin_seq + 1)
880  break;
881 
882  bytesToSend -= state->sentBytes;
883  }
885 }
bool send_fin
Definition: TCPConnection.h:190
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SCTPAssociation.h:270
cOutVector * unackedVector
Definition: TCPConnection.h:364
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
uint32 snd_mss
Definition: TCPConnection.h:159
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendSegment(uint32 bytes)
Utility: sends one segment of &#39;bytes&#39; bytes from snd_nxt, and advances snd_nxt.
Definition: TCPConnectionUtil.cc:581
virtual void sendFin()
Utility: sends FIN.
Definition: TCPConnectionUtil.cc:562
uint32 snd_fin_seq
Definition: TCPConnection.h:191
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void segmentRetransmitted(uint32 fromseq, uint32 toseq)=0
Called after we retransmitted segment.
virtual uint32 getBufferEndSeq()=0
Returns the sequence number of the last byte stored in the buffer plus one.
uint32 sentBytes
Definition: TCPConnection.h:196
uint32 snd_max
Definition: TCPConnection.h:166
void inet::tcp::TCPConnection::retransmitOneSegment ( bool  called_at_rto)
virtual

Utility: retransmit one segment from snd_una.

Referenced by inet::tcp::TCPNoCongestionControl::processRexmitTimer(), inet::tcp::TCPNewReno::processRexmitTimer(), inet::tcp::TCPReno::processRexmitTimer(), inet::tcp::TCPTahoe::processRexmitTimer(), inet::tcp::TCPWestwood::processRexmitTimer(), inet::tcp::TCPVegas::processRexmitTimer(), inet::tcp::TCPNewReno::receivedDataAck(), inet::tcp::TCPVegas::receivedDataAck(), inet::tcp::TCPReno::receivedDuplicateAck(), inet::tcp::TCPNewReno::receivedDuplicateAck(), inet::tcp::TCPTahoe::receivedDuplicateAck(), inet::tcp::TCPWestwood::receivedDuplicateAck(), and inet::tcp::TCPVegas::receivedDuplicateAck().

803 {
804  uint32 old_snd_nxt = state->snd_nxt;
805 
806  // retransmit one segment at snd_una, and set snd_nxt accordingly (if not called at RTO)
808 
809  // When FIN sent the snd_max - snd_nxt larger than bytes available in queue
812 
813  // FIN (without user data) needs to be resent
814  if (bytes == 0 && state->send_fin && state->snd_fin_seq == sendQueue->getBufferEndSeq()) {
816  EV_DETAIL << "No outstanding DATA, resending FIN, advancing snd_nxt over the FIN\n";
818  sendFin();
820  state->snd_max = ++state->snd_nxt;
821 
822  if (unackedVector)
823  unackedVector->record(state->snd_max - state->snd_una);
824  }
825  else {
826  ASSERT(bytes != 0);
827 
828  sendSegment(bytes);
830 
831  if (!called_at_rto) {
832  if (seqGreater(old_snd_nxt, state->snd_nxt))
833  state->snd_nxt = old_snd_nxt;
834  }
835 
836  // notify
838 
839  if (state->sack_enabled) {
840  // RFC 3517, page 7: "(3) Retransmit the first data segment presumed dropped -- the segment
841  // starting with sequence number HighACK + 1. To prevent repeated
842  // retransmission of the same data, set HighRxt to the highest
843  // sequence number in the retransmitted segment."
845  }
846  }
847 }
bool send_fin
Definition: TCPConnection.h:190
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SCTPAssociation.h:270
cOutVector * unackedVector
Definition: TCPConnection.h:364
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
uint32 snd_nxt
Definition: TCPConnection.h:165
virtual void sendSegment(uint32 bytes)
Utility: sends one segment of &#39;bytes&#39; bytes from snd_nxt, and advances snd_nxt.
Definition: TCPConnectionUtil.cc:581
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendFin()
Utility: sends FIN.
Definition: TCPConnectionUtil.cc:562
uint32 snd_fin_seq
Definition: TCPConnection.h:191
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
unsigned long ulong
Definition: INETDefs.h:64
virtual void segmentRetransmitted(uint32 fromseq, uint32 toseq)=0
Called after we retransmitted segment.
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
virtual uint32 getBufferEndSeq()=0
Returns the sequence number of the last byte stored in the buffer plus one.
uint32 highRxt
Definition: TCPConnection.h:243
uint32 snd_max
Definition: TCPConnection.h:166
virtual void ackSent()=0
Called after we sent an ACK.
virtual uint32 getHighestRexmittedSeqNum() const
Returns the highest sequence number rexmitted by data sender.
Definition: TCPSACKRexmitQueue.cc:267
void inet::tcp::TCPConnection::segmentArrivalWhileClosed ( TCPSegment tcpseg,
L3Address  src,
L3Address  dest 
)
virtual

This method gets invoked from TCP when a segment arrives which doesn't belong to an existing connection.

TCP creates a temporary connection object so that it can call this method, then immediately deletes it.

Referenced by inet::tcp::TCP::segmentArrivalWhileClosed().

40 {
41  EV_INFO << "Seg arrived: ";
42  printSegmentBrief(tcpseg);
43 
44  // This segment doesn't belong to any connection, so this object
45  // must be a temp object created solely for the purpose of calling us
46 
47  ASSERT(state == nullptr);
48 
49  EV_INFO << "Segment doesn't belong to any existing connection\n";
50 
51  // RFC 793:
52  //"
53  // all data in the incoming segment is discarded. An incoming
54  // segment containing a RST is discarded. An incoming segment not
55  // containing a RST causes a RST to be sent in response. The
56  // acknowledgment and sequence field values are selected to make the
57  // reset sequence acceptable to the TCP that sent the offending
58  // segment.
59  //
60  // If the ACK bit is off, sequence number zero is used,
61  //
62  // <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
63  //
64  // If the ACK bit is on,
65  //
66  // <SEQ=SEG.ACK><CTL=RST>
67  //
68  // ...
69  //
70  // SEG.LEN = the number of octets occupied by the data in the segment
71  // (counting SYN and FIN)
72  //"
73  if (tcpseg->getRstBit()) {
74  EV_DETAIL << "RST bit set: dropping segment\n";
75  return;
76  }
77 
78  if (!tcpseg->getAckBit()) {
79  EV_DETAIL << "ACK bit not set: sending RST+ACK\n";
80  uint32 ackNo = tcpseg->getSequenceNo() + tcpseg->getSegLen();
81  sendRstAck(0, ackNo, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
82  }
83  else {
84  EV_DETAIL << "ACK bit set: sending RST\n";
85  sendRst(tcpseg->getAckNo(), destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
86  }
87 }
virtual void sendRstAck(uint32 seq, uint32 ack, L3Address src, L3Address dest, int srcPort, int destPort)
Utility: sends RST+ACK; does not use connection state.
Definition: TCPConnectionUtil.cc:523
static void printSegmentBrief(TCPSegment *tcpseg)
Utility: prints important header fields.
Definition: TCPConnectionUtil.cc:157
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void sendRst(uint32 seqNo)
Utility: sends RST.
Definition: TCPConnectionUtil.cc:504
void inet::tcp::TCPConnection::selectInitialSeqNum ( )
protectedvirtual

Utility: generates ISS and initializes corresponding state variables.

Referenced by process_OPEN_ACTIVE(), process_SEND(), and processSegmentInListen().

395 {
396  // set the initial send sequence number
397  state->iss = (unsigned long)fmod(SIMTIME_DBL(simTime()) * 250000.0, 1.0 + (double)(unsigned)0xffffffffUL) & 0xffffffffUL;
398 
400 
401  sendQueue->init(state->iss + 1); // + 1 is for SYN
402  rexmitQueue->init(state->iss + 1); // + 1 is for SYN
403 }
virtual void init(uint32 startSeq)=0
Initialize the object.
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
virtual void init(uint32 seqNum)
Initialize the object.
Definition: TCPSACKRexmitQueue.cc:37
uint32 snd_nxt
Definition: TCPConnection.h:165
uint32 snd_una
Definition: TCPConnection.h:164
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 iss
Definition: TCPConnection.h:171
uint32 snd_max
Definition: TCPConnection.h:166
void inet::tcp::TCPConnection::sendAck ( )
virtual

Utility: send ACK.

Referenced by inet::tcp::DumbTCP::established(), inet::tcp::TCPBaseAlg::established(), inet::tcp::TCPBaseAlg::processDelayedAckTimer(), processSegment1stThru8th(), inet::tcp::DumbTCP::receivedAckForDataNotYetSent(), inet::tcp::TCPBaseAlg::receivedAckForDataNotYetSent(), inet::tcp::DumbTCP::receivedOutOfOrderSegment(), inet::tcp::TCPBaseAlg::receivedOutOfOrderSegment(), inet::tcp::DumbTCP::receiveSeqChanged(), and inet::tcp::TCPBaseAlg::receiveSeqChanged().

544 {
545  TCPSegment *tcpseg = createTCPSegment("ACK");
546 
547  tcpseg->setAckBit(true);
548  tcpseg->setSequenceNo(state->snd_nxt);
549  tcpseg->setAckNo(state->rcv_nxt);
550  tcpseg->setWindow(updateRcvWnd());
551 
552  // write header options
553  writeHeaderOptions(tcpseg);
554 
555  // send it
556  sendToIP(tcpseg);
557 
558  // notify
560 }
virtual TCPSegment writeHeaderOptions(TCPSegment *tcpseg)
Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implem...
Definition: TCPConnectionUtil.cc:1065
uint32 rcv_nxt
Definition: TCPConnection.h:174
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual unsigned short updateRcvWnd()
Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled...
Definition: TCPConnectionUtil.cc:1260
virtual void sendToIP(TCPSegment *tcpseg)
Utility: adds control info to segment and sends it to IP.
Definition: TCPConnectionUtil.cc:236
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void ackSent()=0
Called after we sent an ACK.
virtual TCPSegment * createTCPSegment(const char *name)
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.
Definition: TCPConnectionUtil.cc:283
bool inet::tcp::TCPConnection::sendData ( bool  fullSegmentsOnly,
uint32  congestionWindow 
)
virtual

Utility: Send data from sendQueue, at most congestionWindow.

If fullSegmentsOnly is set, don't send segments smaller than SMSS (needed for Nagle). Returns true if some data was actually sent.

Referenced by inet::tcp::DumbTCP::established(), inet::tcp::DumbTCP::receivedDataAck(), inet::tcp::DumbTCP::sendCommandInvoked(), and inet::tcp::TCPBaseAlg::sendData().

663 {
664  // we'll start sending from snd_max, if not after RTO
665  if (!state->afterRto)
667 
668  uint32 old_highRxt = 0;
669 
670  if (state->sack_enabled)
671  old_highRxt = rexmitQueue->getHighestRexmittedSeqNum();
672 
673  // check how many bytes we have
675 
676  if (buffered == 0)
677  return false;
678 
679  // maxWindow is minimum of snd_wnd and congestionWindow (snd_cwnd)
680  ulong maxWindow = std::min(state->snd_wnd, congestionWindow);
681 
682  // effectiveWindow: number of bytes we're allowed to send now
683  long effectiveWin = maxWindow - (state->snd_nxt - state->snd_una);
684 
685  if (effectiveWin <= 0) {
686  EV_WARN << "Effective window is zero (advertised window " << state->snd_wnd
687  << ", congestion window " << congestionWindow << "), cannot send.\n";
688  return false;
689  }
690 
691  ulong bytesToSend = effectiveWin;
692 
693  if (bytesToSend > buffered)
694  bytesToSend = buffered;
695 
696  uint32 effectiveMaxBytesSend = state->snd_mss;
697 
698  if (state->ts_enabled)
699  effectiveMaxBytesSend -= TCP_OPTION_TS_SIZE;
700 
701  // last segment could be less than state->snd_mss (or less than snd_mss - TCP_OPTION_TS_SIZE if using TS option)
702  if (fullSegmentsOnly && (bytesToSend < (effectiveMaxBytesSend))) {
703  EV_WARN << "Cannot send, not enough data for a full segment (SMSS=" << state->snd_mss
704  << ", effectiveWindow=" << effectiveWin << ", bytesToSend=" << bytesToSend << ", in buffer " << buffered << ")\n";
705  return false;
706  }
707 
708  // start sending 'bytesToSend' bytes
709  EV_INFO << "Will send " << bytesToSend << " bytes (effectiveWindow " << effectiveWin
710  << ", in buffer " << buffered << " bytes)\n";
711 
712  uint32 old_snd_nxt = state->snd_nxt;
713 
714  ASSERT(bytesToSend > 0);
715 
716 #ifdef TCP_SENDFRAGMENTS /* normally undefined */
717  // make agressive use of the window until the last byte
718  while (bytesToSend > 0) {
719  ulong bytes = std::min(bytesToSend, state->snd_mss);
720  sendSegment(bytes);
721  bytesToSend -= state->sentBytes;
722  }
723 #else // ifdef TCP_SENDFRAGMENTS
724  // send < MSS segments only if it's the only segment we can send now
725  // Note: if (bytesToSend == 1010 && MSS == 1012 && ts_enabled == true) => we may send
726  // 2 segments (1000 payload + 12 optionsHeader and 10 payload + 12 optionsHeader)
727  // FIXME this should probably obey Nagle's alg -- to be checked
728  if (bytesToSend <= state->snd_mss) {
729  sendSegment(bytesToSend);
730  bytesToSend -= state->sentBytes;
731  }
732  else { // send whole segments only (nagle_enabled)
733  while (bytesToSend >= effectiveMaxBytesSend) {
735  bytesToSend -= state->sentBytes;
736  }
737  }
738 
739  // check how many bytes we have - last segment could be less than state->snd_mss
741 
742  if (bytesToSend == buffered && buffered != 0) // last segment?
743  sendSegment(bytesToSend);
744  else if (bytesToSend > 0)
745  EV_DETAIL << bytesToSend << " bytes of space left in effectiveWindow\n";
746 #endif // ifdef TCP_SENDFRAGMENTS
747 
748  // remember highest seq sent (snd_nxt may be set back on retransmission,
749  // but we'll need snd_max to check validity of ACKs -- they must ack
750  // something we really sent)
753 
754  if (unackedVector)
755  unackedVector->record(state->snd_max - state->snd_una);
756 
757  // notify (once is enough)
759 
760  if (state->sack_enabled && state->lossRecovery && old_highRxt != state->highRxt) {
761  // Note: Restart of REXMIT timer on retransmission is not part of RFC 2581, however optional in RFC 3517 if sent during recovery.
762  EV_DETAIL << "Retransmission sent during recovery, restarting REXMIT timer.\n";
764  }
765  else // don't measure RTT for retransmitted packets
766  tcpAlgorithm->dataSent(old_snd_nxt);
767 
768  return true;
769 }
bool ts_enabled
Definition: TCPConnection.h:226
virtual void restartRexmitTimer()=0
Restart REXMIT timer.
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SCTPAssociation.h:270
cOutVector * unackedVector
Definition: TCPConnection.h:364
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
#define TCP_OPTION_TS_SIZE
Definition: TCPConnection.h:130
virtual void dataSent(uint32 fromseq)=0
Called after we sent data.
uint32 snd_wnd
Definition: TCPConnection.h:167
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendSegment(uint32 bytes)
Utility: sends one segment of &#39;bytes&#39; bytes from snd_nxt, and advances snd_nxt.
Definition: TCPConnectionUtil.cc:581
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
unsigned long ulong
Definition: INETDefs.h:64
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
bool afterRto
Definition: TCPConnection.h:213
uint32 highRxt
Definition: TCPConnection.h:243
uint32 sentBytes
Definition: TCPConnection.h:196
bool lossRecovery
Definition: TCPConnection.h:248
uint32 snd_max
Definition: TCPConnection.h:166
virtual void ackSent()=0
Called after we sent an ACK.
virtual uint32 getHighestRexmittedSeqNum() const
Returns the highest sequence number rexmitted by data sender.
Definition: TCPSACKRexmitQueue.cc:267
void inet::tcp::TCPConnection::sendDataDuringLossRecoveryPhase ( uint32  congestionWindow)
virtual

Utility: send data during Loss Recovery phase (if SACK is enabled).

Referenced by inet::tcp::TCPReno::receivedDataAck(), and inet::tcp::TCPReno::receivedDuplicateAck().

345 {
346  ASSERT(state->sack_enabled && state->lossRecovery);
347 
348  // RFC 3517 pages 7 and 8: "(5) In order to take advantage of potential additional available
349  // cwnd, proceed to step (C) below.
350  // (...)
351  // (C) If cwnd - pipe >= 1 SMSS the sender SHOULD transmit one or more
352  // segments as follows:
353  // (...)
354  // (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1)"
355  while (((int)congestionWindow - (int)state->pipe) >= (int)state->snd_mss) { // Note: Typecast needed to avoid prohibited transmissions
356  // RFC 3517 pages 7 and 8: "(C.1) The scoreboard MUST be queried via NextSeg () for the
357  // sequence number range of the next segment to transmit (if any),
358  // and the given segment sent. If NextSeg () returns failure (no
359  // data to send) return without sending anything (i.e., terminate
360  // steps C.1 -- C.5)."
361 
362  uint32 seqNum;
363 
364  if (!nextSeg(seqNum)) // if nextSeg() returns false (=failure): terminate steps C.1 -- C.5
365  break;
366 
368  // RFC 3517 page 8: "(C.4) The estimate of the amount of data outstanding in the
369  // network must be updated by incrementing pipe by the number of
370  // octets transmitted in (C.1)."
371  state->pipe += state->sentBytes;
372  }
373 }
virtual void sendSegmentDuringLossRecoveryPhase(uint32 seqNum)
Utility: send segment during Loss Recovery phase (if SACK is enabled).
Definition: TCPConnectionSackUtil.cc:375
uint32 pipe
Definition: TCPConnection.h:244
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual bool nextSeg(uint32 &seqNum)
For SACK TCP.
Definition: TCPConnectionSackUtil.cc:221
uint32 sentBytes
Definition: TCPConnection.h:196
bool lossRecovery
Definition: TCPConnection.h:248
void inet::tcp::TCPConnection::sendEstabIndicationToApp ( )
protectedvirtual

Utility: sends TCP_I_ESTABLISHED indication with TCPConnectInfo to application.

Referenced by processSegment1stThru8th(), and processSegmentInSynSent().

306 {
307  EV_INFO << "Notifying app: " << indicationName(TCP_I_ESTABLISHED) << "\n";
308  cMessage *msg = new cMessage(indicationName(TCP_I_ESTABLISHED));
309  msg->setKind(TCP_I_ESTABLISHED);
310 
311  TCPConnectInfo *ind = new TCPConnectInfo();
312  ind->setConnId(connId);
313  ind->setLocalAddr(localAddr);
314  ind->setRemoteAddr(remoteAddr);
315  ind->setLocalPort(localPort);
316  ind->setRemotePort(remotePort);
317 
318  msg->setControlInfo(ind);
319  sendToApp(msg);
320 }
static const char * indicationName(int code)
Utility: returns name of TCP_I_xxx constants.
Definition: TCPConnectionUtil.cc:98
L3Address remoteAddr
Definition: TCPConnection.h:325
Definition: TCPCommand_m.h:100
int localPort
Definition: TCPConnection.h:326
L3Address localAddr
Definition: TCPConnection.h:324
int remotePort
Definition: TCPConnection.h:327
virtual void sendToApp(cMessage *msg)
Utility: sends packet to application.
Definition: TCPConnectionUtil.cc:322
int connId
Definition: TCPConnection.h:321
void inet::tcp::TCPConnection::sendFin ( )
virtual

Utility: sends FIN.

Referenced by process_CLOSE(), retransmitData(), and retransmitOneSegment().

563 {
564  TCPSegment *tcpseg = createTCPSegment("FIN");
565 
566  // Note: ACK bit *must* be set for both FIN and FIN+ACK. What makes
567  // the difference for FIN+ACK is that its ackNo acks the remote TCP's FIN.
568  tcpseg->setFinBit(true);
569  tcpseg->setAckBit(true);
570  tcpseg->setAckNo(state->rcv_nxt);
571  tcpseg->setSequenceNo(state->snd_nxt);
572  tcpseg->setWindow(updateRcvWnd());
573 
574  // send it
575  sendToIP(tcpseg);
576 
577  // notify
579 }
uint32 rcv_nxt
Definition: TCPConnection.h:174
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual unsigned short updateRcvWnd()
Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled...
Definition: TCPConnectionUtil.cc:1260
virtual void sendToIP(TCPSegment *tcpseg)
Utility: adds control info to segment and sends it to IP.
Definition: TCPConnectionUtil.cc:236
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual void ackSent()=0
Called after we sent an ACK.
virtual TCPSegment * createTCPSegment(const char *name)
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.
Definition: TCPConnectionUtil.cc:283
void inet::tcp::TCPConnection::sendIndicationToApp ( int  code,
const int  id = 0 
)
protectedvirtual

Utility: sends status indication (TCP_I_xxx) to application.

Referenced by process_TIMEOUT_CONN_ESTAB(), processRstInSynReceived(), processSegment1stThru8th(), processSegmentInSynSent(), sendSegment(), and signalConnectionTimeout().

294 {
295  EV_INFO << "Notifying app: " << indicationName(code) << "\n";
296  cMessage *msg = new cMessage(indicationName(code));
297  msg->setKind(code);
298  TCPCommand *ind = new TCPCommand();
299  ind->setConnId(connId);
300  ind->setUserId(id);
301  msg->setControlInfo(ind);
302  sendToApp(msg);
303 }
static const char * indicationName(int code)
Utility: returns name of TCP_I_xxx constants.
Definition: TCPConnectionUtil.cc:98
virtual void sendToApp(cMessage *msg)
Utility: sends packet to application.
Definition: TCPConnectionUtil.cc:322
int connId
Definition: TCPConnection.h:321
void inet::tcp::TCPConnection::sendOneNewSegment ( bool  fullSegmentsOnly,
uint32  congestionWindow 
)
virtual

Utility: send one new segment from snd_max if allowed (RFC 3042).

Referenced by inet::tcp::TCPBaseAlg::receivedDuplicateAck().

1338 {
1340 
1341  // RFC 3042, page 3:
1342  // "When a TCP sender has previously unsent data queued for transmission
1343  // it SHOULD use the Limited Transmit algorithm, which calls for a TCP
1344  // sender to transmit new data upon the arrival of the first two
1345  // consecutive duplicate ACKs when the following conditions are
1346  // satisfied:
1347  //
1348  // * The receiver's advertised window allows the transmission of the
1349  // segment.
1350  //
1351  // * The amount of outstanding data would remain less than or equal
1352  // to the congestion window plus 2 segments. In other words, the
1353  // sender can only send two segments beyond the congestion window
1354  // (cwnd).
1355  //
1356  // The congestion window (cwnd) MUST NOT be changed when these new
1357  // segments are transmitted. Assuming that these new segments and the
1358  // corresponding ACKs are not dropped, this procedure allows the sender
1359  // to infer loss using the standard Fast Retransmit threshold of three
1360  // duplicate ACKs [RFC2581]. This is more robust to reordered packets
1361  // than if an old packet were retransmitted on the first or second
1362  // duplicate ACK.
1363  //
1364  // Note: If the connection is using selective acknowledgments [RFC2018],
1365  // the data sender MUST NOT send new segments in response to duplicate
1366  // ACKs that contain no new SACK information, as a misbehaving receiver
1367  // can generate such ACKs to trigger inappropriate transmission of data
1368  // segments. See [SCWA99] for a discussion of attacks by misbehaving
1369  // receivers."
1371  // check how many bytes we have
1373 
1374  if (buffered >= state->snd_mss || (!fullSegmentsOnly && buffered > 0)) {
1375  ulong outstandingData = state->snd_max - state->snd_una;
1376 
1377  // check conditions from RFC 3042
1378  if (outstandingData + state->snd_mss <= state->snd_wnd &&
1379  outstandingData + state->snd_mss <= congestionWindow + 2 * state->snd_mss)
1380  {
1381  // RFC 3042, page 3: "(...)the sender can only send two segments beyond the congestion window (cwnd)."
1382  uint32 effectiveWin = std::min(state->snd_wnd, congestionWindow) - outstandingData + 2 * state->snd_mss;
1383 
1384  // bytes: number of bytes we're allowed to send now
1385  uint32 bytes = std::min(effectiveWin, state->snd_mss);
1386 
1387  if (bytes >= state->snd_mss || (!fullSegmentsOnly && bytes > 0)) {
1388  uint32 old_snd_nxt = state->snd_nxt;
1389  // we'll start sending from snd_max
1390  state->snd_nxt = state->snd_max;
1391 
1392  EV_DETAIL << "Limited Transmit algorithm enabled. Sending one new segment.\n";
1393  sendSegment(bytes);
1394 
1396  state->snd_max = state->snd_nxt;
1397 
1398  if (unackedVector)
1399  unackedVector->record(state->snd_max - state->snd_una);
1400 
1401  // reset snd_nxt if needed
1402  if (state->afterRto)
1403  state->snd_nxt = old_snd_nxt + state->sentBytes;
1404 
1405  // notify
1406  tcpAlgorithm->ackSent();
1407  tcpAlgorithm->dataSent(old_snd_nxt);
1408  }
1409  }
1410  }
1411  }
1412 }
uint32 sackedBytes
Definition: TCPConnection.h:246
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SCTPAssociation.h:270
cOutVector * unackedVector
Definition: TCPConnection.h:364
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
virtual void dataSent(uint32 fromseq)=0
Called after we sent data.
uint32 snd_wnd
Definition: TCPConnection.h:167
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
uint32 snd_nxt
Definition: TCPConnection.h:165
uint32 sackedBytes_old
Definition: TCPConnection.h:247
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendSegment(uint32 bytes)
Utility: sends one segment of &#39;bytes&#39; bytes from snd_nxt, and advances snd_nxt.
Definition: TCPConnectionUtil.cc:581
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
unsigned long ulong
Definition: INETDefs.h:64
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
bool afterRto
Definition: TCPConnection.h:213
uint32 sentBytes
Definition: TCPConnection.h:196
uint32 snd_max
Definition: TCPConnection.h:166
virtual void ackSent()=0
Called after we sent an ACK.
bool limited_transmit_enabled
Definition: TCPConnection.h:200
bool inet::tcp::TCPConnection::sendProbe ( )
virtual

Utility: sends 1 bytes as "probe", called by the "persist" mechanism.

Referenced by inet::tcp::TCPBaseAlg::processPersistTimer().

772 {
773  // we'll start sending from snd_max
775 
776  // check we have 1 byte to send
778  EV_WARN << "Cannot send probe because send buffer is empty\n";
779  return false;
780  }
781 
782  uint32 old_snd_nxt = state->snd_nxt;
783 
784  EV_INFO << "Sending 1 byte as probe, with seq=" << state->snd_nxt << "\n";
785  sendSegment(1);
786 
787  // remember highest seq sent (snd_nxt may be set back on retransmission,
788  // but we'll need snd_max to check validity of ACKs -- they must ack
789  // something we really sent)
791 
792  if (unackedVector)
793  unackedVector->record(state->snd_max - state->snd_una);
794 
795  // notify
797  tcpAlgorithm->dataSent(old_snd_nxt);
798 
799  return true;
800 }
cOutVector * unackedVector
Definition: TCPConnection.h:364
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
virtual void dataSent(uint32 fromseq)=0
Called after we sent data.
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendSegment(uint32 bytes)
Utility: sends one segment of &#39;bytes&#39; bytes from snd_nxt, and advances snd_nxt.
Definition: TCPConnectionUtil.cc:581
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 snd_max
Definition: TCPConnection.h:166
virtual void ackSent()=0
Called after we sent an ACK.
void inet::tcp::TCPConnection::sendRst ( uint32  seqNo)
virtual

Utility: sends RST.

Referenced by process_ABORT(), processSegment1stThru8th(), processSegmentInListen(), processSegmentInSynSent(), and segmentArrivalWhileClosed().

505 {
507 }
L3Address remoteAddr
Definition: TCPConnection.h:325
int localPort
Definition: TCPConnection.h:326
L3Address localAddr
Definition: TCPConnection.h:324
int remotePort
Definition: TCPConnection.h:327
virtual void sendRst(uint32 seqNo)
Utility: sends RST.
Definition: TCPConnectionUtil.cc:504
void inet::tcp::TCPConnection::sendRst ( uint32  seq,
L3Address  src,
L3Address  dest,
int  srcPort,
int  destPort 
)
virtual

Utility: sends RST; does not use connection state.

510 {
511  TCPSegment *tcpseg = createTCPSegment("RST");
512 
513  tcpseg->setSrcPort(srcPort);
514  tcpseg->setDestPort(destPort);
515 
516  tcpseg->setRstBit(true);
517  tcpseg->setSequenceNo(seq);
518 
519  // send it
520  sendToIP(tcpseg, src, dest);
521 }
virtual void sendToIP(TCPSegment *tcpseg)
Utility: adds control info to segment and sends it to IP.
Definition: TCPConnectionUtil.cc:236
virtual TCPSegment * createTCPSegment(const char *name)
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.
Definition: TCPConnectionUtil.cc:283
void inet::tcp::TCPConnection::sendRstAck ( uint32  seq,
uint32  ack,
L3Address  src,
L3Address  dest,
int  srcPort,
int  destPort 
)
virtual

Utility: sends RST+ACK; does not use connection state.

Referenced by segmentArrivalWhileClosed().

524 {
525  TCPSegment *tcpseg = createTCPSegment("RST+ACK");
526 
527  tcpseg->setSrcPort(srcPort);
528  tcpseg->setDestPort(destPort);
529 
530  tcpseg->setRstBit(true);
531  tcpseg->setAckBit(true);
532  tcpseg->setSequenceNo(seq);
533  tcpseg->setAckNo(ack);
534 
535  // send it
536  sendToIP(tcpseg, src, dest);
537 
538  // notify
539  if (tcpAlgorithm)
541 }
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendToIP(TCPSegment *tcpseg)
Utility: adds control info to segment and sends it to IP.
Definition: TCPConnectionUtil.cc:236
virtual void ackSent()=0
Called after we sent an ACK.
virtual TCPSegment * createTCPSegment(const char *name)
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.
Definition: TCPConnectionUtil.cc:283
void inet::tcp::TCPConnection::sendSegment ( uint32  bytes)
virtual

Utility: sends one segment of 'bytes' bytes from snd_nxt, and advances snd_nxt.

sendData(), sendProbe() and retransmitData() internally all rely on this one.

Referenced by retransmitData(), retransmitOneSegment(), sendData(), sendOneNewSegment(), sendProbe(), and sendSegmentDuringLossRecoveryPhase().

582 {
583  if (state->sack_enabled && state->afterRto) {
584  // check rexmitQ and try to forward snd_nxt before sending new data
586 
587  if (forward > 0) {
588  EV_INFO << "sendSegment(" << bytes << ") forwarded " << forward << " bytes of snd_nxt from " << state->snd_nxt;
589  state->snd_nxt += forward;
590  EV_INFO << " to " << state->snd_nxt << endl;
591  rexmitQueue->info();
592  }
593  }
594 
596 
597  if (bytes > buffered) // last segment?
598  bytes = buffered;
599 
600  // if header options will be added, this could reduce the number of data bytes allowed for this segment,
601  // because following condition must to be respected:
602  // bytes + options_len <= snd_mss
603  TCPSegment *tcpseg_temp = createTCPSegment(nullptr);
604  tcpseg_temp->setAckBit(true); // needed for TS option, otherwise TSecr will be set to 0
605  writeHeaderOptions(tcpseg_temp);
606  uint options_len = tcpseg_temp->getHeaderLength() - TCP_HEADER_OCTETS; // TCP_HEADER_OCTETS = 20
607 
608  ASSERT(options_len < state->snd_mss);
609 
610  if (bytes + options_len > state->snd_mss)
611  bytes = state->snd_mss - options_len;
612 
613  state->sentBytes = bytes;
614 
615  // send one segment of 'bytes' bytes from snd_nxt, and advance snd_nxt
616  TCPSegment *tcpseg = sendQueue->createSegmentWithBytes(state->snd_nxt, bytes);
617 
618  // if sack_enabled copy region of tcpseg to rexmitQueue
619  if (state->sack_enabled)
621 
622  tcpseg->setAckNo(state->rcv_nxt);
623  tcpseg->setAckBit(true);
624  tcpseg->setWindow(updateRcvWnd());
625 
626  // TBD when to set PSH bit?
627  // TBD set URG bit if needed
628  ASSERT(bytes == tcpseg->getPayloadLength());
629 
630  state->snd_nxt += bytes;
631 
632  // check if afterRto bit can be reset
634  state->afterRto = false;
635 
637  EV_DETAIL << "Setting FIN on segment\n";
638  tcpseg->setFinBit(true);
639  state->snd_nxt = state->snd_fin_seq + 1;
640  }
641 
642  // add header options and update header length (from tcpseg_temp)
643  for (uint i = 0; i < tcpseg_temp->getHeaderOptionArraySize(); i++)
644  tcpseg->addHeaderOption(tcpseg_temp->getHeaderOption(i)->dup());
645 
646  tcpseg->setHeaderLength(tcpseg_temp->getHeaderLength());
647  delete tcpseg_temp;
648 
649  // send it
650  sendToIP(tcpseg);
651 
652  // let application fill queue again, if there is space
653  const uint32 alreadyQueued = sendQueue->getBytesAvailable(sendQueue->getBufferStartSeq());
654  const uint32 abated = (state->sendQueueLimit > alreadyQueued) ? state->sendQueueLimit - alreadyQueued : 0;
655  if ((state->sendQueueLimit > 0) && !state->queueUpdate && (abated >= state->snd_mss)) { // request more data if space >= 1 MSS
656  // Tell upper layer readiness to accept more data
658  state->queueUpdate = true;
659  }
660 }
bool seqGE(uint32 a, uint32 b)
Definition: TCPSegment.h:35
bool send_fin
Definition: TCPConnection.h:190
virtual TCPSegment writeHeaderOptions(TCPSegment *tcpseg)
Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implem...
Definition: TCPConnectionUtil.cc:1065
uint32 sendQueueLimit
Definition: TCPConnection.h:251
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TCPConnectionUtil.cc:293
unsigned int uint
Definition: INETDefs.h:63
uint32 rcv_nxt
Definition: TCPConnection.h:174
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
ulong getBytesAvailable(uint32 fromSeq)
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TCPSendQueue.h:138
virtual uint32 checkRexmitQueueForSackedOrRexmittedSegments(uint32 fromSeq) const
Checks rexmit queue for sacked of rexmitted segments and returns a certain offset (contiguous sacked ...
Definition: TCPSACKRexmitQueue.cc:277
virtual void enqueueSentData(uint32 fromSeqNum, uint32 toSeqNum)
Inserts sent data to the rexmit queue.
Definition: TCPSACKRexmitQueue.cc:87
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
uint32 snd_nxt
Definition: TCPConnection.h:165
#define TCP_HEADER_OCTETS
Definition: TCPSegment_m.h:50
uint32 snd_fin_seq
Definition: TCPConnection.h:191
uint32_t uint32
Definition: Compat.h:30
virtual unsigned short updateRcvWnd()
Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled...
Definition: TCPConnectionUtil.cc:1260
virtual uint32 getBufferStartSeq()=0
Returns the sequence number of the first byte stored in the buffer.
virtual void sendToIP(TCPSegment *tcpseg)
Utility: adds control info to segment and sends it to IP.
Definition: TCPConnectionUtil.cc:236
TCPSendQueue * sendQueue
Definition: TCPConnection.h:339
TCPStateVariables * state
Definition: TCPConnection.h:336
bool queueUpdate
Definition: TCPConnection.h:252
unsigned long ulong
Definition: INETDefs.h:64
bool afterRto
Definition: TCPConnection.h:213
Definition: TCPCommand_m.h:107
uint32 sentBytes
Definition: TCPConnection.h:196
virtual TCPSegment * createSegmentWithBytes(uint32 fromSeq, ulong maxNumBytes)=0
Called when the TCP wants to send or retransmit data, it constructs a TCP segment which contains the ...
uint32 snd_max
Definition: TCPConnection.h:166
if(!(yy_init))
Definition: lexer.cc:1644
virtual void info() const
Prints the current rexmitQueue status for debug purposes.
Definition: TCPSACKRexmitQueue.cc:51
virtual TCPSegment * createTCPSegment(const char *name)
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.
Definition: TCPConnectionUtil.cc:283
void inet::tcp::TCPConnection::sendSegmentDuringLossRecoveryPhase ( uint32  seqNum)
virtual

Utility: send segment during Loss Recovery phase (if SACK is enabled).

Referenced by sendDataDuringLossRecoveryPhase().

376 {
377  ASSERT(state->sack_enabled && state->lossRecovery);
378 
379  // start sending from seqNum
380  state->snd_nxt = seqNum;
381 
383 
384  // no need to check cwnd and rwnd - has already be done before
385  // no need to check nagle - sending mss bytes
387 
388  uint32 sentSeqNum = seqNum + state->sentBytes;
389 
390  ASSERT(seqLE(state->snd_nxt, sentSeqNum + 1)); // +1 for FIN, if sent
391 
392  // RFC 3517 page 8: "(C.2) If any of the data octets sent in (C.1) are below HighData,
393  // HighRxt MUST be set to the highest sequence number of the
394  // retransmitted segment."
395  if (seqLess(seqNum, state->snd_max)) { // HighData = snd_max
397  }
398 
399  // RFC 3517 page 8: "(C.3) If any of the data octets sent in (C.1) are above HighData,
400  // HighData must be updated to reflect the transmission of
401  // previously unsent data."
402  if (seqGreater(sentSeqNum, state->snd_max)) // HighData = snd_max
403  state->snd_max = sentSeqNum;
404 
405  if (unackedVector)
406  unackedVector->record(state->snd_max - state->snd_una);
407 
408  // RFC 3517, page 9: "6 Managing the RTO Timer
409  //
410  // The standard TCP RTO estimator is defined in [RFC2988]. Due to the
411  // fact that the SACK algorithm in this document can have an impact on
412  // the behavior of the estimator, implementers may wish to consider how
413  // the timer is managed. [RFC2988] calls for the RTO timer to be
414  // re-armed each time an ACK arrives that advances the cumulative ACK
415  // point. Because the algorithm presented in this document can keep the
416  // ACK clock going through a fairly significant loss event,
417  // (comparatively longer than the algorithm described in [RFC2581]), on
418  // some networks the loss event could last longer than the RTO. In this
419  // case the RTO timer would expire prematurely and a segment that need
420  // not be retransmitted would be resent.
421  //
422  // Therefore we give implementers the latitude to use the standard
423  // [RFC2988] style RTO management or, optionally, a more careful variant
424  // that re-arms the RTO timer on each retransmission that is sent during
425  // recovery MAY be used. This provides a more conservative timer than
426  // specified in [RFC2988], and so may not always be an attractive
427  // alternative. However, in some cases it may prevent needless
428  // retransmissions, go-back-N transmission and further reduction of the
429  // congestion window."
431 
432  if (old_highRxt != state->highRxt) {
433  // Note: Restart of REXMIT timer on retransmission is not part of RFC 2581, however optional in RFC 3517 if sent during recovery.
434  EV_INFO << "Retransmission sent during recovery, restarting REXMIT timer.\n";
436  }
437  else // don't measure RTT for retransmitted packets
438  tcpAlgorithm->dataSent(seqNum); // seqNum = old_snd_nxt
439 }
virtual void restartRexmitTimer()=0
Restart REXMIT timer.
cOutVector * unackedVector
Definition: TCPConnection.h:364
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
virtual void dataSent(uint32 fromseq)=0
Called after we sent data.
uint32 snd_mss
Definition: TCPConnection.h:159
bool sack_enabled
Definition: TCPConnection.h:235
uint32 snd_nxt
Definition: TCPConnection.h:165
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual void sendSegment(uint32 bytes)
Utility: sends one segment of &#39;bytes&#39; bytes from snd_nxt, and advances snd_nxt.
Definition: TCPConnectionUtil.cc:581
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
bool seqGreater(uint32 a, uint32 b)
Definition: TCPSegment.h:34
uint32 highRxt
Definition: TCPConnection.h:243
uint32 sentBytes
Definition: TCPConnection.h:196
bool lossRecovery
Definition: TCPConnection.h:248
uint32 snd_max
Definition: TCPConnection.h:166
virtual void ackSent()=0
Called after we sent an ACK.
virtual uint32 getHighestRexmittedSeqNum() const
Returns the highest sequence number rexmitted by data sender.
Definition: TCPSACKRexmitQueue.cc:267
void inet::tcp::TCPConnection::sendSyn ( )
protectedvirtual

Utility: send SYN.

Referenced by process_OPEN_ACTIVE(), process_SEND(), and process_TIMEOUT_SYN_REXMIT().

458 {
459  if (remoteAddr.isUnspecified() || remotePort == -1)
460  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: foreign socket unspecified");
461 
462  if (localPort == -1)
463  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: local port unspecified");
464 
465  // create segment
466  TCPSegment *tcpseg = createTCPSegment("SYN");
467  tcpseg->setSequenceNo(state->iss);
468  tcpseg->setSynBit(true);
469  updateRcvWnd();
470  tcpseg->setWindow(state->rcv_wnd);
471 
472  state->snd_max = state->snd_nxt = state->iss + 1;
473 
474  // write header options
475  writeHeaderOptions(tcpseg);
476 
477  // send it
478  sendToIP(tcpseg);
479 }
L3Address remoteAddr
Definition: TCPConnection.h:325
virtual TCPSegment writeHeaderOptions(TCPSegment *tcpseg)
Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implem...
Definition: TCPConnectionUtil.cc:1065
bool isUnspecified() const
Definition: L3Address.cc:133
uint32 snd_nxt
Definition: TCPConnection.h:165
TCP * tcpMain
Definition: TCPConnection.h:330
virtual unsigned short updateRcvWnd()
Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled...
Definition: TCPConnectionUtil.cc:1260
int localPort
Definition: TCPConnection.h:326
virtual void sendToIP(TCPSegment *tcpseg)
Utility: adds control info to segment and sends it to IP.
Definition: TCPConnectionUtil.cc:236
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 iss
Definition: TCPConnection.h:171
int remotePort
Definition: TCPConnection.h:327
uint32 rcv_wnd
Definition: TCPConnection.h:175
uint32 snd_max
Definition: TCPConnection.h:166
virtual TCPSegment * createTCPSegment(const char *name)
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.
Definition: TCPConnectionUtil.cc:283
void inet::tcp::TCPConnection::sendSynAck ( )
protectedvirtual

Utility: send SYN+ACK.

Referenced by process_TIMEOUT_SYN_REXMIT(), processSegmentInListen(), and processSegmentInSynSent().

482 {
483  // create segment
484  TCPSegment *tcpseg = createTCPSegment("SYN+ACK");
485  tcpseg->setSequenceNo(state->iss);
486  tcpseg->setAckNo(state->rcv_nxt);
487  tcpseg->setSynBit(true);
488  tcpseg->setAckBit(true);
489  updateRcvWnd();
490  tcpseg->setWindow(state->rcv_wnd);
491 
492  state->snd_max = state->snd_nxt = state->iss + 1;
493 
494  // write header options
495  writeHeaderOptions(tcpseg);
496 
497  // send it
498  sendToIP(tcpseg);
499 
500  // notify
502 }
virtual TCPSegment writeHeaderOptions(TCPSegment *tcpseg)
Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implem...
Definition: TCPConnectionUtil.cc:1065
uint32 rcv_nxt
Definition: TCPConnection.h:174
uint32 snd_nxt
Definition: TCPConnection.h:165
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
virtual unsigned short updateRcvWnd()
Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled...
Definition: TCPConnectionUtil.cc:1260
virtual void sendToIP(TCPSegment *tcpseg)
Utility: adds control info to segment and sends it to IP.
Definition: TCPConnectionUtil.cc:236
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 iss
Definition: TCPConnection.h:171
uint32 rcv_wnd
Definition: TCPConnection.h:175
uint32 snd_max
Definition: TCPConnection.h:166
virtual void ackSent()=0
Called after we sent an ACK.
virtual TCPSegment * createTCPSegment(const char *name)
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment.
Definition: TCPConnectionUtil.cc:283
void inet::tcp::TCPConnection::sendToApp ( cMessage *  msg)
protectedvirtual

Utility: sends packet to application.

Referenced by process_READ_REQUEST(), process_STATUS(), processSegment1stThru8th(), sendEstabIndicationToApp(), and sendIndicationToApp().

323 {
324  tcpMain->send(msg, "appOut", appGateIndex);
325 }
int appGateIndex
Definition: TCPConnection.h:320
TCP * tcpMain
Definition: TCPConnection.h:330
void inet::tcp::TCPConnection::sendToIP ( TCPSegment tcpseg)
virtual

Utility: adds control info to segment and sends it to IP.

Referenced by sendAck(), sendFin(), sendRst(), sendRstAck(), sendSegment(), sendSyn(), and sendSynAck().

237 {
238  // record seq (only if we do send data) and ackno
239  if (sndNxtVector && tcpseg->getPayloadLength() != 0)
240  sndNxtVector->record(tcpseg->getSequenceNo());
241 
242  if (sndAckVector)
243  sndAckVector->record(tcpseg->getAckNo());
244 
245  // final touches on the segment before sending
246  tcpseg->setSrcPort(localPort);
247  tcpseg->setDestPort(remotePort);
248  ASSERT(tcpseg->getHeaderLength() >= TCP_HEADER_OCTETS); // TCP_HEADER_OCTETS = 20 (without options)
249  ASSERT(tcpseg->getHeaderLength() <= TCP_MAX_HEADER_OCTETS); // TCP_MAX_HEADER_OCTETS = 60
250  tcpseg->setByteLength(tcpseg->getHeaderLength() + tcpseg->getPayloadLength());
251  state->sentBytes = tcpseg->getPayloadLength(); // resetting sentBytes to 0 if sending a segment without data (e.g. ACK)
252 
253  EV_INFO << "Sending: ";
254  printSegmentBrief(tcpseg);
255 
256  // TBD reuse next function for sending
257 
258  IL3AddressType *addressType = remoteAddr.getAddressType();
259  INetworkProtocolControlInfo *controlInfo = addressType->createNetworkProtocolControlInfo();
260  controlInfo->setTransportProtocol(IP_PROT_TCP);
261  controlInfo->setSourceAddress(localAddr);
262  controlInfo->setDestinationAddress(remoteAddr);
263  tcpseg->setControlInfo(check_and_cast<cObject *>(controlInfo));
264  tcpMain->send(tcpseg, "ipOut");
265 }
virtual void setTransportProtocol(short Transportprotocol)=0
const unsigned int TCP_MAX_HEADER_OCTETS
Definition: TCPSegment_m.h:53
L3Address remoteAddr
Definition: TCPConnection.h:325
cOutVector * sndNxtVector
Definition: TCPConnection.h:360
cOutVector * sndAckVector
Definition: TCPConnection.h:361
static void printSegmentBrief(TCPSegment *tcpseg)
Utility: prints important header fields.
Definition: TCPConnectionUtil.cc:157
#define TCP_HEADER_OCTETS
Definition: TCPSegment_m.h:50
IL3AddressType * getAddressType() const
Definition: L3Address.cc:60
TCP * tcpMain
Definition: TCPConnection.h:330
int localPort
Definition: TCPConnection.h:326
TCPStateVariables * state
Definition: TCPConnection.h:336
L3Address localAddr
Definition: TCPConnection.h:324
int remotePort
Definition: TCPConnection.h:327
Definition: IPProtocolId_m.h:80
virtual INetworkProtocolControlInfo * createNetworkProtocolControlInfo() const =0
uint32 sentBytes
Definition: TCPConnection.h:196
void inet::tcp::TCPConnection::sendToIP ( TCPSegment tcpseg,
L3Address  src,
L3Address  dest 
)
staticprotected

Utility: send IP packet.

268 {
269  EV_STATICCONTEXT;
270  EV_INFO << "Sending: ";
271  printSegmentBrief(tcpseg);
272 
273  IL3AddressType *addressType = dest.getAddressType();
274  INetworkProtocolControlInfo *controlInfo = addressType->createNetworkProtocolControlInfo();
275  controlInfo->setTransportProtocol(IP_PROT_TCP);
276  controlInfo->setSourceAddress(src);
277  controlInfo->setDestinationAddress(dest);
278  tcpseg->setControlInfo(check_and_cast<cObject *>(controlInfo));
279  tcpseg->setByteLength(tcpseg->getHeaderLength() + tcpseg->getPayloadLength());
280  check_and_cast<TCP *>(getSimulation()->getContextModule())->send(tcpseg, "ipOut");
281 }
static void printSegmentBrief(TCPSegment *tcpseg)
Utility: prints important header fields.
Definition: TCPConnectionUtil.cc:157
Definition: IPProtocolId_m.h:80
void inet::tcp::TCPConnection::setPipe ( )
virtual

For SACK TCP.

RFC 3517, page 3: "This routine traverses the sequence space from HighACK to HighData and MUST set the "pipe" variable to an estimate of the number of octets that are currently in transit between the TCP sender and the TCP receiver."

Referenced by inet::tcp::TCPReno::receivedDataAck(), and inet::tcp::TCPReno::receivedDuplicateAck().

154 {
155  ASSERT(state->sack_enabled);
156 
157  // RFC 3517, pages 1 and 2: "
158  // "HighACK" is the sequence number of the highest byte of data that
159  // has been cumulatively ACKed at a given point.
160  //
161  // "HighData" is the highest sequence number transmitted at a given
162  // point.
163  //
164  // "HighRxt" is the highest sequence number which has been
165  // retransmitted during the current loss recovery phase.
166  //
167  // "Pipe" is a sender's estimate of the number of bytes outstanding
168  // in the network. This is used during recovery for limiting the
169  // sender's sending rate. The pipe variable allows TCP to use a
170  // fundamentally different congestion control than specified in
171  // [RFC2581]. The algorithm is often referred to as the "pipe
172  // algorithm"."
173  // HighAck = snd_una
174  // HighData = snd_max
175 
177  state->pipe = 0;
178  uint32 length = 0; // required for rexmitQueue->checkSackBlock()
179  bool sacked; // required for rexmitQueue->checkSackBlock()
180  bool rexmitted; // required for rexmitQueue->checkSackBlock()
181 
182  // RFC 3517, page 3: "This routine traverses the sequence space from HighACK to HighData
183  // and MUST set the "pipe" variable to an estimate of the number of
184  // octets that are currently in transit between the TCP sender and
185  // the TCP receiver. After initializing pipe to zero the following
186  // steps are taken for each octet 'S1' in the sequence space between
187  // HighACK and HighData that has not been SACKed:"
188  for (uint32 s1 = state->snd_una; seqLess(s1, state->snd_max); s1 += length) {
189  rexmitQueue->checkSackBlock(s1, length, sacked, rexmitted);
190 
191  if (!sacked) {
192  // RFC 3517, page 3: "(a) If IsLost (S1) returns false:
193  //
194  // Pipe is incremented by 1 octet.
195  //
196  // The effect of this condition is that pipe is incremented for
197  // packets that have not been SACKed and have not been determined
198  // to have been lost (i.e., those segments that are still assumed
199  // to be in the network)."
200  if (isLost(s1) == false)
201  state->pipe += length;
202 
203  // RFC 3517, pages 3 and 4: "(b) If S1 <= HighRxt:
204  //
205  // Pipe is incremented by 1 octet.
206  //
207  // The effect of this condition is that pipe is incremented for
208  // the retransmission of the octet.
209  //
210  // Note that octets retransmitted without being considered lost are
211  // counted twice by the above mechanism."
212  if (seqLess(s1, state->highRxt))
213  state->pipe += length;
214  }
215  }
216 
217  if (pipeVector)
218  pipeVector->record(state->pipe);
219 }
uint32 pipe
Definition: TCPConnection.h:244
TCPSACKRexmitQueue * rexmitQueue
Definition: TCPConnection.h:344
virtual void checkSackBlock(uint32 seqNum, uint32 &length, bool &sacked, bool &rexmitted) const
Definition: TCPSACKRexmitQueue.cc:373
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
bool sack_enabled
Definition: TCPConnection.h:235
uint32 snd_una
Definition: TCPConnection.h:164
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
virtual bool isLost(uint32 seqNum)
For SACK TCP.
Definition: TCPConnectionSackUtil.cc:135
uint32 highRxt
Definition: TCPConnection.h:243
uint32 snd_max
Definition: TCPConnection.h:166
virtual uint32 getHighestRexmittedSeqNum() const
Returns the highest sequence number rexmitted by data sender.
Definition: TCPSACKRexmitQueue.cc:267
cOutVector * pipeVector
Definition: TCPConnection.h:367
void inet::tcp::TCPConnection::signalConnectionTimeout ( )
virtual

Utility: signal to user that connection timed out.

Referenced by inet::tcp::TCPBaseAlg::processRexmitTimer().

289 {
291 }
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TCPConnectionUtil.cc:293
Definition: TCPCommand_m.h:105
void inet::tcp::TCPConnection::startSynRexmitTimer ( )
virtual

Utility: start SYN-REXMIT timer.

Referenced by process_OPEN_ACTIVE(), process_SEND(), processSegmentInListen(), and processSegmentInSynSent().

1312 {
1313  state->syn_rexmit_count = 0;
1315 
1316  if (synRexmitTimer->isScheduled())
1318 
1320 }
simtime_t syn_rexmit_timeout
Definition: TCPConnection.h:183
cMessage * cancelEvent(cMessage *msg)
Utility: cancel a timer.
Definition: TCPConnection.h:529
int syn_rexmit_count
Definition: TCPConnection.h:182
TCPStateVariables * state
Definition: TCPConnection.h:336
#define TCP_TIMEOUT_SYN_REXMIT
Definition: TCPConnection.h:120
void scheduleTimeout(cMessage *msg, simtime_t timeout)
Utility: start a timer.
Definition: TCPConnection.h:524
cMessage * synRexmitTimer
Definition: TCPConnection.h:354
void inet::tcp::TCPConnection::stateEntered ( int  state,
int  oldState,
TCPEventCode  event 
)
protectedvirtual

Perform cleanup necessary when entering a new state, e.g.

cancelling timers

722 {
723  // cancel timers
724  switch (state) {
725  case TCP_S_INIT:
726  // we'll never get back to INIT
727  break;
728 
729  case TCP_S_LISTEN:
730  // we may get back to LISTEN from SYN_RCVD
731  ASSERT(connEstabTimer && synRexmitTimer);
734  break;
735 
736  case TCP_S_SYN_RCVD:
737  case TCP_S_SYN_SENT:
738  break;
739 
740  case TCP_S_ESTABLISHED:
741  // we're in ESTABLISHED, these timers are no longer needed
742  delete cancelEvent(connEstabTimer);
743  delete cancelEvent(synRexmitTimer);
744  connEstabTimer = synRexmitTimer = nullptr;
745  // TCP_I_ESTAB notification moved inside event processing
746  break;
747 
748  case TCP_S_CLOSE_WAIT:
749  case TCP_S_LAST_ACK:
750  case TCP_S_FIN_WAIT_1:
751  case TCP_S_FIN_WAIT_2:
752  case TCP_S_CLOSING:
753  if (state == TCP_S_CLOSE_WAIT)
755  // whether connection setup succeeded (ESTABLISHED) or not (others),
756  // cancel these timers
757  if (connEstabTimer)
759  if (synRexmitTimer)
761  break;
762 
763  case TCP_S_TIME_WAIT:
765  break;
766 
767  case TCP_S_CLOSED:
768  if (oldState != TCP_S_TIME_WAIT && event != TCP_E_ABORT)
770  // all timers need to be cancelled
771  if (the2MSLTimer)
773  if (connEstabTimer)
775  if (finWait2Timer)
777  if (synRexmitTimer)
780  break;
781  }
782 }
Definition: TCPCommand_m.h:102
Definition: TCPCommand_m.h:101
Definition: TCPConnection.h:68
Definition: TCPConnection.h:69
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TCPConnectionUtil.cc:293
cMessage * cancelEvent(cMessage *msg)
Utility: cancel a timer.
Definition: TCPConnection.h:529
Definition: TCPConnection.h:70
virtual void connectionClosed()=0
Called when the connection closes, it should cancel all running timers.
Definition: TCPConnection.h:74
Definition: TCPConnection.h:66
Definition: TCPConnection.h:72
Definition: TCPConnection.h:63
Definition: TCPConnection.h:90
cMessage * the2MSLTimer
Definition: TCPConnection.h:351
TCPAlgorithm * tcpAlgorithm
Definition: TCPConnection.h:348
TCPStateVariables * state
Definition: TCPConnection.h:336
cMessage * finWait2Timer
Definition: TCPConnection.h:353
cMessage * connEstabTimer
Definition: TCPConnection.h:352
Definition: TCPConnection.h:71
Definition: TCPConnection.h:65
Definition: TCPConnection.h:67
Definition: TCPConnection.h:64
Definition: TCPConnection.h:73
cMessage * synRexmitTimer
Definition: TCPConnection.h:354
const char * inet::tcp::TCPConnection::stateName ( int  state)
static

Utility: returns name of TCP_S_xxx constants.

Referenced by printConnBrief(), process_STATUS(), process_TIMEOUT_2MSL(), process_TIMEOUT_CONN_ESTAB(), process_TIMEOUT_FIN_WAIT_2(), process_TIMEOUT_SYN_REXMIT(), processSegment1stThru8th(), and processTSOption().

46 {
47 #define CASE(x) case x: \
48  s = #x + 6; break
49  const char *s = "unknown";
50  switch (state) {
63  }
64  return s;
65 #undef CASE
66 }
Definition: TCPConnection.h:68
Definition: TCPConnection.h:69
Definition: TCPConnection.h:70
Definition: TCPConnection.h:74
Definition: TCPConnection.h:66
Definition: TCPConnection.h:72
Definition: TCPConnection.h:63
#define CASE(x)
TCPStateVariables * state
Definition: TCPConnection.h:336
Definition: TCPConnection.h:71
value< double, units::s > s
Definition: Units.h:1049
Definition: TCPConnection.h:65
Definition: TCPConnection.h:67
Definition: TCPConnection.h:64
Definition: TCPConnection.h:73
bool inet::tcp::TCPConnection::tryFastRoute ( TCPSegment tcpseg)
protectedvirtual

Shortcut to process most common case as fast as possible.

Returns false if segment requires normal (slow) route.

34 {
35  // fast route processing not yet implemented
36  return false;
37 }
void inet::tcp::TCPConnection::updateRcvQueueVars ( )
virtual

Utility: update receiver queue related variables and statistics - called before setting rcv_wnd.

Referenced by processSegment1stThru8th(), processSegmentInListen(), processSegmentInSynSent(), and updateRcvWnd().

1248 {
1249  // update receive queue related state variables
1252 
1253  // update receive queue related statistics
1256 
1257 // tcpEV << "receiveQ: receiveQLength=" << receiveQueue->getQueueLength() << " maxRcvBuffer=" << state->maxRcvBuffer << " usedRcvBuffer=" << state->usedRcvBuffer << " freeRcvBuffer=" << state->freeRcvBuffer << "\n";
1258 }
uint32 freeRcvBuffer
Definition: TCPConnection.h:264
virtual uint32 getAmountOfFreeBytes(uint32 maxRcvBuffer)=0
Returns the number of bytes currently free (=available) in queue.
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 maxRcvBuffer
Definition: TCPConnection.h:262
cOutVector * tcpRcvQueueBytesVector
Definition: TCPConnection.h:374
uint32 usedRcvBuffer
Definition: TCPConnection.h:263
unsigned short inet::tcp::TCPConnection::updateRcvWnd ( )
virtual

Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled.

Returns the (scaled) receive window size.

Referenced by sendAck(), sendFin(), sendSegment(), sendSyn(), and sendSynAck().

1261 {
1262  uint32 win = 0;
1263 
1264  // update receive queue related state variables and statistics
1266  win = state->freeRcvBuffer;
1267 
1268  // Following lines are based on [Stevens, W.R.: TCP/IP Illustrated, Volume 2, chapter 26.7, pages 878-879]:
1269  // Don't advertise less than one full-sized segment to avoid SWS
1270  if (win < (state->maxRcvBuffer / 4) && win < state->snd_mss)
1271  win = 0;
1272 
1273  // Do not shrink window
1274  // (rcv_adv minus rcv_nxt) is the amount of space still available to the sender that was previously advertised
1275  if (win < state->rcv_adv - state->rcv_nxt)
1276  win = state->rcv_adv - state->rcv_nxt;
1277 
1278  // Observe upper limit for advertised window on this connection
1279  if (win > TCP_MAX_WIN && !state->ws_enabled) // TCP_MAX_WIN = 65535 (16 bit)
1280  win = TCP_MAX_WIN; // Note: The window size is limited to a 16 bit value in the TCP header if WINDOW SCALE option (RFC 1323) is not used
1281 
1282  // Note: The order of the "Do not shrink window" and "Observe upper limit" parts has been changed to the order used in FreeBSD Release 7.1
1283 
1284  // update rcv_adv if needed
1285  if (win > 0 && seqGE(state->rcv_nxt + win, state->rcv_adv)) {
1286  state->rcv_adv = state->rcv_nxt + win;
1287 
1288  if (rcvAdvVector)
1289  rcvAdvVector->record(state->rcv_adv);
1290  }
1291 
1292  state->rcv_wnd = win;
1293 
1294  if (rcvWndVector)
1295  rcvWndVector->record(state->rcv_wnd);
1296 
1297  // scale rcv_wnd:
1298  uint32 scaled_rcv_wnd = state->rcv_wnd;
1299  if (state->ws_enabled && state->rcv_wnd_scale) {
1300  ASSERT(state->rcv_wnd_scale <= 14); // RFC 1323, page 11: "the shift count must be limited to 14"
1301  scaled_rcv_wnd = scaled_rcv_wnd >> state->rcv_wnd_scale;
1302  }
1303 
1304  ASSERT(scaled_rcv_wnd == (unsigned short)scaled_rcv_wnd);
1305 
1306  return (unsigned short)scaled_rcv_wnd;
1307 }
bool seqGE(uint32 a, uint32 b)
Definition: TCPSegment.h:35
uint32 rcv_adv
Definition: TCPConnection.h:178
uint32 rcv_nxt
Definition: TCPConnection.h:174
uint32 freeRcvBuffer
Definition: TCPConnection.h:264
#define TCP_MAX_WIN
Definition: TCPConnection.h:125
bool ws_enabled
Definition: TCPConnection.h:217
virtual void updateRcvQueueVars()
Utility: update receiver queue related variables and statistics - called before setting rcv_wnd...
Definition: TCPConnectionUtil.cc:1247
cOutVector * rcvAdvVector
Definition: TCPConnection.h:359
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 maxRcvBuffer
Definition: TCPConnection.h:262
uint rcv_wnd_scale
Definition: TCPConnection.h:221
uint32 rcv_wnd
Definition: TCPConnection.h:175
cOutVector * rcvWndVector
Definition: TCPConnection.h:358
void inet::tcp::TCPConnection::updateWndInfo ( TCPSegment tcpseg,
bool  doAlways = false 
)
virtual

Utility: update window information (snd_wnd, snd_wl1, snd_wl2)

Referenced by processAckInEstabEtc(), processSegmentInListen(), and processSegmentInSynSent().

1310 {
1311  uint32 true_window = tcpseg->getWindow();
1312  // RFC 1323, page 10:
1313  // "The window field (SEG.WND) in the header of every incoming
1314  // segment, with the exception of SYN segments, is left-shifted
1315  // by Snd.Wind.Scale bits before updating SND.WND:
1316  // SND.WND = SEG.WND << Snd.Wind.Scale"
1317  if (state->ws_enabled && !tcpseg->getSynBit())
1318  true_window = tcpseg->getWindow() << state->snd_wnd_scale;
1319 
1320  // Following lines are based on [Stevens, W.R.: TCP/IP Illustrated, Volume 2, page 982]:
1321  if (doAlways || (tcpseg->getAckBit()
1322  && (seqLess(state->snd_wl1, tcpseg->getSequenceNo()) ||
1323  (state->snd_wl1 == tcpseg->getSequenceNo() && seqLE(state->snd_wl2, tcpseg->getAckNo())) ||
1324  (state->snd_wl2 == tcpseg->getAckNo() && true_window > state->snd_wnd))))
1325  {
1326  // send window should be updated
1327  state->snd_wnd = true_window;
1328  EV_INFO << "Updating send window from segment: new wnd=" << state->snd_wnd << "\n";
1329  state->snd_wl1 = tcpseg->getSequenceNo();
1330  state->snd_wl2 = tcpseg->getAckNo();
1331 
1332  if (sndWndVector)
1333  sndWndVector->record(state->snd_wnd);
1334  }
1335 }
uint32 snd_wl1
Definition: TCPConnection.h:169
uint snd_wnd_scale
Definition: TCPConnection.h:222
bool seqLess(uint32 a, uint32 b)
Definition: TCPSegment.h:32
bool ws_enabled
Definition: TCPConnection.h:217
uint32 snd_wnd
Definition: TCPConnection.h:167
uint32 snd_wl2
Definition: TCPConnection.h:170
bool seqLE(uint32 a, uint32 b)
Definition: TCPSegment.h:33
uint32_t uint32
Definition: Compat.h:30
TCPStateVariables * state
Definition: TCPConnection.h:336
cOutVector * sndWndVector
Definition: TCPConnection.h:357
TCPSegment inet::tcp::TCPConnection::writeHeaderOptions ( TCPSegment tcpseg)
protectedvirtual

Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implemented)

Referenced by sendAck(), sendSegment(), sendSyn(), and sendSynAck().

1066 {
1067  // SYN flag set and connetion in INIT or LISTEN state (or after synRexmit timeout)
1068  if (tcpseg->getSynBit() && (fsm.getState() == TCP_S_INIT || fsm.getState() == TCP_S_LISTEN
1069  || ((fsm.getState() == TCP_S_SYN_SENT || fsm.getState() == TCP_S_SYN_RCVD)
1070  && state->syn_rexmit_count > 0)))
1071  {
1072  // MSS header option
1073  if (state->snd_mss > 0) {
1074  TCPOptionMaxSegmentSize *option = new TCPOptionMaxSegmentSize();
1075  option->setMaxSegmentSize(state->snd_mss);
1076  tcpseg->addHeaderOption(option);
1077  EV_INFO << "TCP Header Option MSS(=" << state->snd_mss << ") sent\n";
1078  }
1079 
1080  // WS header option
1081  if (state->ws_support && (state->rcv_ws || (fsm.getState() == TCP_S_INIT
1082  || (fsm.getState() == TCP_S_SYN_SENT && state->syn_rexmit_count > 0))))
1083  {
1084  // 1 padding byte
1085  tcpseg->addHeaderOption(new TCPOptionNop()); // NOP
1086 
1087  // Update WS variables
1088  if (state->ws_manual_scale > -1) {
1090  } else {
1091  ulong scaled_rcv_wnd = receiveQueue->getFirstSeqNo() + state->maxRcvBuffer - state->rcv_nxt;
1092  state->rcv_wnd_scale = 0;
1093 
1094  while (scaled_rcv_wnd > TCP_MAX_WIN && state->rcv_wnd_scale < 14) { // RFC 1323, page 11: "the shift count must be limited to 14"
1095  scaled_rcv_wnd = scaled_rcv_wnd >> 1;
1096  state->rcv_wnd_scale++;
1097  }
1098  }
1099 
1100  TCPOptionWindowScale *option = new TCPOptionWindowScale();
1101  option->setWindowScale(state->rcv_wnd_scale); // rcv_wnd_scale is also set in scaleRcvWnd()
1102  state->snd_ws = true;
1104  EV_INFO << "TCP Header Option WS(=" << option->getWindowScale() << ") sent, WS (ws_enabled) is set to " << state->ws_enabled << "\n";
1105  tcpseg->addHeaderOption(option);
1106  }
1107 
1108  // SACK_PERMITTED header option
1109  if (state->sack_support && (state->rcv_sack_perm || (fsm.getState() == TCP_S_INIT
1110  || (fsm.getState() == TCP_S_SYN_SENT && state->syn_rexmit_count > 0))))
1111  {
1112  if (!state->ts_support) { // if TS is supported by host, do not add NOPs to this segment
1113  // 2 padding bytes
1114  tcpseg->addHeaderOption(new TCPOptionNop()); // NOP
1115  tcpseg->addHeaderOption(new TCPOptionNop()); // NOP
1116  }
1117 
1118  tcpseg->addHeaderOption(new TCPOptionSackPermitted());
1119 
1120  // Update SACK variables
1121  state->snd_sack_perm = true;
1123  EV_INFO << "TCP Header Option SACK_PERMITTED sent, SACK (sack_enabled) is set to " << state->sack_enabled << "\n";
1124  }
1125 
1126  // TS header option
1127  if (state->ts_support && (state->rcv_initial_ts || (fsm.getState() == TCP_S_INIT
1128  || (fsm.getState() == TCP_S_SYN_SENT && state->syn_rexmit_count > 0))))
1129  {
1130  if (!state->sack_support) { // if SACK is supported by host, do not add NOPs to this segment
1131  // 2 padding bytes
1132  tcpseg->addHeaderOption(new TCPOptionNop()); // NOP
1133  tcpseg->addHeaderOption(new TCPOptionNop()); // NOP
1134  }
1135 
1136  TCPOptionTimestamp *option = new TCPOptionTimestamp();
1137 
1138  // Update TS variables
1139  // RFC 1323, page 13: "The Timestamp Value field (TSval) contains the current value of the timestamp clock of the TCP sending the option."
1140  option->setSenderTimestamp(convertSimtimeToTS(simTime()));
1141 
1142  // RFC 1323, page 16: "(3) When a TSopt is sent, its TSecr field is set to the current TS.Recent value."
1143  // RFC 1323, page 13:
1144  // "The Timestamp Echo Reply field (TSecr) is only valid if the ACK
1145  // bit is set in the TCP header; if it is valid, it echos a times-
1146  // tamp value that was sent by the remote TCP in the TSval field
1147  // of a Timestamps option. When TSecr is not valid, its value
1148  // must be zero."
1149  option->setEchoedTimestamp(tcpseg->getAckBit() ? state->ts_recent : 0);
1150 
1151  state->snd_initial_ts = true;
1153  EV_INFO << "TCP Header Option TS(TSval=" << option->getSenderTimestamp() << ", TSecr=" << option->getEchoedTimestamp() << ") sent, TS (ts_enabled) is set to " << state->ts_enabled << "\n";
1154  tcpseg->addHeaderOption(option);
1155  }
1156 
1157  // TODO add new TCPOptions here once they are implemented
1158  }
1159  else if (fsm.getState() == TCP_S_SYN_SENT || fsm.getState() == TCP_S_SYN_RCVD
1160  || fsm.getState() == TCP_S_ESTABLISHED || fsm.getState() == TCP_S_FIN_WAIT_1
1161  || fsm.getState() == TCP_S_FIN_WAIT_2) // connetion is not in INIT or LISTEN state
1162  {
1163  // TS header option
1164  if (state->ts_enabled) { // Is TS enabled?
1165  if (!(state->sack_enabled && (state->snd_sack || state->snd_dsack))) { // if SACK is enabled and SACKs need to be added, do not add NOPs to this segment
1166  // 2 padding bytes
1167  tcpseg->addHeaderOption(new TCPOptionNop()); // NOP
1168  tcpseg->addHeaderOption(new TCPOptionNop()); // NOP
1169  }
1170 
1171  TCPOptionTimestamp *option = new TCPOptionTimestamp();
1172 
1173  // Update TS variables
1174  // RFC 1323, page 13: "The Timestamp Value field (TSval) contains the current value of the timestamp clock of the TCP sending the option."
1175  option->setSenderTimestamp(convertSimtimeToTS(simTime()));
1176 
1177  // RFC 1323, page 16: "(3) When a TSopt is sent, its TSecr field is set to the current TS.Recent value."
1178  // RFC 1323, page 13:
1179  // "The Timestamp Echo Reply field (TSecr) is only valid if the ACK
1180  // bit is set in the TCP header; if it is valid, it echos a times-
1181  // tamp value that was sent by the remote TCP in the TSval field
1182  // of a Timestamps option. When TSecr is not valid, its value
1183  // must be zero."
1184  option->setEchoedTimestamp(tcpseg->getAckBit() ? state->ts_recent : 0);
1185 
1186  EV_INFO << "TCP Header Option TS(TSval=" << option->getSenderTimestamp() << ", TSecr=" << option->getEchoedTimestamp() << ") sent\n";
1187  tcpseg->addHeaderOption(option);
1188  }
1189 
1190  // SACK header option
1191 
1192  // RFC 2018, page 4:
1193  // "If sent at all, SACK options SHOULD be included in all ACKs which do
1194  // not ACK the highest sequence number in the data receiver's queue. In
1195  // this situation the network has lost or mis-ordered data, such that
1196  // the receiver holds non-contiguous data in its queue. RFC 1122,
1197  // Section 4.2.2.21, discusses the reasons for the receiver to send ACKs
1198  // in response to additional segments received in this state. The
1199  // receiver SHOULD send an ACK for every valid segment that arrives
1200  // containing new data, and each of these "duplicate" ACKs SHOULD bear a
1201  // SACK option."
1202  if (state->sack_enabled && (state->snd_sack || state->snd_dsack)) {
1203  addSacks(tcpseg);
1204  }
1205 
1206  // TODO add new TCPOptions here once they are implemented
1207  // TODO delegate to TCPAlgorithm as well -- it may want to append additional options
1208  }
1209 
1210  if (tcpseg->getHeaderOptionArraySize() != 0) {
1211  uint options_len = tcpseg->getHeaderOptionArrayLength();
1212 
1213  if (options_len <= TCP_OPTIONS_MAX_SIZE) // Options length allowed? - maximum: 40 Bytes
1214  tcpseg->setHeaderLength(TCP_HEADER_OCTETS + options_len); // TCP_HEADER_OCTETS = 20
1215  else {
1216  tcpseg->setHeaderLength(TCP_HEADER_OCTETS); // TCP_HEADER_OCTETS = 20
1217  tcpseg->dropHeaderOptions(); // drop all options
1218  EV_ERROR << "ERROR: Options length exceeded! Segment will be sent without options" << "\n";
1219  }
1220  }
1221 
1222  return *tcpseg;
1223 }
bool ts_enabled
Definition: TCPConnection.h:226
int ws_manual_scale
Definition: TCPConnection.h:218
bool ws_support
Definition: TCPConnection.h:216
Definition: TCPConnection.h:68
unsigned int uint
Definition: INETDefs.h:63
bool sack_support
Definition: TCPConnection.h:234
uint32 rcv_nxt
Definition: TCPConnection.h:174
static uint32 convertSimtimeToTS(simtime_t simtime)
Utility: converts a given simtime to a timestamp (TS).
Definition: TCPConnectionUtil.cc:1414
cFSM fsm
Definition: TCPConnection.h:333
Definition: TCPConnection.h:66
#define TCP_MAX_WIN
Definition: TCPConnection.h:125
Definition: TCPConnection.h:72
Definition: TCPConnection.h:63
bool ws_enabled
Definition: TCPConnection.h:217
bool rcv_initial_ts
Definition: TCPConnection.h:228
bool snd_dsack
Definition: TCPConnection.h:241
virtual TCPSegment addSacks(TCPSegment *tcpseg)
Utility: adds SACKs to segments header options field.
Definition: TCPConnectionSackUtil.cc:441
#define TCP_OPTIONS_MAX_SIZE
Definition: TCPConnection.h:128
uint32 snd_mss
Definition: TCPConnection.h:159
TCPReceiveQueue * receiveQueue
Definition: TCPConnection.h:340
bool sack_enabled
Definition: TCPConnection.h:235
bool snd_ws
Definition: TCPConnection.h:219
bool rcv_sack_perm
Definition: TCPConnection.h:237
#define TCP_HEADER_OCTETS
Definition: TCPSegment_m.h:50
bool snd_initial_ts
Definition: TCPConnection.h:227
bool snd_sack
Definition: TCPConnection.h:240
bool rcv_ws
Definition: TCPConnection.h:220
bool snd_sack_perm
Definition: TCPConnection.h:236
int syn_rexmit_count
Definition: TCPConnection.h:182
TCPStateVariables * state
Definition: TCPConnection.h:336
uint32 maxRcvBuffer
Definition: TCPConnection.h:262
Definition: TCPConnection.h:71
unsigned long ulong
Definition: INETDefs.h:64
uint rcv_wnd_scale
Definition: TCPConnection.h:221
Definition: TCPConnection.h:65
uint32 ts_recent
Definition: TCPConnection.h:229
Definition: TCPConnection.h:67
virtual uint32 getFirstSeqNo()=0
Returns the minimum of first byte seq.no.
bool ts_support
Definition: TCPConnection.h:225

Member Data Documentation

cMessage* inet::tcp::TCPConnection::connEstabTimer = nullptr
protected
cOutVector* inet::tcp::TCPConnection::dupAcksVector = nullptr
protected
cMessage* inet::tcp::TCPConnection::finWait2Timer = nullptr
protected
cOutVector* inet::tcp::TCPConnection::pipeVector = nullptr
protected

Referenced by setPipe().

cOutVector* inet::tcp::TCPConnection::rcvAckVector = nullptr
protected

Referenced by process_RCV_SEGMENT().

cOutVector* inet::tcp::TCPConnection::rcvAdvVector = nullptr
protected
cOutVector* inet::tcp::TCPConnection::rcvNASegVector = nullptr
protected
cOutVector* inet::tcp::TCPConnection::rcvOooSegVector = nullptr
protected
cOutVector* inet::tcp::TCPConnection::rcvSacksVector = nullptr
protected

Referenced by processSACKOption().

cOutVector* inet::tcp::TCPConnection::rcvSeqVector = nullptr
protected

Referenced by process_RCV_SEGMENT().

cOutVector* inet::tcp::TCPConnection::rcvWndVector = nullptr
protected

Referenced by updateRcvWnd().

cOutVector* inet::tcp::TCPConnection::sackedBytesVector = nullptr
protected

Referenced by processSACKOption().

cOutVector* inet::tcp::TCPConnection::sndAckVector = nullptr
protected

Referenced by sendToIP().

cOutVector* inet::tcp::TCPConnection::sndNxtVector = nullptr
protected

Referenced by sendToIP().

cOutVector* inet::tcp::TCPConnection::sndSacksVector = nullptr
protected

Referenced by addSacks().

cOutVector* inet::tcp::TCPConnection::sndWndVector = nullptr
protected

Referenced by updateWndInfo().

cMessage* inet::tcp::TCPConnection::synRexmitTimer = nullptr
protected
cOutVector* inet::tcp::TCPConnection::tcpRcvQueueBytesVector = nullptr
protected

Referenced by updateRcvQueueVars().

cOutVector* inet::tcp::TCPConnection::tcpRcvQueueDropsVector = nullptr
protected
cMessage* inet::tcp::TCPConnection::the2MSLTimer = nullptr
protected
TCPDataTransferMode inet::tcp::TCPConnection::transferMode = TCP_TRANSFER_UNDEFINED
protected
cOutVector* inet::tcp::TCPConnection::unackedVector = nullptr
protected

The documentation for this class was generated from the following files: