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

int getSocketId () const
 
void setSocketId (int newSocketId)
 
int getListeningSocketId () const
 
const L3AddressgetLocalAddr () const
 
const L3AddressgetRemoteAddr () const
 
TcpSackRexmitQueuegetRexmitQueue () const
 

Public Attributes

int socketId = -1
 
int listeningSocketId = -1
 
L3Address localAddr
 
L3Address remoteAddr
 
int localPort = -1
 
int remotePort = -1
 
int ttl = -1
 
short dscp = -1
 
short tos = -1
 
TcpSackRexmitQueuerexmitQueue = nullptr
 

Static Public Attributes

static simsignal_t tcpConnectionAddedSignal
 
static simsignal_t stateSignal = registerSignal("state")
 
static simsignal_t sndWndSignal = registerSignal("sndWnd")
 
static simsignal_t rcvWndSignal = registerSignal("rcvWnd")
 
static simsignal_t rcvAdvSignal = registerSignal("rcvAdv")
 
static simsignal_t sndNxtSignal = registerSignal("sndNxt")
 
static simsignal_t sndAckSignal = registerSignal("sndAck")
 
static simsignal_t rcvSeqSignal = registerSignal("rcvSeq")
 
static simsignal_t rcvAckSignal = registerSignal("rcvAck")
 
static simsignal_t unackedSignal = registerSignal("unacked")
 
static simsignal_t dupAcksSignal = registerSignal("dupAcks")
 
static simsignal_t pipeSignal = registerSignal("pipe")
 
static simsignal_t sndSacksSignal = registerSignal("sndSacks")
 
static simsignal_t rcvSacksSignal = registerSignal("rcvSacks")
 
static simsignal_t rcvOooSegSignal = registerSignal("rcvOooSeg")
 
static simsignal_t rcvNASegSignal = registerSignal("rcvNASeg")
 
static simsignal_t sackedBytesSignal = registerSignal("sackedBytes")
 
static simsignal_t tcpRcvQueueBytesSignal = registerSignal("tcpRcvQueueBytes")
 
static simsignal_t tcpRcvQueueDropsSignal = registerSignal("tcpRcvQueueDrops")
 
static simsignal_t tcpRcvPayloadBytesSignal = registerSignal("tcpRcvPayloadBytes")
 

Protected Member Functions

TcpSendQueuegetSendQueue () const
 
TcpReceiveQueuegetReceiveQueue () const
 
TcpAlgorithmgetTcpAlgorithm () const
 
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_ACCEPT (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_DESTROY (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)
 
virtual void process_OPTIONS (TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
 
Processing TCP segment arrivals. Invoked from processTCPSegment().
virtual bool tryFastRoute (const Ptr< const TcpHeader > &tcpHeader)
 Shortcut to process most common case as fast as possible. More...
 
virtual TcpEventCode process_RCV_SEGMENT (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address src, L3Address dest)
 Process incoming TCP segment. More...
 
virtual TcpEventCode processSegmentInListen (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address src, L3Address dest)
 
virtual TcpEventCode processSynInListen (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address srcAddr, L3Address destAddr)
 
virtual TcpEventCode processSegmentInSynSent (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address src, L3Address dest)
 
virtual TcpEventCode processSegment1stThru8th (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
 
virtual TcpEventCode processRstInSynReceived (const Ptr< const TcpHeader > &tcpHeader)
 
virtual bool processAckInEstabEtc (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
 
Processing of TCP options. Invoked from readHeaderOptions(). Return value indicates whether the option was valid.
virtual bool processMSSOption (const Ptr< const TcpHeader > &tcpHeader, const TcpOptionMaxSegmentSize &option)
 
virtual bool processWSOption (const Ptr< const TcpHeader > &tcpHeader, const TcpOptionWindowScale &option)
 
virtual bool processSACKPermittedOption (const Ptr< const TcpHeader > &tcpHeader, const TcpOptionSackPermitted &option)
 
virtual bool processSACKOption (const Ptr< const TcpHeader > &tcpHeader, const TcpOptionSack &option)
 
virtual bool processTSOption (const Ptr< const TcpHeader > &tcpHeader, const TcpOptionTimestamp &option)
 

Protected Attributes

TcptcpMain = nullptr
 
cFSM fsm
 
TcpStateVariablesstate = nullptr
 
TcpSendQueuesendQueue = nullptr
 
TcpReceiveQueuereceiveQueue = nullptr
 
TcpAlgorithmtcpAlgorithm = nullptr
 
cMessage * the2MSLTimer = nullptr
 
cMessage * connEstabTimer = nullptr
 
cMessage * finWait2Timer = nullptr
 
cMessage * synRexmitTimer = nullptr
 

Processing timeouts. Invoked from processTimer().

virtual void sendAck ()
 Utility: send ACK. More...
 
virtual bool sendData (uint32_t 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_t seqNo)
 Utility: sends RST. More...
 
virtual void sendRst (uint32_t seq, L3Address src, L3Address dest, int srcPort, int destPort)
 Utility: sends RST; does not use connection state. More...
 
virtual void sendRstAck (uint32_t seq, uint32_t 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 uint32_t sendSegment (uint32_t bytes)
 Utility: sends one segment of 'bytes' bytes from snd_nxt, and advances snd_nxt. More...
 
virtual void sendToIP (Packet *tcpSegment, const Ptr< TcpHeader > &tcpHeader)
 Utility: adds control info to segment and sends it to IP. More...
 
virtual void startSynRexmitTimer ()
 Utility: start SYN-REXMIT timer. More...
 
virtual void signalConnectionTimeout ()
 Utility: signal to user that connection timed out. More...
 
virtual void printConnBrief () const
 Utility: prints local/remote addr/port and app gate index/socketId. More...
 
virtual void updateRcvQueueVars ()
 Utility: update receiver queue related variables and statistics - called before setting rcv_wnd. More...
 
virtual bool hasEnoughSpaceForSegmentInReceiveQueue (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
 Utility: returns true when receive queue has enough space for store the tcpHeader. More...
 
virtual unsigned short updateRcvWnd ()
 Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled. More...
 
virtual void updateWndInfo (const Ptr< const TcpHeader > &tcpHeader, bool doAlways=false)
 Utility: update window information (snd_wnd, snd_wl1, snd_wl2) More...
 
 TcpConnection ()
 
 TcpConnection (const TcpConnection &other)
 
void initialize ()
 
void initConnection (Tcp *mod, int socketId)
 The "normal" constructor. More...
 
virtual ~TcpConnection ()
 Destructor. More...
 
int getLocalPort () const
 
L3Address getLocalAddress () const
 
int getRemotePort () const
 
L3Address getRemoteAddress () const
 
virtual void segmentArrivalWhileClosed (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address src, L3Address dest)
 This method gets invoked from TCP when a segment arrives which doesn't belong to an existing connection. More...
 
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)
 
virtual TcpConnectioncloneListeningConnection ()
 Utility: clone a listening connection. More...
 
virtual void initClonedConnection (TcpConnection *listenerConn)
 
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 (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader) 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 (const Ptr< const TcpHeader > &tcpHeader)
 Utility: readHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implemented) More...
 
virtual TcpHeader writeHeaderOptions (const Ptr< TcpHeader > &tcpHeader)
 Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implemented) More...
 
virtual TcpHeader addSacks (const Ptr< TcpHeader > &tcpHeader)
 Utility: adds SACKs to segments header options field. More...
 
virtual uint32_t getTSval (const Ptr< const TcpHeader > &tcpHeader) const
 Utility: get TSval from segments TS header option. More...
 
virtual uint32_t getTSecr (const Ptr< const TcpHeader > &tcpHeader) const
 Utility: get TSecr from segments TS header option. More...
 
virtual bool isToBeAccepted () const
 Utility: returns true if the connection is not yet accepted by the application. More...
 
virtual void sendToIP (Packet *pkt, const Ptr< TcpHeader > &tcpHeader, L3Address src, L3Address dest)
 Utility: send IP packet. 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 sendAvailableIndicationToApp ()
 Utility: sends TCP_I_AVAILABLE indication with TcpAvailableInfo to application. More...
 
virtual void sendEstabIndicationToApp ()
 Utility: sends TCP_I_ESTABLISHED indication with TcpConnectInfo to application. More...
 
virtual void sendAvailableDataToApp ()
 Utility: sends data or data notification to application. More...
 
static void printSegmentBrief (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
 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...
 

Various getters

int getFsmState () const
 
const TcpStateVariablesgetState () const
 
TcpStateVariablesgetState ()
 
TcpSendQueuegetSendQueue ()
 
TcpSackRexmitQueuegetRexmitQueue ()
 
TcpReceiveQueuegetReceiveQueue ()
 
TcpAlgorithmgetTcpAlgorithm ()
 
TcpgetTcpMain ()
 
virtual bool processTimer (cMessage *msg)
 Process self-messages (timers). More...
 
virtual bool processTCPSegment (Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address srcAddr, L3Address destAddr)
 Process incoming TCP segment. More...
 
virtual bool processAppCommand (cMessage *msg)
 Process commands from the application. More...
 
virtual void handleMessage (cMessage *msg)
 
virtual bool isLost (uint32_t seqNum)
 For SACK TCP. More...
 
virtual void setPipe ()
 For SACK TCP. More...
 
virtual bool nextSeg (uint32_t &seqNum)
 For SACK TCP. More...
 
virtual void sendDataDuringLossRecoveryPhase (uint32_t congestionWindow)
 Utility: send data during Loss Recovery phase (if SACK is enabled). More...
 
virtual uint32_t sendSegmentDuringLossRecoveryPhase (uint32_t seqNum)
 Utility: send segment during Loss Recovery phase (if SACK is enabled). More...
 
virtual void sendOneNewSegment (bool fullSegmentsOnly, uint32_t 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...
 
static uint32_t convertSimtimeToTS (simtime_t simtime)
 Utility: converts a given simtime to a timestamp (TS). More...
 
static simtime_t convertTSToSimtime (uint32_t timestamp)
 Utility: converts a given timestamp (TS) to a simtime. More...
 

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

◆ TcpConnection() [1/2]

inet::tcp::TcpConnection::TcpConnection ( )
inline
582 {}

◆ TcpConnection() [2/2]

inet::tcp::TcpConnection::TcpConnection ( const TcpConnection other)
inline
583 {} // FIXME kludge

◆ ~TcpConnection()

inet::tcp::TcpConnection::~TcpConnection ( )
virtual

Destructor.

222 {
223  delete sendQueue;
224  delete rexmitQueue;
225  delete receiveQueue;
226  delete tcpAlgorithm;
227  delete state;
228 
229  if (the2MSLTimer)
230  delete cancelEvent(the2MSLTimer);
231  if (connEstabTimer)
232  delete cancelEvent(connEstabTimer);
233  if (finWait2Timer)
234  delete cancelEvent(finWait2Timer);
235  if (synRexmitTimer)
236  delete cancelEvent(synRexmitTimer);
237 }

Member Function Documentation

◆ addSacks()

TcpHeader inet::tcp::TcpConnection::addSacks ( const Ptr< TcpHeader > &  tcpHeader)
protectedvirtual

Utility: adds SACKs to segments header options field.

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

Referenced by writeHeaderOptions().

◆ cloneListeningConnection()

TcpConnection * inet::tcp::TcpConnection::cloneListeningConnection ( )
protectedvirtual

Utility: clone a listening connection.

Used for forking.

235 {
236  auto moduleType = cModuleType::get("inet.transportlayer.tcp.TcpConnection");
237  int newSocketId = getEnvir()->getUniqueNumber();
238  char submoduleName[24];
239  sprintf(submoduleName, "conn-%d", newSocketId);
240  auto conn = check_and_cast<TcpConnection *>(moduleType->createScheduleInit(submoduleName, tcpMain));
241  conn->initConnection(tcpMain, newSocketId);
242  conn->initClonedConnection(this);
243  return conn;
244 }

Referenced by processSegmentInListen().

◆ configureStateVariables()

void inet::tcp::TcpConnection::configureStateVariables ( )
protectedvirtual

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

437 {
438  state->dupthresh = tcpMain->par("dupthresh");
439  long advertisedWindowPar = tcpMain->par("advertisedWindow");
440  state->ws_support = tcpMain->par("windowScalingSupport"); // if set, this means that current host supports WS (RFC 1323)
441  state->ws_manual_scale = tcpMain->par("windowScalingFactor"); // scaling factor (set manually) to help for Tcp validation
442  state->ecnWillingness = tcpMain->par("ecnWillingness"); // if set, current host is willing to use ECN
443  if ((!state->ws_support && advertisedWindowPar > TCP_MAX_WIN) || advertisedWindowPar <= 0 || advertisedWindowPar > TCP_MAX_WIN_SCALED)
444  throw cRuntimeError("Invalid advertisedWindow parameter: %ld", advertisedWindowPar);
445 
446  state->rcv_wnd = advertisedWindowPar;
447  state->rcv_adv = advertisedWindowPar;
448 
449  if (state->ws_support && advertisedWindowPar > TCP_MAX_WIN) {
450  state->rcv_wnd = TCP_MAX_WIN; // we cannot to guarantee that the other end is also supporting the Window Scale (header option) (RFC 1322)
451  state->rcv_adv = TCP_MAX_WIN; // therefore TCP_MAX_WIN is used as initial value for rcv_wnd and rcv_adv
452  }
453 
454  state->maxRcvBuffer = advertisedWindowPar;
455  state->delayed_acks_enabled = tcpMain->par("delayedAcksEnabled"); // delayed ACK algorithm (RFC 1122) enabled/disabled
456  state->nagle_enabled = tcpMain->par("nagleEnabled"); // Nagle's algorithm (RFC 896) enabled/disabled
457  state->limited_transmit_enabled = tcpMain->par("limitedTransmitEnabled"); // Limited Transmit algorithm (RFC 3042) enabled/disabled
458  state->increased_IW_enabled = tcpMain->par("increasedIWEnabled"); // Increased Initial Window (RFC 3390) enabled/disabled
459  state->snd_mss = tcpMain->par("mss"); // Maximum Segment Size (RFC 793)
460  state->ts_support = tcpMain->par("timestampSupport"); // if set, this means that current host supports TS (RFC 1323)
461  state->sack_support = tcpMain->par("sackSupport"); // if set, this means that current host supports SACK (RFC 2018, 2883, 3517)
462 
463  if (state->sack_support) {
464  std::string algorithmName1 = "TcpReno";
465  std::string algorithmName2 = tcpMain->par("tcpAlgorithmClass");
466 
467  if (algorithmName1 != algorithmName2) { // TODO add additional checks for new SACK supporting algorithms here once they are implemented
468  EV_DEBUG << "If you want to use TCP SACK please set tcpAlgorithmClass to TcpReno\n";
469 
470  ASSERT(false);
471  }
472  }
473 }

Referenced by initClonedConnection(), and initConnection().

◆ convertSimtimeToTS()

uint32_t inet::tcp::TcpConnection::convertSimtimeToTS ( simtime_t  simtime)
static

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

1590 {
1591  ASSERT(SimTime::getScaleExp() <= -3);
1592 
1593  uint32_t timestamp = (uint32_t)(simtime.inUnit(SIMTIME_MS));
1594  return timestamp;
1595 }

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

◆ convertTSToSimtime()

simtime_t inet::tcp::TcpConnection::convertTSToSimtime ( uint32_t  timestamp)
static

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

1598 {
1599  ASSERT(SimTime::getScaleExp() <= -3);
1600 
1601  simtime_t simtime(timestamp, SIMTIME_MS);
1602  return simtime;
1603 }

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

◆ eventName()

const char * inet::tcp::TcpConnection::eventName ( int  event)
static

Utility: returns name of TCP_E_xxx constants.

66 {
67 #define CASE(x) case x: \
68  s = (char *)#x + 6; break
69  const char *s = "unknown";
70  switch (event) {
91  }
92  return s;
93 #undef CASE
94 }

Referenced by performStateTransition(), and processAppCommand().

◆ getFsmState()

int inet::tcp::TcpConnection::getFsmState ( ) const
inline
612 { return fsm.getState(); }

Referenced by inet::tcp::operator<<().

◆ getListeningSocketId()

int inet::tcp::TcpConnection::getListeningSocketId ( ) const
inline
342 { return listeningSocketId; }

◆ getLocalAddr()

const L3Address& inet::tcp::TcpConnection::getLocalAddr ( ) const
inline
346 { return localAddr; }

◆ getLocalAddress()

L3Address inet::tcp::TcpConnection::getLocalAddress ( ) const
inline
597 { return localAddr; }

◆ getLocalPort()

int inet::tcp::TcpConnection::getLocalPort ( ) const
inline
596 { return localPort; }

◆ getReceiveQueue() [1/2]

TcpReceiveQueue* inet::tcp::TcpConnection::getReceiveQueue ( )
inline
617 { return receiveQueue; }

◆ getReceiveQueue() [2/2]

TcpReceiveQueue* inet::tcp::TcpConnection::getReceiveQueue ( ) const
inlineprotected
370 { return receiveQueue; }

◆ getRemoteAddr()

const L3Address& inet::tcp::TcpConnection::getRemoteAddr ( ) const
inline
348 { return remoteAddr; }

◆ getRemoteAddress()

L3Address inet::tcp::TcpConnection::getRemoteAddress ( ) const
inline
600 { return remoteAddr; }

◆ getRemotePort()

int inet::tcp::TcpConnection::getRemotePort ( ) const
inline
599 { return remotePort; }

◆ getRexmitQueue() [1/2]

TcpSackRexmitQueue* inet::tcp::TcpConnection::getRexmitQueue ( )
inline
616 { return rexmitQueue; }

◆ getRexmitQueue() [2/2]

TcpSackRexmitQueue* inet::tcp::TcpConnection::getRexmitQueue ( ) const
inline
374 { return rexmitQueue; }

◆ getSendQueue() [1/2]

TcpSendQueue* inet::tcp::TcpConnection::getSendQueue ( )
inline
615 { return sendQueue; }

◆ getSendQueue() [2/2]

TcpSendQueue* inet::tcp::TcpConnection::getSendQueue ( ) const
inlineprotected
368 { return sendQueue; }

◆ getSocketId()

int inet::tcp::TcpConnection::getSocketId ( ) const
inline
338 { return socketId; }

Referenced by initClonedConnection().

◆ getState() [1/2]

TcpStateVariables* inet::tcp::TcpConnection::getState ( )
inline
614 { return state; }

◆ getState() [2/2]

const TcpStateVariables* inet::tcp::TcpConnection::getState ( ) const
inline

◆ getTcpAlgorithm() [1/2]

TcpAlgorithm* inet::tcp::TcpConnection::getTcpAlgorithm ( )
inline
618 { return tcpAlgorithm; }

◆ getTcpAlgorithm() [2/2]

TcpAlgorithm* inet::tcp::TcpConnection::getTcpAlgorithm ( ) const
inlineprotected
379 { return tcpAlgorithm; }

◆ getTcpMain()

Tcp* inet::tcp::TcpConnection::getTcpMain ( )
inline

◆ getTSecr()

uint32_t inet::tcp::TcpConnection::getTSecr ( const Ptr< const TcpHeader > &  tcpHeader) const
protectedvirtual

Utility: get TSecr from segments TS header option.

1416 {
1417  for (uint i = 0; i < tcpHeader->getHeaderOptionArraySize(); i++) {
1418  const TcpOption *option = tcpHeader->getHeaderOption(i);
1419  if (option->getKind() == TCPOPTION_TIMESTAMP)
1420  return check_and_cast<const TcpOptionTimestamp *>(option)->getEchoedTimestamp();
1421  }
1422 
1423  return 0;
1424 }

Referenced by processAckInEstabEtc().

◆ getTSval()

uint32_t inet::tcp::TcpConnection::getTSval ( const Ptr< const TcpHeader > &  tcpHeader) const
protectedvirtual

Utility: get TSval from segments TS header option.

1405 {
1406  for (uint i = 0; i < tcpHeader->getHeaderOptionArraySize(); i++) {
1407  const TcpOption *option = tcpHeader->getHeaderOption(i);
1408  if (option->getKind() == TCPOPTION_TIMESTAMP)
1409  return check_and_cast<const TcpOptionTimestamp *>(option)->getSenderTimestamp();
1410  }
1411 
1412  return 0;
1413 }

Referenced by processSegment1stThru8th().

◆ handleMessage()

void inet::tcp::TcpConnection::handleMessage ( cMessage *  msg)
virtual
240 {
241  if (msg->isSelfMessage()) {
242  if (!processTimer(msg))
243  tcpMain->removeConnection(this);
244  }
245  else
246  throw cRuntimeError("model error: TcpConnection allows only self messages");
247 }

◆ hasEnoughSpaceForSegmentInReceiveQueue()

bool inet::tcp::TcpConnection::hasEnoughSpaceForSegmentInReceiveQueue ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader 
)
virtual

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

110 {
111  // TODO must rewrite it
112 // return (state->freeRcvBuffer >= tcpHeader->getPayloadLength()); // enough freeRcvBuffer in rcvQueue for new segment?
113 
114  long int payloadLength = tcpSegment->getByteLength() - B(tcpHeader->getHeaderLength()).get();
115  uint32_t payloadSeq = tcpHeader->getSequenceNo();
116  uint32_t firstSeq = receiveQueue->getFirstSeqNo();
117  if (seqLess(payloadSeq, firstSeq)) {
118  long delta = firstSeq - payloadSeq;
119  payloadSeq += delta;
120  payloadLength -= delta;
121  }
122  return seqLE(firstSeq, payloadSeq) && seqLE(payloadSeq + payloadLength, firstSeq + state->maxRcvBuffer);
123 }

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

◆ indicationName()

const char * inet::tcp::TcpConnection::indicationName ( int  code)
static

Utility: returns name of TCP_I_xxx constants.

97 {
98 #define CASE(x) case x: \
99  s = (char *)#x + 6; break
100  const char *s = "unknown";
101  switch (code) {
102  CASE(TCP_I_DATA);
113  }
114  return s;
115 #undef CASE
116 }

Referenced by sendAvailableIndicationToApp(), sendEstabIndicationToApp(), and sendIndicationToApp().

◆ initClonedConnection()

void inet::tcp::TcpConnection::initClonedConnection ( TcpConnection listenerConn)
protectedvirtual
201 {
202  Enter_Method("initClonedConnection");
203  listeningSocketId = listenerConn->getSocketId();
204 
205  // following code to be kept consistent with initConnection()
206  const char *sendQueueClass = listenerConn->sendQueue->getClassName();
207  sendQueue = check_and_cast<TcpSendQueue *>(inet::utils::createOne(sendQueueClass));
208  sendQueue->setConnection(this);
209 
210  const char *receiveQueueClass = listenerConn->receiveQueue->getClassName();
211  receiveQueue = check_and_cast<TcpReceiveQueue *>(inet::utils::createOne(receiveQueueClass));
213 
214  // create SACK retransmit queue
215  rexmitQueue = new TcpSackRexmitQueue();
216  rexmitQueue->setConnection(this);
217 
218  const char *tcpAlgorithmClass = listenerConn->tcpAlgorithm->getClassName();
219  tcpAlgorithm = check_and_cast<TcpAlgorithm *>(inet::utils::createOne(tcpAlgorithmClass));
221 
225 
226  // put it into LISTEN, with our localAddr/localPort
227  state->active = false;
228  state->fork = true;
229  localAddr = listenerConn->localAddr;
230  localPort = listenerConn->localPort;
231  FSM_Goto(fsm, TCP_S_LISTEN);
232 }

◆ initConnection() [1/2]

void inet::tcp::TcpConnection::initConnection ( Tcp mod,
int  socketId 
)

The "normal" constructor.

199 {
200  Enter_Method("initConnection");
201 
202  tcpMain = _mod;
203  socketId = _socketId;
204 
205  fsm.setName(getName());
206  fsm.setState(TCP_S_INIT);
207 
208  // queues and algorithm will be created on active or passive open
209 
210  the2MSLTimer = new cMessage("2MSL");
211  connEstabTimer = new cMessage("CONN-ESTAB");
212  finWait2Timer = new cMessage("FIN-WAIT-2");
213  synRexmitTimer = new cMessage("SYN-REXMIT");
214 
215  the2MSLTimer->setContextPointer(this);
216  connEstabTimer->setContextPointer(this);
217  finWait2Timer->setContextPointer(this);
218  synRexmitTimer->setContextPointer(this);
219 }

◆ initConnection() [2/2]

void inet::tcp::TcpConnection::initConnection ( TcpOpenCommand openCmd)
protectedvirtual

Utility: creates send/receive queues and tcpAlgorithm.

408 {
409  // create send queue
411  sendQueue->setConnection(this);
412 
413  // create receive queue
416 
417  // create SACK retransmit queue
418  rexmitQueue = new TcpSackRexmitQueue();
419  rexmitQueue->setConnection(this);
420 
421  // create algorithm
422  const char *tcpAlgorithmClass = openCmd->getTcpAlgorithmClass();
423 
424  if (opp_isempty(tcpAlgorithmClass))
425  tcpAlgorithmClass = tcpMain->par("tcpAlgorithmClass");
426 
427  tcpAlgorithm = check_and_cast<TcpAlgorithm *>(inet::utils::createOne(tcpAlgorithmClass));
429 
430  // create state block
434 }

Referenced by process_OPEN_ACTIVE(), and process_OPEN_PASSIVE().

◆ initialize()

void inet::tcp::TcpConnection::initialize ( )
inline
584 {}

◆ isLost()

bool inet::tcp::TcpConnection::isLost ( uint32_t  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."

124 {
125  ASSERT(state->sack_enabled);
126 
127  // RFC 3517, page 3: "This routine returns whether the given sequence number is
128  // considered to be lost. The routine returns true when either
129  // DupThresh discontiguous SACKed sequences have arrived above
130  // 'SeqNum' or (DupThresh * SMSS) bytes with sequence numbers greater
131  // than 'SeqNum' have been SACKed. Otherwise, the routine returns
132  // false."
133  ASSERT(seqGE(seqNum, state->snd_una)); // HighAck = snd_una
134 
137 
138  return isLost;
139 }

Referenced by nextSeg(), and setPipe().

◆ isSegmentAcceptable()

bool inet::tcp::TcpConnection::isSegmentAcceptable ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader 
) const
protectedvirtual

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

487 {
488  // check that segment entirely falls in receive window
489  // RFC 793, page 69:
490  // "There are four cases for the acceptability test for an incoming segment:
491  // Segment Receive Test
492  // Length Window
493  // ------- ------- -------------------------------------------
494  // 0 0 SEG.SEQ = RCV.NXT
495  // 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
496  // >0 0 not acceptable
497  // >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
498  // or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND"
499  uint32_t len = tcpSegment->getByteLength() - B(tcpHeader->getHeaderLength()).get();
500  uint32_t seqNo = tcpHeader->getSequenceNo();
501  uint32_t ackNo = tcpHeader->getAckNo();
502  uint32_t rcvWndEnd = state->rcv_nxt + state->rcv_wnd;
503  bool ret;
504 
505  if (len == 0) {
506  if (state->rcv_wnd == 0)
507  ret = (seqNo == state->rcv_nxt);
508  else // rcv_wnd > 0
509 // ret = seqLE(state->rcv_nxt, seqNo) && seqLess(seqNo, rcvWndEnd);
510  ret = seqLE(state->rcv_nxt, seqNo) && seqLE(seqNo, rcvWndEnd); // Accept an ACK on end of window
511  }
512  else { // len > 0
513  if (state->rcv_wnd == 0)
514  ret = false;
515  else // rcv_wnd > 0
516  ret = (seqLE(state->rcv_nxt, seqNo) && seqLess(seqNo, rcvWndEnd))
517  || (seqLess(state->rcv_nxt, seqNo + len) && seqLE(seqNo + len, rcvWndEnd)); // Accept an ACK on end of window
518  }
519 
520  // RFC 793, page 25:
521  // "A new acknowledgment (called an "acceptable ack"), is one for which
522  // the inequality below holds:
523  // SND.UNA < SEG.ACK =< SND.NXT"
524  if (!ret && len == 0) {
525  if (!state->afterRto)
526  ret = (seqLess(state->snd_una, ackNo) && seqLE(ackNo, state->snd_nxt));
527  else
528  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
529  }
530 
531  if (!ret)
532  EV_WARN << "Not Acceptable segment. seqNo=" << seqNo << " ackNo=" << ackNo << " len=" << len << " rcv_nxt="
533  << state->rcv_nxt << " rcv_wnd=" << state->rcv_wnd << " afterRto=" << state->afterRto << "\n";
534 
535  return ret;
536 }

Referenced by processSegment1stThru8th().

◆ isSendQueueEmpty()

bool inet::tcp::TcpConnection::isSendQueueEmpty ( )
virtual

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

1606 {
1607  return sendQueue->getBytesAvailable(state->snd_nxt) == 0;
1608 }

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

◆ isToBeAccepted()

virtual bool inet::tcp::TcpConnection::isToBeAccepted ( ) const
inlineprotectedvirtual

Utility: returns true if the connection is not yet accepted by the application.

489 { return listeningSocketId != -1; }

Referenced by process_READ_REQUEST(), and processSegment1stThru8th().

◆ nextSeg()

bool inet::tcp::TcpConnection::nextSeg ( uint32_t &  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.

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

Referenced by sendDataDuringLossRecoveryPhase().

◆ optionName()

const char * inet::tcp::TcpConnection::optionName ( int  option)
static

Utility: returns name of TCPOPTION_xxx constants.

119 {
120  switch (option) {
122  return "EOL";
123 
125  return "NOP";
126 
128  return "MSS";
129 
131  return "WS";
132 
134  return "SACK_PERMITTED";
135 
136  case TCPOPTION_SACK:
137  return "SACK";
138 
139  case TCPOPTION_TIMESTAMP:
140  return "TS";
141 
142  default:
143  return "unknown";
144  }
145 }

Referenced by printSegmentBrief(), and readHeaderOptions().

◆ performStateTransition()

bool inet::tcp::TcpConnection::performStateTransition ( const TcpEventCode event)
protectedvirtual

Implemements the pure TCP state machine.

415 {
416  ASSERT(fsm.getState() != TCP_S_CLOSED); // closed connections should be deleted immediately
417 
418  if (event == TCP_E_IGNORE) { // e.g. discarded segment
419  EV_DETAIL << "Staying in state: " << stateName(fsm.getState()) << " (no FSM event)\n";
420  return true;
421  }
422 
423  // state machine
424  // TODO add handling of connection timeout event (KEEP-ALIVE), with transition to CLOSED
425  // Note: empty "default:" lines are for gcc's benefit which would otherwise spit warnings
426  int oldState = fsm.getState();
427 
428  switch (fsm.getState()) {
429  case TCP_S_INIT:
430  switch (event) {
431  case TCP_E_OPEN_PASSIVE:
432  FSM_Goto(fsm, TCP_S_LISTEN);
433  break;
434 
435  case TCP_E_OPEN_ACTIVE:
436  FSM_Goto(fsm, TCP_S_SYN_SENT);
437  break;
438 
439  case TCP_E_DESTROY:
440  FSM_Goto(fsm, TCP_S_CLOSED);
441  break;
442 
443  default:
444  break;
445  }
446  break;
447 
448  case TCP_S_LISTEN:
449  switch (event) {
450  case TCP_E_OPEN_ACTIVE:
451  FSM_Goto(fsm, TCP_S_SYN_SENT);
452  break;
453 
454  case TCP_E_SEND:
455  FSM_Goto(fsm, TCP_S_SYN_SENT);
456  break;
457 
458  case TCP_E_CLOSE:
459  FSM_Goto(fsm, TCP_S_CLOSED);
460  break;
461 
462  case TCP_E_ABORT:
463  FSM_Goto(fsm, TCP_S_CLOSED);
464  break;
465 
466  case TCP_E_DESTROY:
467  FSM_Goto(fsm, TCP_S_CLOSED);
468  break;
469 
470  case TCP_E_RCV_SYN:
471  FSM_Goto(fsm, TCP_S_SYN_RCVD);
472  break;
473 
474  default:
475  break;
476  }
477  break;
478 
479  case TCP_S_SYN_RCVD:
480  switch (event) {
481  case TCP_E_CLOSE:
482  FSM_Goto(fsm, TCP_S_FIN_WAIT_1);
483  break;
484 
485  case TCP_E_ABORT:
486  FSM_Goto(fsm, TCP_S_CLOSED);
487  break;
488 
489  case TCP_E_DESTROY:
490  FSM_Goto(fsm, TCP_S_CLOSED);
491  break;
492 
494  FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN);
495  break;
496 
497  case TCP_E_RCV_RST:
498  FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN);
499  break;
500 
501  case TCP_E_RCV_ACK:
502  FSM_Goto(fsm, TCP_S_ESTABLISHED);
503  break;
504 
505  case TCP_E_RCV_FIN:
506  FSM_Goto(fsm, TCP_S_CLOSE_WAIT);
507  break;
508 
509  case TCP_E_RCV_UNEXP_SYN:
510  FSM_Goto(fsm, TCP_S_CLOSED);
511  break;
512 
513  default:
514  break;
515  }
516  break;
517 
518  case TCP_S_SYN_SENT:
519  switch (event) {
520  case TCP_E_CLOSE:
521  case TCP_E_ABORT:
522  case TCP_E_DESTROY:
524  case TCP_E_RCV_RST:
525  FSM_Goto(fsm, TCP_S_CLOSED);
526  break;
527 
528  case TCP_E_RCV_SYN_ACK:
529  FSM_Goto(fsm, TCP_S_ESTABLISHED);
530  break;
531 
532  case TCP_E_RCV_SYN:
533  FSM_Goto(fsm, TCP_S_SYN_RCVD);
534  break;
535 
536  default:
537  break;
538  }
539  break;
540 
541  case TCP_S_ESTABLISHED:
542  switch (event) {
543  case TCP_E_CLOSE:
544  FSM_Goto(fsm, TCP_S_FIN_WAIT_1);
545  break;
546 
547  case TCP_E_ABORT:
548  case TCP_E_DESTROY:
549  case TCP_E_RCV_RST:
550  case TCP_E_RCV_UNEXP_SYN:
551  FSM_Goto(fsm, TCP_S_CLOSED);
552  break;
553 
554  case TCP_E_RCV_FIN:
555  FSM_Goto(fsm, TCP_S_CLOSE_WAIT);
556  break;
557 
558  default:
559  break;
560  }
561  break;
562 
563  case TCP_S_CLOSE_WAIT:
564  switch (event) {
565  case TCP_E_CLOSE:
566  FSM_Goto(fsm, TCP_S_LAST_ACK);
567  break;
568 
569  case TCP_E_ABORT:
570  case TCP_E_DESTROY:
571  case TCP_E_RCV_RST:
572  case TCP_E_RCV_UNEXP_SYN:
573  FSM_Goto(fsm, TCP_S_CLOSED);
574  break;
575 
576  default:
577  break;
578  }
579  break;
580 
581  case TCP_S_LAST_ACK:
582  switch (event) {
583  case TCP_E_ABORT:
584  case TCP_E_DESTROY:
585  case TCP_E_RCV_ACK:
586  case TCP_E_RCV_RST:
587  case TCP_E_RCV_UNEXP_SYN:
588  FSM_Goto(fsm, TCP_S_CLOSED);
589  break;
590 
591  default:
592  break;
593  }
594  break;
595 
596  case TCP_S_FIN_WAIT_1:
597  switch (event) {
598  case TCP_E_ABORT:
599  case TCP_E_DESTROY:
600  case TCP_E_RCV_RST:
601  case TCP_E_RCV_UNEXP_SYN:
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  default:
618  break;
619  }
620  break;
621 
622  case TCP_S_FIN_WAIT_2:
623  switch (event) {
624  case TCP_E_ABORT:
625  case TCP_E_DESTROY:
627  case TCP_E_RCV_RST:
628  case TCP_E_RCV_UNEXP_SYN:
629  FSM_Goto(fsm, TCP_S_CLOSED);
630  break;
631 
632  case TCP_E_RCV_FIN:
633  FSM_Goto(fsm, TCP_S_TIME_WAIT);
634  break;
635 
636  default:
637  break;
638  }
639  break;
640 
641  case TCP_S_CLOSING:
642  switch (event) {
643  case TCP_E_ABORT:
644  case TCP_E_DESTROY:
645  case TCP_E_RCV_RST:
646  case TCP_E_RCV_UNEXP_SYN:
647  FSM_Goto(fsm, TCP_S_CLOSED);
648  break;
649 
650  case TCP_E_RCV_ACK:
651  FSM_Goto(fsm, TCP_S_TIME_WAIT);
652  break;
653 
654  default:
655  break;
656  }
657  break;
658 
659  case TCP_S_TIME_WAIT:
660  switch (event) {
661  case TCP_E_ABORT:
662  case TCP_E_TIMEOUT_2MSL:
663  case TCP_E_RCV_RST:
664  case TCP_E_RCV_UNEXP_SYN:
665  case TCP_E_DESTROY:
666  FSM_Goto(fsm, TCP_S_CLOSED);
667  break;
668 
669  default:
670  break;
671  }
672  break;
673 
674  case TCP_S_CLOSED:
675  break;
676  }
677 
678  if (oldState != fsm.getState()) {
679  EV_INFO << "Transition: " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n";
680  EV_DEBUG_C("testing") << tcpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (on " << eventName(event) << ")\n";
681 
682  // cancel timers, etc.
683  stateEntered(fsm.getState(), oldState, event);
684  }
685  else {
686  EV_DETAIL << "Staying in state: " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n";
687  }
688 
689  return fsm.getState() != TCP_S_CLOSED;
690 }

Referenced by processAppCommand(), processSegmentInListen(), processTCPSegment(), and processTimer().

◆ preanalyseAppCommandEvent()

TcpEventCode inet::tcp::TcpConnection::preanalyseAppCommandEvent ( int  commandCode)
protectedvirtual

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

374 {
375  switch (commandCode) {
376  case TCP_C_OPEN_ACTIVE:
377  return TCP_E_OPEN_ACTIVE;
378 
379  case TCP_C_OPEN_PASSIVE:
380  return TCP_E_OPEN_PASSIVE;
381 
382  case TCP_C_ACCEPT:
383  return TCP_E_ACCEPT;
384 
385  case TCP_C_SEND:
386  return TCP_E_SEND;
387 
388  case TCP_C_CLOSE:
389  return TCP_E_CLOSE;
390 
391  case TCP_C_ABORT:
392  return TCP_E_ABORT;
393 
394  case TCP_C_DESTROY:
395  return TCP_E_DESTROY;
396 
397  case TCP_C_STATUS:
398  return TCP_E_STATUS;
399 
402 
403  case TCP_C_READ:
404  return TCP_E_READ;
405 
406  case TCP_C_SETOPTION:
407  return TCP_E_SETOPTION;
408 
409  default:
410  throw cRuntimeError(tcpMain, "Unknown message kind in app command");
411  }
412 }

Referenced by processAppCommand().

◆ printConnBrief()

void inet::tcp::TcpConnection::printConnBrief ( ) const
virtual

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

148 {
149  EV_DETAIL << "Connection "
150  << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort
151  << " on socketId=" << socketId
152  << " in " << stateName(fsm.getState())
153  << "\n";
154 }

Referenced by processAppCommand(), processTCPSegment(), and processTimer().

◆ printSegmentBrief()

void inet::tcp::TcpConnection::printSegmentBrief ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader 
)
static

Utility: prints important header fields.

157 {
158  EV_STATICCONTEXT;
159  EV_INFO << "." << tcpHeader->getSrcPort() << " > ";
160  EV_INFO << "." << tcpHeader->getDestPort() << ": ";
161 
162  if (tcpHeader->getSynBit())
163  EV_INFO << (tcpHeader->getAckBit() ? "SYN+ACK " : "SYN ");
164 
165  if (tcpHeader->getFinBit())
166  EV_INFO << "FIN(+ACK) ";
167 
168  if (tcpHeader->getRstBit())
169  EV_INFO << (tcpHeader->getAckBit() ? "RST+ACK " : "RST ");
170 
171  if (tcpHeader->getPshBit())
172  EV_INFO << "PSH ";
173 
174  auto payloadLength = tcpSegment->getByteLength() - B(tcpHeader->getHeaderLength()).get();
175  if (payloadLength > 0 || tcpHeader->getSynBit()) {
176  EV_INFO << "[" << tcpHeader->getSequenceNo() << ".." << (tcpHeader->getSequenceNo() + payloadLength) << ") ";
177  EV_INFO << "(l=" << payloadLength << ") ";
178  }
179 
180  if (tcpHeader->getAckBit())
181  EV_INFO << "ack " << tcpHeader->getAckNo() << " ";
182 
183  EV_INFO << "win " << tcpHeader->getWindow() << " ";
184 
185  if (tcpHeader->getUrgBit())
186  EV_INFO << "urg " << tcpHeader->getUrgentPointer() << " ";
187 
188  if (tcpHeader->getHeaderLength() > TCP_MIN_HEADER_LENGTH) { // Header options present?
189  EV_INFO << "options ";
190 
191  for (uint i = 0; i < tcpHeader->getHeaderOptionArraySize(); i++) {
192  const TcpOption *option = tcpHeader->getHeaderOption(i);
193  short kind = option->getKind();
194  EV_INFO << optionName(kind) << " ";
195  }
196  }
197  EV_INFO << "\n";
198 }

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

◆ process_ABORT()

void inet::tcp::TcpConnection::process_ABORT ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
248 {
249  delete tcpCommand;
250  delete msg;
251 
252  //
253  // The ABORT event will automatically take the connection to the CLOSED
254  // state, flush queues etc -- no need to do it here. Also, we don't need to
255  // send notification to the user, they know what's going on.
256  //
257  switch (fsm.getState()) {
258  case TCP_S_INIT:
259  throw cRuntimeError("Error processing command ABORT: connection not open");
260 
261  case TCP_S_SYN_RCVD:
262  case TCP_S_ESTABLISHED:
263  case TCP_S_FIN_WAIT_1:
264  case TCP_S_FIN_WAIT_2:
265  case TCP_S_CLOSE_WAIT:
266  //"
267  // Send a reset segment:
268  //
269  // <SEQ=SND.NXT><CTL=RST>
270  //"
272  break;
273  }
274 }

Referenced by processAppCommand().

◆ process_ACCEPT()

void inet::tcp::TcpConnection::process_ACCEPT ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
103 {
104  TcpAcceptCommand *acceptCommand = check_and_cast<TcpAcceptCommand *>(tcpCommand);
105  listeningSocketId = -1;
108  delete acceptCommand;
109  delete msg;
110 }

Referenced by processAppCommand().

◆ process_CLOSE()

void inet::tcp::TcpConnection::process_CLOSE ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
191 {
192  delete tcpCommand;
193  delete msg;
194 
195  switch (fsm.getState()) {
196  case TCP_S_INIT:
197  case TCP_S_LISTEN:
198  // Nothing to do here
199  break;
200 
201  case TCP_S_SYN_SENT:
202  // Delete the TCB and return "error: closing" responses to any
203  // queued SENDs, or RECEIVEs.
204  break;
205 
206  case TCP_S_SYN_RCVD:
207  case TCP_S_ESTABLISHED:
208  case TCP_S_CLOSE_WAIT:
209  //
210  // SYN_RCVD processing (ESTABLISHED and CLOSE_WAIT are similar):
211  //"
212  // If no SENDs have been issued and there is no pending data to send,
213  // then form a FIN segment and send it, and enter FIN-WAIT-1 state;
214  // otherwise queue for processing after entering ESTABLISHED state.
215  //"
216  if (state->snd_max == sendQueue->getBufferEndSeq()) {
217  EV_DETAIL << "No outstanding SENDs, sending FIN right away, advancing snd_nxt over the FIN\n";
219  sendFin();
221  state->snd_max = ++state->snd_nxt;
222 
224 
225  // state transition will automatically take us to FIN_WAIT_1 (or LAST_ACK)
226  }
227  else {
228  EV_DETAIL << "SEND of " << (sendQueue->getBufferEndSeq() - state->snd_max)
229  << " bytes pending, deferring sending of FIN\n";
230  event = TCP_E_IGNORE;
231  }
232  state->send_fin = true;
234  break;
235 
236  case TCP_S_FIN_WAIT_1:
237  case TCP_S_FIN_WAIT_2:
238  case TCP_S_CLOSING:
239  case TCP_S_LAST_ACK:
240  case TCP_S_TIME_WAIT:
241  // RFC 793 is not entirely clear on how to handle a duplicate close request.
242  // Here we treat it as an error.
243  throw cRuntimeError(tcpMain, "Duplicate CLOSE command: connection already closing");
244  }
245 }

Referenced by processAppCommand().

◆ process_DESTROY()

void inet::tcp::TcpConnection::process_DESTROY ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
277 {
278  delete tcpCommand;
279  delete msg;
280  // TODO should we send a RST or not?
281 }

Referenced by processAppCommand().

◆ process_OPEN_ACTIVE()

void inet::tcp::TcpConnection::process_OPEN_ACTIVE ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
27 {
28  TcpOpenCommand *openCmd = check_and_cast<TcpOpenCommand *>(tcpCommand);
29  L3Address localAddr, remoteAddr;
30  int localPort, remotePort;
31 
32  switch (fsm.getState()) {
33  case TCP_S_INIT:
34  initConnection(openCmd);
35 
36  // store local/remote socket
37  state->active = true;
38  localAddr = openCmd->getLocalAddr();
39  remoteAddr = openCmd->getRemoteAddr();
40  localPort = openCmd->getLocalPort();
41  remotePort = openCmd->getRemotePort();
42 
43  if (remoteAddr.isUnspecified() || remotePort == -1)
44  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: remote address and port must be specified");
45 
46  if (localPort == -1) {
48  EV_DETAIL << "Assigned ephemeral port " << localPort << "\n";
49  }
50 
51  EV_DETAIL << "OPEN: " << localAddr << ":" << localPort << " --> " << remoteAddr << ":" << remotePort << "\n";
52 
54 
55  // send initial SYN
57  sendSyn();
59  scheduleAfter(TCP_TIMEOUT_CONN_ESTAB, connEstabTimer);
60  break;
61 
62  default:
63  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: connection already exists");
64  }
65 
66  delete openCmd;
67  delete msg;
68 }

Referenced by processAppCommand().

◆ process_OPEN_PASSIVE()

void inet::tcp::TcpConnection::process_OPEN_PASSIVE ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
71 {
72  TcpOpenCommand *openCmd = check_and_cast<TcpOpenCommand *>(tcpCommand);
73  L3Address localAddr;
74  int localPort;
75 
76  switch (fsm.getState()) {
77  case TCP_S_INIT:
78  initConnection(openCmd);
79 
80  // store local/remote socket
81  state->active = false;
82  state->fork = openCmd->getFork();
83  localAddr = openCmd->getLocalAddr();
84  localPort = openCmd->getLocalPort();
85 
86  if (localPort == -1)
87  throw cRuntimeError(tcpMain, "Error processing command OPEN_PASSIVE: local port must be specified");
88 
89  EV_DETAIL << "Starting to listen on: " << localAddr << ":" << localPort << "\n";
90 
91  tcpMain->addSockPair(this, localAddr, L3Address(), localPort, -1);
92  break;
93 
94  default:
95  throw cRuntimeError(tcpMain, "Error processing command OPEN_PASSIVE: connection already exists");
96  }
97 
98  delete openCmd;
99  delete msg;
100 }

Referenced by processAppCommand().

◆ process_OPTIONS()

void inet::tcp::TcpConnection::process_OPTIONS ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
173 {
174  ASSERT(event == TCP_E_SETOPTION);
175 
176  if (auto cmd = dynamic_cast<TcpSetTimeToLiveCommand *>(tcpCommand))
177  ttl = cmd->getTtl();
178  else if (auto cmd = dynamic_cast<TcpSetTosCommand *>(tcpCommand)) {
179  tos = cmd->getTos();
180  }
181  else if (auto cmd = dynamic_cast<TcpSetDscpCommand *>(tcpCommand)) {
182  dscp = cmd->getDscp();
183  }
184  else
185  throw cRuntimeError("Unknown subclass of TcpSetOptionCommand received from app: %s", tcpCommand->getClassName());
186  delete tcpCommand;
187  delete msg;
188 }

Referenced by processAppCommand().

◆ process_QUEUE_BYTES_LIMIT()

void inet::tcp::TcpConnection::process_QUEUE_BYTES_LIMIT ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
321 {
322  if (state == nullptr)
323  throw cRuntimeError("Called process_QUEUE_BYTES_LIMIT on uninitialized TcpConnection!");
324 
325  state->sendQueueLimit = tcpCommand->getUserId(); // Set queue size limit
326  EV << "state->sendQueueLimit set to " << state->sendQueueLimit << "\n";
327  delete msg;
328  delete tcpCommand;
329 }

Referenced by processAppCommand().

◆ process_RCV_SEGMENT()

TcpEventCode inet::tcp::TcpConnection::process_RCV_SEGMENT ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader,
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.

79 {
80  EV_INFO << "Seg arrived: ";
81  printSegmentBrief(tcpSegment, tcpHeader);
82  EV_DETAIL << "TCB: " << state->str() << "\n";
83 
84  emit(rcvSeqSignal, tcpHeader->getSequenceNo());
85  emit(rcvAckSignal, tcpHeader->getAckNo());
86 
87  emit(tcpRcvPayloadBytesSignal, int(tcpSegment->getByteLength() - B(tcpHeader->getHeaderLength()).get()));
88  //
89  // Note: this code is organized exactly as RFC 793, section "3.9 Event
90  // Processing", subsection "SEGMENT ARRIVES".
91  //
92  TcpEventCode event;
93 
94  if (fsm.getState() == TCP_S_LISTEN) {
95  event = processSegmentInListen(tcpSegment, tcpHeader, src, dest);
96  }
97  else if (fsm.getState() == TCP_S_SYN_SENT) {
98  event = processSegmentInSynSent(tcpSegment, tcpHeader, src, dest);
99  }
100  else {
101  // RFC 793 steps "first check sequence number", "second check the RST bit", etc
102  event = processSegment1stThru8th(tcpSegment, tcpHeader);
103  }
104 
105  delete tcpSegment;
106  return event;
107 }

Referenced by processTCPSegment().

◆ process_READ_REQUEST()

void inet::tcp::TcpConnection::process_READ_REQUEST ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
160 {
161  if (isToBeAccepted())
162  throw cRuntimeError("READ without ACCEPT");
163  delete msg;
164  Packet *dataMsg;
165  while ((dataMsg = receiveQueue->extractBytesUpTo(state->rcv_nxt)) != nullptr) {
166  dataMsg->setKind(TCP_I_DATA);
167  dataMsg->addTag<SocketInd>()->setSocketId(socketId);
168  sendToApp(dataMsg);
169  }
170 }

Referenced by processAppCommand().

◆ process_SEND()

void inet::tcp::TcpConnection::process_SEND ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
113 {
114  // FIXME how to support PUSH? One option is to treat each SEND as a unit of data,
115  // and set PSH at SEND boundaries
116  Packet *packet = check_and_cast<Packet *>(msg);
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();
127  scheduleAfter(TCP_TIMEOUT_CONN_ESTAB, connEstabTimer);
128  sendQueue->enqueueAppData(packet); // 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(packet); // 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(packet);
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 }

Referenced by processAppCommand().

◆ process_STATUS()

void inet::tcp::TcpConnection::process_STATUS ( TcpEventCode event,
TcpCommand tcpCommand,
cMessage *  msg 
)
protectedvirtual
284 {
285  delete tcpCommand; // but reuse msg for reply
286 
287  if (fsm.getState() == TCP_S_INIT)
288  throw cRuntimeError("Error processing command STATUS: connection not open");
289 
290  TcpStatusInfo *statusInfo = new TcpStatusInfo();
291 
292  statusInfo->setState(fsm.getState());
293  statusInfo->setStateName(stateName(fsm.getState()));
294 
295  statusInfo->setLocalAddr(localAddr);
296  statusInfo->setRemoteAddr(remoteAddr);
297  statusInfo->setLocalPort(localPort);
298  statusInfo->setRemotePort(remotePort);
299 
300  statusInfo->setSnd_mss(state->snd_mss);
301  statusInfo->setSnd_una(state->snd_una);
302  statusInfo->setSnd_nxt(state->snd_nxt);
303  statusInfo->setSnd_max(state->snd_max);
304  statusInfo->setSnd_wnd(state->snd_wnd);
305  statusInfo->setSnd_up(state->snd_up);
306  statusInfo->setSnd_wl1(state->snd_wl1);
307  statusInfo->setSnd_wl2(state->snd_wl2);
308  statusInfo->setIss(state->iss);
309  statusInfo->setRcv_nxt(state->rcv_nxt);
310  statusInfo->setRcv_wnd(state->rcv_wnd);
311  statusInfo->setRcv_up(state->rcv_up);
312  statusInfo->setIrs(state->irs);
313  statusInfo->setFin_ack_rcvd(state->fin_ack_rcvd);
314 
315  msg->setControlInfo(statusInfo);
316  msg->setKind(TCP_I_STATUS);
317  sendToApp(msg);
318 }

Referenced by processAppCommand().

◆ process_TIMEOUT_2MSL()

void inet::tcp::TcpConnection::process_TIMEOUT_2MSL ( )
protectedvirtual
1296 {
1297  //"
1298  // If the time-wait timeout expires on a connection delete the TCB,
1299  // enter the CLOSED state and return.
1300  //"
1301  switch (fsm.getState()) {
1302  case TCP_S_TIME_WAIT:
1303  // Nothing to do here. The TIMEOUT_2MSL event will automatically take
1304  // the connection to CLOSED. We already notified the user
1305  // (TCP_I_CLOSED) when we entered the TIME_WAIT state from CLOSING,
1306  // FIN_WAIT_1 or FIN_WAIT_2.
1307  break;
1308 
1309  default:
1310  // We should not receive this timeout in this state.
1311  throw cRuntimeError(tcpMain,
1312  "Internal error: received time-wait (2MSL) timeout in state %s",
1313  stateName(fsm.getState()));
1314  }
1315 }

Referenced by processTimer().

◆ process_TIMEOUT_CONN_ESTAB()

void inet::tcp::TcpConnection::process_TIMEOUT_CONN_ESTAB ( )
protectedvirtual
1276 {
1277  switch (fsm.getState()) {
1278  case TCP_S_SYN_RCVD:
1279  case TCP_S_SYN_SENT:
1280  // Nothing to do here. TIMEOUT_CONN_ESTAB event will automatically
1281  // take the connection to LISTEN or CLOSED, and cancel SYN-REXMIT timer.
1282  if (state->active) {
1283  // notify user if we're on the active side
1285  }
1286  break;
1287 
1288  default:
1289  // We should not receive this timeout in this state.
1290  throw cRuntimeError(tcpMain, "Internal error: received CONN_ESTAB timeout in state %s",
1291  stateName(fsm.getState()));
1292  }
1293 }

Referenced by processTimer().

◆ process_TIMEOUT_FIN_WAIT_2()

void inet::tcp::TcpConnection::process_TIMEOUT_FIN_WAIT_2 ( )
protectedvirtual
1318 {
1319  switch (fsm.getState()) {
1320  case TCP_S_FIN_WAIT_2:
1321  // Nothing to do here. The TIMEOUT_FIN_WAIT_2 event will automatically take
1322  // the connection to CLOSED.
1323  break;
1324 
1325  default:
1326  // We should not receive this timeout in this state.
1327  throw cRuntimeError(tcpMain, "Internal error: received FIN_WAIT_2 timeout in state %s",
1328  stateName(fsm.getState()));
1329  }
1330 }

Referenced by processTimer().

◆ process_TIMEOUT_SYN_REXMIT()

void inet::tcp::TcpConnection::process_TIMEOUT_SYN_REXMIT ( TcpEventCode event)
protectedvirtual
1340 {
1342  EV_INFO << "Retransmission count during connection setup exceeds " << MAX_SYN_REXMIT_COUNT << ", giving up\n";
1343  // Note ABORT will take the connection to closed, and cancel CONN-ESTAB timer as well
1344  event = TCP_E_ABORT;
1345  return;
1346  }
1347 
1348  EV_INFO << "Performing retransmission #" << state->syn_rexmit_count << "\n";
1349 
1350  // resend what's needed
1351  switch (fsm.getState()) {
1352  case TCP_S_SYN_SENT:
1353  sendSyn();
1354  break;
1355 
1356  case TCP_S_SYN_RCVD:
1357  sendSynAck();
1358  break;
1359 
1360  default:
1361  throw cRuntimeError(tcpMain, "Internal error: SYN-REXMIT timer expired while in state %s",
1362  stateName(fsm.getState()));
1363  }
1364 
1365  // reschedule timer
1366  state->syn_rexmit_timeout *= 2;
1367 
1370 
1371  scheduleAfter(state->syn_rexmit_timeout, synRexmitTimer);
1372 }

Referenced by processTimer().

◆ processAckInEstabEtc()

bool inet::tcp::TcpConnection::processAckInEstabEtc ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader 
)
protectedvirtual
1128 {
1129  EV_DETAIL << "Processing ACK in a data transfer state\n";
1130 
1131  int payloadLength = tcpSegment->getByteLength() - B(tcpHeader->getHeaderLength()).get();
1132 
1133  // ECN
1134  TcpStateVariables *state = getState();
1135  if (state && state->ect) {
1136  if (tcpHeader->getEceBit() == true)
1137  EV_INFO << "Received packet with ECE\n";
1138 
1139  state->gotEce = tcpHeader->getEceBit();
1140  }
1141 
1142  //
1143  //"
1144  // If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
1145  // Any segments on the retransmission queue which are thereby
1146  // entirely acknowledged are removed. Users should receive
1147  // positive acknowledgments for buffers which have been SENT and
1148  // fully acknowledged (i.e., SEND buffer should be returned with
1149  // "ok" response). If the ACK is a duplicate
1150  // (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks
1151  // something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
1152  // drop the segment, and return.
1153  //
1154  // If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
1155  // updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
1156  // SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
1157  // SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
1158  //
1159  // Note that SND.WND is an offset from SND.UNA, that SND.WL1
1160  // records the sequence number of the last segment used to update
1161  // SND.WND, and that SND.WL2 records the acknowledgment number of
1162  // the last segment used to update SND.WND. The check here
1163  // prevents using old segments to update the window.
1164  //"
1165  // Note: should use SND.MAX instead of SND.NXT in above checks
1166  //
1167  if (seqGE(state->snd_una, tcpHeader->getAckNo())) {
1168  //
1169  // duplicate ACK? A received TCP segment is a duplicate ACK if all of
1170  // the following apply:
1171  // (1) snd_una == ackNo
1172  // (2) segment contains no data
1173  // (3) there's unacked data (snd_una != snd_max)
1174  //
1175  // Note: ssfnet uses additional constraint "window is the same as last
1176  // received (not an update)" -- we don't do that because window updates
1177  // are ignored anyway if neither seqNo nor ackNo has changed.
1178  //
1179  if (state->snd_una == tcpHeader->getAckNo() && payloadLength == 0 && state->snd_una != state->snd_max) {
1180  state->dupacks++;
1181 
1182  emit(dupAcksSignal, state->dupacks);
1183 
1184  // we need to update send window even if the ACK is a dupACK, because rcv win
1185  // could have been changed if faulty data receiver is not respecting the "do not shrink window" rule
1186  updateWndInfo(tcpHeader);
1187 
1189  }
1190  else {
1191  // if doesn't qualify as duplicate ACK, just ignore it.
1192  if (payloadLength == 0) {
1193  if (state->snd_una != tcpHeader->getAckNo())
1194  EV_DETAIL << "Old ACK: ackNo < snd_una\n";
1195  else if (state->snd_una == state->snd_max)
1196  EV_DETAIL << "ACK looks duplicate but we have currently no unacked data (snd_una == snd_max)\n";
1197  }
1198 
1199  // reset counter
1200  state->dupacks = 0;
1201 
1202  emit(dupAcksSignal, state->dupacks);
1203  }
1204  }
1205  else if (seqLE(tcpHeader->getAckNo(), state->snd_max)) {
1206  // ack in window.
1207  uint32_t old_snd_una = state->snd_una;
1208  state->snd_una = tcpHeader->getAckNo();
1209 
1211 
1212  // after retransmitting a lost segment, we may get an ack well ahead of snd_nxt
1213  if (seqLess(state->snd_nxt, state->snd_una))
1214  state->snd_nxt = state->snd_una;
1215 
1216  // RFC 1323, page 36:
1217  // "If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
1218  // Also compute a new estimate of round-trip time. If Snd.TS.OK
1219  // bit is on, use my.TSclock - SEG.TSecr; otherwise use the
1220  // elapsed time since the first segment in the retransmission
1221  // queue was sent. Any segments on the retransmission queue
1222  // which are thereby entirely acknowledged."
1223  if (state->ts_enabled)
1225  // Note: If TS is disabled the RTT measurement is completed in TcpBaseAlg::receivedDataAck()
1226 
1227  uint32_t discardUpToSeq = state->snd_una;
1228 
1229  // our FIN acked?
1230  if (state->send_fin && tcpHeader->getAckNo() == state->snd_fin_seq + 1) {
1231  // set flag that our FIN has been acked
1232  EV_DETAIL << "ACK acks our FIN\n";
1233  state->fin_ack_rcvd = true;
1234  discardUpToSeq--; // the FIN sequence number is not real data
1235  }
1236 
1237  // acked data no longer needed in send queue
1238  sendQueue->discardUpTo(discardUpToSeq);
1239 
1240  // acked data no longer needed in rexmit queue
1241  if (state->sack_enabled)
1242  rexmitQueue->discardUpTo(discardUpToSeq);
1243 
1244  updateWndInfo(tcpHeader);
1245 
1246  // if segment contains data, wait until data has been forwarded to app before sending ACK,
1247  // otherwise we would use an old ACKNo
1248  if (payloadLength == 0 && fsm.getState() != TCP_S_SYN_RCVD) {
1249  // notify
1250  tcpAlgorithm->receivedDataAck(old_snd_una);
1251 
1252  // in the receivedDataAck we need the old value
1253  state->dupacks = 0;
1254 
1255  emit(dupAcksSignal, state->dupacks);
1256  }
1257  }
1258  else {
1259  ASSERT(seqGreater(tcpHeader->getAckNo(), state->snd_max)); // from if-ladder
1260 
1261  // send an ACK, drop the segment, and return.
1262  tcpAlgorithm->receivedAckForDataNotYetSent(tcpHeader->getAckNo());
1263  state->dupacks = 0;
1264 
1265  emit(dupAcksSignal, state->dupacks);
1266 
1267  return false; // means "drop"
1268  }
1269 
1270  return true;
1271 }

Referenced by processSegment1stThru8th().

◆ processAppCommand()

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).

309 {
310  Enter_Method("processAppCommand");
311 
312  take(msg);
313  printConnBrief();
314 
315  // first do actions
316  TcpCommand *tcpCommand = check_and_cast_nullable<TcpCommand *>(msg->removeControlInfo());
317  TcpEventCode event = preanalyseAppCommandEvent(msg->getKind());
318  EV_INFO << "App command: " << eventName(event) << "\n";
319 
320  switch (event) {
321  case TCP_E_OPEN_ACTIVE:
322  process_OPEN_ACTIVE(event, tcpCommand, msg);
323  break;
324 
325  case TCP_E_OPEN_PASSIVE:
326  process_OPEN_PASSIVE(event, tcpCommand, msg);
327  break;
328 
329  case TCP_E_ACCEPT:
330  process_ACCEPT(event, tcpCommand, msg);
331  break;
332 
333  case TCP_E_SEND:
334  process_SEND(event, tcpCommand, msg);
335  break;
336 
337  case TCP_E_CLOSE:
338  process_CLOSE(event, tcpCommand, msg);
339  break;
340 
341  case TCP_E_ABORT:
342  process_ABORT(event, tcpCommand, msg);
343  break;
344 
345  case TCP_E_DESTROY:
346  process_DESTROY(event, tcpCommand, msg);
347  break;
348 
349  case TCP_E_STATUS:
350  process_STATUS(event, tcpCommand, msg);
351  break;
352 
354  process_QUEUE_BYTES_LIMIT(event, tcpCommand, msg);
355  break;
356 
357  case TCP_E_READ:
358  process_READ_REQUEST(event, tcpCommand, msg);
359  break;
360 
361  case TCP_E_SETOPTION:
362  process_OPTIONS(event, tcpCommand, msg);
363  break;
364 
365  default:
366  throw cRuntimeError(tcpMain, "wrong event code");
367  }
368 
369  // then state transitions
370  return performStateTransition(event);
371 }

Referenced by inet::tcp::Tcp::handleUpperCommand().

◆ processMSSOption()

bool inet::tcp::TcpConnection::processMSSOption ( const Ptr< const TcpHeader > &  tcpHeader,
const TcpOptionMaxSegmentSize option 
)
protectedvirtual
1115 {
1116  if (option.getLength() != 4) {
1117  EV_ERROR << "ERROR: MSS option length incorrect\n";
1118  return false;
1119  }
1120 
1121  if (fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) {
1122  EV_ERROR << "ERROR: Tcp Header Option MSS received, but in unexpected state\n";
1123  return false;
1124  }
1125 
1126  // RFC 2581, page 1:
1127  // "The SMSS is the size of the largest segment that the sender can transmit.
1128  // This value can be based on the maximum transmission unit of the network,
1129  // the path MTU discovery [MD90] algorithm, RMSS (see next item), or other
1130  // factors. The size does not include the TCP/IP headers and options."
1131  //
1132  // "The RMSS is the size of the largest segment the receiver is willing to accept.
1133  // This is the value specified in the MSS option sent by the receiver during
1134  // connection startup. Or, if the MSS option is not used, 536 bytes [Bra89].
1135  // The size does not include the TCP/IP headers and options."
1136  //
1137  //
1138  // The value of snd_mss (SMSS) is set to the minimum of snd_mss (local parameter) and
1139  // the value specified in the MSS option received during connection startup.
1140  state->snd_mss = std::min(state->snd_mss, (uint32_t)option.getMaxSegmentSize());
1141 
1142  if (state->snd_mss == 0)
1143  state->snd_mss = 536;
1144 
1145  EV_INFO << "Tcp Header Option MSS(=" << option.getMaxSegmentSize() << ") received, SMSS is set to " << state->snd_mss << "\n";
1146  return true;
1147 }

Referenced by readHeaderOptions().

◆ processRstInSynReceived()

TcpEventCode inet::tcp::TcpConnection::processRstInSynReceived ( const Ptr< const TcpHeader > &  tcpHeader)
protectedvirtual
1097 {
1098  EV_DETAIL << "Processing RST in SYN_RCVD\n";
1099 
1100  //"
1101  // If this connection was initiated with a passive OPEN (i.e.,
1102  // came from the LISTEN state), then return this connection to
1103  // LISTEN state and return. The user need not be informed. If
1104  // this connection was initiated with an active OPEN (i.e., came
1105  // from SYN-SENT state) then the connection was refused, signal
1106  // the user "connection refused". In either case, all segments
1107  // on the retransmission queue should be removed. And in the
1108  // active OPEN case, enter the CLOSED state and delete the TCB,
1109  // and return.
1110  //"
1111 
1112  sendQueue->discardUpTo(sendQueue->getBufferEndSeq()); // flush send queue
1113 
1114  if (state->sack_enabled)
1115  rexmitQueue->discardUpTo(rexmitQueue->getBufferEndSeq()); // flush rexmit queue
1116 
1117  if (state->active) {
1118  // signal "connection refused"
1120  }
1121 
1122  // on RCV_RST, FSM will go either to LISTEN or to CLOSED, depending on state->active
1123  // 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!)
1124  return TCP_E_RCV_RST;
1125 }

Referenced by processSegment1stThru8th().

◆ processSACKOption()

bool inet::tcp::TcpConnection::processSACKOption ( const Ptr< const TcpHeader > &  tcpHeader,
const TcpOptionSack option 
)
protectedvirtual
30 {
31  if (option.getLength() % 8 != 2) {
32  EV_ERROR << "ERROR: option length incorrect\n";
33  return false;
34  }
35 
36  uint n = option.getSackItemArraySize();
37  ASSERT(option.getLength() == 2 + n * 8);
38 
39  if (!state->sack_enabled) {
40  EV_ERROR << "ERROR: " << n << " SACK(s) received, but sack_enabled is set to false\n";
41  return false;
42  }
43 
44  if (fsm.getState() != TCP_S_SYN_RCVD && fsm.getState() != TCP_S_ESTABLISHED
45  && fsm.getState() != TCP_S_FIN_WAIT_1 && fsm.getState() != TCP_S_FIN_WAIT_2)
46  {
47  EV_ERROR << "ERROR: Tcp Header Option SACK received, but in unexpected state\n";
48  return false;
49  }
50 
51  if (n > 0) { // sacks present?
52  EV_INFO << n << " SACK(s) received:\n";
53  for (uint i = 0; i < n; i++) {
54  Sack tmp;
55  tmp.setStart(option.getSackItem(i).getStart());
56  tmp.setEnd(option.getSackItem(i).getEnd());
57 
58  EV_INFO << (i + 1) << ". SACK: " << tmp.str() << endl;
59 
60  // check for D-SACK
61  if (i == 0 && seqLE(tmp.getEnd(), tcpHeader->getAckNo())) {
62  // RFC 2883, page 8:
63  // "In order for the sender to check that the first (D)SACK block of an
64  // acknowledgement in fact acknowledges duplicate data, the sender
65  // should compare the sequence space in the first SACK block to the
66  // cumulative ACK which is carried IN THE SAME PACKET. If the SACK
67  // sequence space is less than this cumulative ACK, it is an indication
68  // that the segment identified by the SACK block has been received more
69  // than once by the receiver. An implementation MUST NOT compare the
70  // sequence space in the SACK block to the TCP state variable snd.una
71  // (which carries the total cumulative ACK), as this may result in the
72  // wrong conclusion if ACK packets are reordered."
73  EV_DETAIL << "Received D-SACK below cumulative ACK=" << tcpHeader->getAckNo()
74  << " D-SACK: " << tmp.str() << endl;
75  // Note: RFC 2883 does not specify what should be done in this case.
76  // RFC 2883, page 9:
77  // "5. Detection of Duplicate Packets
78  // (...) This document does not specify what action a TCP implementation should
79  // take in these cases. The extension to the SACK option simply enables
80  // the sender to detect each of these cases.(...)"
81  }
82  else if (i == 0 && n > 1 && seqGreater(tmp.getEnd(), tcpHeader->getAckNo())) {
83  // RFC 2883, page 8:
84  // "If the sequence space in the first SACK block is greater than the
85  // cumulative ACK, then the sender next compares the sequence space in
86  // the first SACK block with the sequence space in the second SACK
87  // block, if there is one. This comparison can determine if the first
88  // SACK block is reporting duplicate data that lies above the cumulative
89  // ACK."
90  Sack tmp2(option.getSackItem(1).getStart(), option.getSackItem(1).getEnd());
91 
92  if (tmp2.contains(tmp)) {
93  EV_DETAIL << "Received D-SACK above cumulative ACK=" << tcpHeader->getAckNo()
94  << " D-SACK: " << tmp.str()
95  << ", SACK: " << tmp2.str() << endl;
96  // Note: RFC 2883 does not specify what should be done in this case.
97  // RFC 2883, page 9:
98  // "5. Detection of Duplicate Packets
99  // (...) This document does not specify what action a TCP implementation should
100  // take in these cases. The extension to the SACK option simply enables
101  // the sender to detect each of these cases.(...)"
102  }
103  }
104 
105  if (seqGreater(tmp.getEnd(), tcpHeader->getAckNo()) && seqGreater(tmp.getEnd(), state->snd_una))
106  rexmitQueue->setSackedBit(tmp.getStart(), tmp.getEnd());
107  else
108  EV_DETAIL << "Received SACK below total cumulative ACK snd_una=" << state->snd_una << "\n";
109  }
110  state->rcv_sacks += n; // total counter, no current number
111 
113 
114  // update scoreboard
115  state->sackedBytes_old = state->sackedBytes; // needed for RFC 3042 to check if last dupAck contained new sack information
117 
119  }
120  return true;
121 }

Referenced by readHeaderOptions().

◆ processSACKPermittedOption()

bool inet::tcp::TcpConnection::processSACKPermittedOption ( const Ptr< const TcpHeader > &  tcpHeader,
const TcpOptionSackPermitted option 
)
protectedvirtual
1223 {
1224  if (option.getLength() != 2) {
1225  EV_ERROR << "ERROR: length incorrect\n";
1226  return false;
1227  }
1228 
1229  if (fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) {
1230  EV_ERROR << "ERROR: Tcp Header Option SACK_PERMITTED received, but in unexpected state\n";
1231  return false;
1232  }
1233 
1234  state->rcv_sack_perm = true;
1236  EV_INFO << "Tcp Header Option SACK_PERMITTED received, SACK (sack_enabled) is set to " << state->sack_enabled << "\n";
1237  return true;
1238 }

Referenced by readHeaderOptions().

◆ processSegment1stThru8th()

TcpEventCode inet::tcp::TcpConnection::processSegment1stThru8th ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader 
)
protectedvirtual
126 {
127 
128  // Delegates additional processing of ECN to the algorithm
130 
131  //
132  // RFC 793: first check sequence number
133  //
134 
135  bool acceptable = true;
136 
137  if (tcpHeader->getHeaderLength() > TCP_MIN_HEADER_LENGTH) { // Header options present? TCP_HEADER_OCTETS = 20
138  // PAWS
139  if (state->ts_enabled) {
140  uint32_t tsval = getTSval(tcpHeader);
141  if (tsval != 0 && seqLess(tsval, state->ts_recent) &&
142  (simTime() - state->time_last_data_sent) > PAWS_IDLE_TIME_THRESH) // PAWS_IDLE_TIME_THRESH = 24 days
143  {
144  EV_DETAIL << "PAWS: Segment is not acceptable, TSval=" << tsval << " in "
145  << stateName(fsm.getState()) << " state received: dropping segment\n";
146  acceptable = false;
147  }
148  }
149 
150  readHeaderOptions(tcpHeader);
151  }
152 
153  if (acceptable)
154  acceptable = isSegmentAcceptable(tcpSegment, tcpHeader);
155 
156  int payloadLength = tcpSegment->getByteLength() - B(tcpHeader->getHeaderLength()).get();
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 (tcpHeader->getRstBit()) {
167  EV_DETAIL << "RST with unacceptable seqNum: dropping\n";
168  }
169  else {
170  if (tcpHeader->getSynBit()) {
171  EV_DETAIL << "SYN with unacceptable seqNum in " << stateName(fsm.getState()) << " state received (SYN duplicat?)\n";
172  }
173  else if (payloadLength > 0 && state->sack_enabled && seqLess((tcpHeader->getSequenceNo() + payloadLength), state->rcv_nxt)) {
174  state->start_seqno = tcpHeader->getSequenceNo();
175  state->end_seqno = tcpHeader->getSequenceNo() + payloadLength;
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 
193 
194  return TCP_E_IGNORE;
195  }
196 
197  // ECN
198  if (tcpHeader->getCwrBit() == true) {
199  EV_INFO << "Received CWR... Leaving ecnEcho State\n";
200  state->ecnEchoState = false;
201  }
202 
203  //
204  // RFC 793: second check the RST bit,
205  //
206  if (tcpHeader->getRstBit()) {
207  // Note: if we come from LISTEN, processSegmentInListen() has already handled RST.
208  switch (fsm.getState()) {
209  case TCP_S_SYN_RCVD:
210  //"
211  // If this connection was initiated with a passive OPEN (i.e.,
212  // came from the LISTEN state), then return this connection to
213  // LISTEN state and return. The user need not be informed. If
214  // this connection was initiated with an active OPEN (i.e., came
215  // from SYN-SENT state) then the connection was refused, signal
216  // the user "connection refused". In either case, all segments
217  // on the retransmission queue should be removed. And in the
218  // active OPEN case, enter the CLOSED state and delete the TCB,
219  // and return.
220  //"
221  return processRstInSynReceived(tcpHeader);
222 
223  case TCP_S_ESTABLISHED:
224  case TCP_S_FIN_WAIT_1:
225  case TCP_S_FIN_WAIT_2:
226  case TCP_S_CLOSE_WAIT:
227  //"
228  // If the RST bit is set then, any outstanding RECEIVEs and SEND
229  // should receive "reset" responses. All segment queues should be
230  // flushed. Users should also receive an unsolicited general
231  // "connection reset" signal.
232  //
233  // Enter the CLOSED state, delete the TCB, and return.
234  //"
235  EV_DETAIL << "RST: performing connection reset, closing connection\n";
237  return TCP_E_RCV_RST; // this will trigger state transition
238 
239  case TCP_S_CLOSING:
240  case TCP_S_LAST_ACK:
241  case TCP_S_TIME_WAIT:
242  //"
243  // enter the CLOSED state, delete the TCB, and return.
244  //"
245  EV_DETAIL << "RST: closing connection\n";
246  return TCP_E_RCV_RST; // this will trigger state transition
247 
248  default:
249  ASSERT(0);
250  break;
251  }
252  }
253 
254  // RFC 793: third check security and precedence
255  // This step is ignored.
256 
257  //
258  // RFC 793: fourth, check the SYN bit,
259  //
260  if (tcpHeader->getSynBit()
261  && !(fsm.getState() == TCP_S_SYN_RCVD && tcpHeader->getAckBit())) {
262  //"
263  // If the SYN is in the window it is an error, send a reset, any
264  // outstanding RECEIVEs and SEND should receive "reset" responses,
265  // all segment queues should be flushed, the user should also
266  // receive an unsolicited general "connection reset" signal, enter
267  // the CLOSED state, delete the TCB, and return.
268  //
269  // If the SYN is not in the window this step would not be reached
270  // and an ack would have been sent in the first step (sequence
271  // number check).
272  //"
273  // Zoltan Bojthe: but accept SYN+ACK in SYN_RCVD state for simultaneous open
274 
275  ASSERT(isSegmentAcceptable(tcpSegment, tcpHeader)); // assert SYN is in the window
276  EV_DETAIL << "SYN is in the window: performing connection reset, closing connection\n";
278  return TCP_E_RCV_UNEXP_SYN;
279  }
280 
281  //
282  // RFC 793: fifth check the ACK field,
283  //
284  if (!tcpHeader->getAckBit()) {
285  // if the ACK bit is off drop the segment and return
286  EV_INFO << "ACK not set, dropping segment\n";
287  return TCP_E_IGNORE;
288  }
289 
290  uint32_t old_snd_una = state->snd_una;
291 
292  TcpEventCode event = TCP_E_IGNORE;
293 
294  if (fsm.getState() == TCP_S_SYN_RCVD) {
295  //"
296  // If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state
297  // and continue processing.
298  //
299  // If the segment acknowledgment is not acceptable, form a
300  // reset segment,
301  //
302  // <SEQ=SEG.ACK><CTL=RST>
303  //
304  // and send it.
305  //"
306  if (!seqLE(state->snd_una, tcpHeader->getAckNo()) || !seqLE(tcpHeader->getAckNo(), state->snd_nxt)) {
307  sendRst(tcpHeader->getAckNo());
308  return TCP_E_IGNORE;
309  }
310 
311  // notify tcpAlgorithm and app layer
312  tcpAlgorithm->established(false);
313 
314  if (isToBeAccepted())
316  else
318 
319  // This will trigger transition to ESTABLISHED. Timers and notifying
320  // app will be taken care of in stateEntered().
321  event = TCP_E_RCV_ACK;
322  }
323 
324  uint32_t old_snd_nxt = state->snd_nxt; // later we'll need to see if snd_nxt changed
325  // Note: If one of the last data segments is lost while already in LAST-ACK state (e.g. if using TCPEchoApps)
326  // TCP must be able to process acceptable acknowledgments, however please note RFC 793, page 73:
327  // "LAST-ACK STATE
328  // The only thing that can arrive in this state is an
329  // acknowledgment of our FIN. If our FIN is now acknowledged,
330  // delete the TCB, enter the CLOSED state, and return."
331  if (fsm.getState() == TCP_S_SYN_RCVD || fsm.getState() == TCP_S_ESTABLISHED ||
332  fsm.getState() == TCP_S_FIN_WAIT_1 || fsm.getState() == TCP_S_FIN_WAIT_2 ||
333  fsm.getState() == TCP_S_CLOSE_WAIT || fsm.getState() == TCP_S_CLOSING ||
334  fsm.getState() == TCP_S_LAST_ACK)
335  {
336  //
337  // ESTABLISHED processing:
338  //"
339  // If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
340  // Any segments on the retransmission queue which are thereby
341  // entirely acknowledged are removed. Users should receive
342  // positive acknowledgments for buffers which have been SENT and
343  // fully acknowledged (i.e., SEND buffer should be returned with
344  // "ok" response). If the ACK is a duplicate
345  // (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks
346  // something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
347  // drop the segment, and return.
348  //
349  // If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
350  // updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
351  // SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
352  // SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
353  //
354  // Note that SND.WND is an offset from SND.UNA, that SND.WL1
355  // records the sequence number of the last segment used to update
356  // SND.WND, and that SND.WL2 records the acknowledgment number of
357  // the last segment used to update SND.WND. The check here
358  // prevents using old segments to update the window.
359  //"
360  bool ok = processAckInEstabEtc(tcpSegment, tcpHeader);
361 
362  if (!ok)
363  return TCP_E_IGNORE; // if acks something not yet sent, drop it
364  }
365 
366  if ((fsm.getState() == TCP_S_FIN_WAIT_1 && state->fin_ack_rcvd)) {
367  //"
368  // FIN-WAIT-1 STATE
369  // In addition to the processing for the ESTABLISHED state, if
370  // our FIN is now acknowledged then enter FIN-WAIT-2 and continue
371  // processing in that state.
372  //"
373  event = TCP_E_RCV_ACK; // will trigger transition to FIN-WAIT-2
374  }
375 
376  if (fsm.getState() == TCP_S_FIN_WAIT_2) {
377  //"
378  // FIN-WAIT-2 STATE
379  // In addition to the processing for the ESTABLISHED state, if
380  // the retransmission queue is empty, the user's CLOSE can be
381  // acknowledged ("ok") but do not delete the TCB.
382  //"
383  // nothing to do here (in our model, used commands don't need to be
384  // acknowledged)
385  }
386 
387  if (fsm.getState() == TCP_S_CLOSING) {
388  //"
389  // In addition to the processing for the ESTABLISHED state, if
390  // the ACK acknowledges our FIN then enter the TIME-WAIT state,
391  // otherwise ignore the segment.
392  //"
393  if (state->fin_ack_rcvd) {
394  EV_INFO << "Our FIN acked -- can go to TIME_WAIT now\n";
395  event = TCP_E_RCV_ACK; // will trigger transition to TIME-WAIT
396  scheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer); // start timer
397 
398  // we're entering TIME_WAIT, so we can signal CLOSED the user
399  // (the only thing left to do is wait until the 2MSL timer expires)
400  }
401  }
402 
403  if (fsm.getState() == TCP_S_LAST_ACK) {
404  //"
405  // The only thing that can arrive in this state is an
406  // acknowledgment of our FIN. If our FIN is now acknowledged,
407  // delete the TCB, enter the CLOSED state, and return.
408  //"
409  if (state->send_fin && tcpHeader->getAckNo() == state->snd_fin_seq + 1) {
410  EV_INFO << "Last ACK arrived\n";
411  return TCP_E_RCV_ACK; // will trigger transition to CLOSED
412  }
413  }
414 
415  if (fsm.getState() == TCP_S_TIME_WAIT) {
416  //"
417  // The only thing that can arrive in this state is a
418  // retransmission of the remote FIN. Acknowledge it, and restart
419  // the 2 MSL timeout.
420  //"
421  // And we are staying in the TIME_WAIT state.
422  //
423  sendAck();
424  rescheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer);
425  }
426 
427  //
428  // RFC 793: sixth, check the URG bit,
429  //
430  if (tcpHeader->getUrgBit() && (fsm.getState() == TCP_S_ESTABLISHED ||
431  fsm.getState() == TCP_S_FIN_WAIT_1 || fsm.getState() == TCP_S_FIN_WAIT_2))
432  {
433  //"
434  // If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal
435  // the user that the remote side has urgent data if the urgent
436  // pointer (RCV.UP) is in advance of the data consumed. If the
437  // user has already been signaled (or is still in the "urgent
438  // mode") for this continuous sequence of urgent data, do not
439  // signal the user again.
440  //"
441 
442  // TODO URG currently not supported
443  }
444 
445  //
446  // RFC 793: seventh, process the segment text,
447  //
448  uint32_t old_rcv_nxt = state->rcv_nxt; // if rcv_nxt changes, we need to send/schedule an ACK
449 
450  if (fsm.getState() == TCP_S_SYN_RCVD || fsm.getState() == TCP_S_ESTABLISHED ||
451  fsm.getState() == TCP_S_FIN_WAIT_1 || fsm.getState() == TCP_S_FIN_WAIT_2)
452  {
453  //"
454  // Once in the ESTABLISHED state, it is possible to deliver segment
455  // text to user RECEIVE buffers. Text from segments can be moved
456  // into buffers until either the buffer is full or the segment is
457  // empty. If the segment empties and carries an PUSH flag, then
458  // the user is informed, when the buffer is returned, that a PUSH
459  // has been received.
460  //
461  // When the TCP takes responsibility for delivering the data to the
462  // user it must also acknowledge the receipt of the data.
463  //
464  // Once the TCP takes responsibility for the data it advances
465  // RCV.NXT over the data accepted, and adjusts RCV.WND as
466  // appropriate to the current buffer availability. The total of
467  // RCV.NXT and RCV.WND should not be reduced.
468  //
469  // Please note the window management suggestions in section 3.7.
470  //
471  // Send an acknowledgment of the form:
472  //
473  // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
474  //
475  // This acknowledgment should be piggybacked on a segment being
476  // transmitted if possible without incurring undue delay.
477  //"
478 
479  if (payloadLength > 0) {
480  // check for full sized segment
481  if ((uint32_t)payloadLength == state->snd_mss || (uint32_t)payloadLength + B(tcpHeader->getHeaderLength() - TCP_MIN_HEADER_LENGTH).get() == state->snd_mss)
483 
484  // check for persist probe
485  if (payloadLength == 1)
486  state->ack_now = true; // TODO how to check if it is really a persist probe?
487 
489 
490  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpSegment, tcpHeader)) { // enough freeRcvBuffer in rcvQueue for new segment?
491  EV_DETAIL << "Processing segment text in a data transfer state\n";
492 
493  // insert into receive buffers. If this segment is contiguous with
494  // previously received ones (seqNo == rcv_nxt), rcv_nxt can be increased;
495  // otherwise it stays the same but the data must be cached nevertheless
496  // (to avoid "Failure to retain above-sequence data" problem, RFC 2525
497  // section 2.5).
498 
499  uint32_t old_usedRcvBuffer = state->usedRcvBuffer;
500  state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpSegment, tcpHeader);
501 
502  if (seqGreater(state->snd_una, old_snd_una)) {
503  // notify
504  tcpAlgorithm->receivedDataAck(old_snd_una);
505 
506  // in the receivedDataAck we need the old value
507  state->dupacks = 0;
508 
509  emit(dupAcksSignal, state->dupacks);
510  }
511 
512  // out-of-order segment?
513  if (old_rcv_nxt == state->rcv_nxt) {
514  state->rcv_oooseg++;
515 
517 
518  // RFC 2018, page 4:
519  // "The receiver SHOULD send an ACK for every valid segment that arrives
520  // containing new data, and each of these "duplicate" ACKs SHOULD bear a
521  // SACK option."
522  if (state->sack_enabled) {
523  // store start and end sequence numbers of current oooseg in state variables
524  state->start_seqno = tcpHeader->getSequenceNo();
525  state->end_seqno = tcpHeader->getSequenceNo() + payloadLength;
526 
527  if (old_usedRcvBuffer == receiveQueue->getAmountOfBufferedBytes()) { // D-SACK
528  state->snd_dsack = true;
529  EV_DETAIL << "SND_D-SACK SET (old_rcv_nxt == rcv_nxt duplicated oooseg rcvd)\n";
530  }
531  else { // SACK
532  state->snd_sack = true;
533  EV_DETAIL << "SND_SACK SET (old_rcv_nxt == rcv_nxt oooseg rcvd)\n";
534  }
535  }
536 
538  }
539  else {
540  // forward data to app
541  //
542  // FIXME observe PSH bit
543  //
544  // FIXME we should implement socket READ command, and pass up only
545  // as many bytes as requested. rcv_wnd should be decreased
546  // accordingly!
547  //
548  if (!isToBeAccepted())
550 
551  // if this segment "filled the gap" until the previously arrived segment
552  // that carried a FIN (i.e.rcv_nxt == rcv_fin_seq), we have to advance
553  // rcv_nxt over the FIN.
554  if (state->fin_rcvd && state->rcv_nxt == state->rcv_fin_seq) {
555  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
556  EV_DETAIL << "All segments arrived up to the FIN segment, advancing rcv_nxt over the FIN\n";
557  state->rcv_nxt = state->rcv_fin_seq + 1;
558  // state transitions will be done in the state machine, here we just set
559  // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
560  event = TCP_E_RCV_FIN;
561 
562  switch (fsm.getState()) {
563  case TCP_S_FIN_WAIT_1:
564  if (state->fin_ack_rcvd) {
565  event = TCP_E_RCV_FIN_ACK;
566  // start the time-wait timer, turn off the other timers
567  cancelEvent(finWait2Timer);
568  scheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer);
569 
570  // we're entering TIME_WAIT, so we can signal CLOSED the user
571  // (the only thing left to do is wait until the 2MSL timer expires)
572  }
573  break;
574 
575  case TCP_S_FIN_WAIT_2:
576  // Start the time-wait timer, turn off the other timers.
577  cancelEvent(finWait2Timer);
578  scheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer);
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  break;
583 
584  case TCP_S_TIME_WAIT:
585  // Restart the 2 MSL time-wait timeout.
586  rescheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer);
587  break;
588 
589  default:
590  break;
591  }
592  }
593  }
594  }
595  else { // not enough freeRcvBuffer in rcvQueue for new segment
596  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
597 
599 
600  // if the ACK bit is off drop the segment and return
601  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
602  return TCP_E_IGNORE;
603  }
604  }
605  }
606 
607  //
608  // RFC 793: eighth, check the FIN bit,
609  //
610  if (tcpHeader->getFinBit()) {
611  state->ack_now = true;
612 
613  //"
614  // If the FIN bit is set, signal the user "connection closing" and
615  // return any pending RECEIVEs with same message, advance RCV.NXT
616  // over the FIN, and send an acknowledgment for the FIN. Note that
617  // FIN implies PUSH for any segment text not yet delivered to the
618  // user.
619  //"
620 
621  // Note: seems like RFC 793 is not entirely correct here: if the
622  // segment is "above sequence" (ie. RCV.NXT < SEG.SEQ), we cannot
623  // advance RCV.NXT over the FIN. Instead we remember this sequence
624  // number and do it later.
625  uint32_t fin_seq = (uint32_t)tcpHeader->getSequenceNo() + (uint32_t)payloadLength;
626 
627  if (state->rcv_nxt == fin_seq) {
628  // advance rcv_nxt over FIN now
629  EV_INFO << "FIN arrived, advancing rcv_nxt over the FIN\n";
630  state->rcv_nxt++;
631  // state transitions will be done in the state machine, here we just set
632  // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
633  event = TCP_E_RCV_FIN;
634 
635  switch (fsm.getState()) {
636  case TCP_S_FIN_WAIT_1:
637  if (state->fin_ack_rcvd) {
638  event = TCP_E_RCV_FIN_ACK;
639  // start the time-wait timer, turn off the other timers
640  cancelEvent(finWait2Timer);
641  scheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer);
642 
643  // we're entering TIME_WAIT, so we can signal CLOSED the user
644  // (the only thing left to do is wait until the 2MSL timer expires)
645  }
646  break;
647 
648  case TCP_S_FIN_WAIT_2:
649  // Start the time-wait timer, turn off the other timers.
650  cancelEvent(finWait2Timer);
651  scheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer);
652 
653  // we're entering TIME_WAIT, so we can signal CLOSED the user
654  // (the only thing left to do is wait until the 2MSL timer expires)
655  break;
656 
657  case TCP_S_TIME_WAIT:
658  // Restart the 2 MSL time-wait timeout.
659  rescheduleAfter(2 * tcpMain->getMsl(), the2MSLTimer);
660  break;
661 
662  default:
663  break;
664  }
665  }
666  else {
667  // we'll have to do it later (when an arriving segment "fills the gap")
668  EV_DETAIL << "FIN segment above sequence, storing sequence number of FIN\n";
669  state->fin_rcvd = true;
670  state->rcv_fin_seq = fin_seq;
671  }
672 
673  // TODO do PUSH stuff
674  }
675 
676  if (old_rcv_nxt != state->rcv_nxt) {
677  // if rcv_nxt changed, either because we received segment text or we
678  // received a FIN that needs to be acked (or both), we need to send or
679  // schedule an ACK.
680  if (state->sack_enabled) {
681  if (receiveQueue->getQueueLength() != 0) {
682  // RFC 2018, page 4:
683  // "If sent at all, SACK options SHOULD be included in all ACKs which do
684  // not ACK the highest sequence number in the data receiver's queue."
685  state->start_seqno = tcpHeader->getSequenceNo();
686  state->end_seqno = tcpHeader->getSequenceNo() + payloadLength;
687  state->snd_sack = true;
688  EV_DETAIL << "SND_SACK SET (rcv_nxt changed, but receiveQ is not empty)\n";
689  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
690  }
691  }
692 
693  // tcpAlgorithm decides when and how to do ACKs
695  }
696 
697  if ((fsm.getState() == TCP_S_ESTABLISHED || fsm.getState() == TCP_S_SYN_RCVD) &&
699  {
700  // if the user issued the CLOSE command a long time ago and we've just
701  // managed to send off FIN, we simulate a CLOSE command now (we had to
702  // defer it at that time because we still had data in the send queue.)
703  // This CLOSE will take us into the FIN_WAIT_1 state.
704  EV_DETAIL << "Now we can do the CLOSE which was deferred a while ago\n";
705  event = TCP_E_CLOSE;
706  }
707 
708  if (fsm.getState() == TCP_S_CLOSE_WAIT && state->send_fin &&
709  state->snd_nxt == state->snd_fin_seq + 1 && old_snd_nxt != state->snd_nxt)
710  {
711  // if we're in CLOSE_WAIT and we just got to sent our long-pending FIN,
712  // we simulate a CLOSE command now (we had to defer it at that time because
713  // we still had data in the send queue.) This CLOSE will take us into the
714  // LAST_ACK state.
715  EV_DETAIL << "Now we can do the CLOSE which was deferred a while ago\n";
716  event = TCP_E_CLOSE;
717  }
718 
719  return event;
720 }

Referenced by process_RCV_SEGMENT().

◆ processSegmentInListen()

TcpEventCode inet::tcp::TcpConnection::processSegmentInListen ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader,
L3Address  src,
L3Address  dest 
)
protectedvirtual
725 {
726  EV_DETAIL << "Processing segment in LISTEN\n";
727 
728  //"
729  // first check for an RST
730  // An incoming RST should be ignored. Return.
731  //"
732  if (tcpHeader->getRstBit()) {
733  EV_INFO << "RST bit set: dropping segment\n";
734  return TCP_E_IGNORE;
735  }
736 
737  //"
738  // second check for an ACK
739  // Any acknowledgment is bad if it arrives on a connection still in
740  // the LISTEN state. An acceptable reset segment should be formed
741  // for any arriving ACK-bearing segment. The RST should be
742  // formatted as follows:
743  //
744  // <SEQ=SEG.ACK><CTL=RST>
745  //
746  // Return.
747  //"
748  if (tcpHeader->getAckBit()) {
749  EV_INFO << "ACK bit set: dropping segment and sending RST\n";
750  sendRst(tcpHeader->getAckNo(), destAddr, srcAddr, tcpHeader->getDestPort(), tcpHeader->getSrcPort());
751  return TCP_E_IGNORE;
752  }
753 
754  //"
755  // third check for a SYN
756  //"
757  if (tcpHeader->getSynBit()) {
758  if (tcpHeader->getFinBit()) {
759  // Looks like implementations vary on how to react to SYN+FIN.
760  // Some treat it as plain SYN (and reply with SYN+ACK), some send RST+ACK.
761  // Let's just do the former here.
762  EV_INFO << "SYN+FIN received: ignoring FIN\n";
763  }
764 
765  EV_DETAIL << "SYN bit set: filling in foreign socket and sending SYN+ACK\n";
766 
767  //"
768  // If the listen was not fully specified (i.e., the foreign socket was not
769  // fully specified), then the unspecified fields should be filled in now.
770  //"
771  //
772  // Also, we may need to fork, in order to leave another connection
773  // LISTENing on the port. Note: forking will change our socketId.
774  //
775  if (state->fork) {
776  TcpConnection *conn = cloneListeningConnection(); // "conn" is the clone which will handle the new connection, while "this" stay LISTENing
777  tcpMain->addForkedConnection(this, conn, destAddr, srcAddr, tcpHeader->getDestPort(), tcpHeader->getSrcPort());
778  EV_DETAIL << "Connection forked: new connection got new socketId=" << conn->socketId << ", "
779  "old connection keeps LISTENing with socketId=" << socketId << "\n";
780  TcpEventCode forkEvent = conn->processSynInListen(tcpSegment, tcpHeader, srcAddr, destAddr);
781  conn->performStateTransition(forkEvent);
782 
783  return TCP_E_IGNORE;
784  }
785  else {
786  tcpMain->updateSockPair(this, destAddr, srcAddr, tcpHeader->getDestPort(), tcpHeader->getSrcPort());
787  return processSynInListen(tcpSegment, tcpHeader, srcAddr, destAddr);
788  }
789  }
790 
791  //"
792  // fourth other text or control
793  // So you are unlikely to get here, but if you do, drop the segment, and return.
794  //"
795  EV_WARN << "Unexpected segment: dropping it\n";
796  return TCP_E_IGNORE;
797 }

Referenced by process_RCV_SEGMENT().

◆ processSegmentInSynSent()

TcpEventCode inet::tcp::TcpConnection::processSegmentInSynSent ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader,
L3Address  src,
L3Address  dest 
)
protectedvirtual
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 (tcpHeader->getAckBit()) {
891  if (seqLE(tcpHeader->getAckNo(), state->iss) || seqGreater(tcpHeader->getAckNo(), state->snd_nxt)) {
892  if (tcpHeader->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(tcpHeader->getAckNo(), destAddr, srcAddr, tcpHeader->getDestPort(), tcpHeader->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 (tcpHeader->getRstBit()) {
915  if (tcpHeader->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 (tcpHeader->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 = tcpHeader->getSequenceNo() + 1;
948 
949  emit(rcvAdvSignal, state->rcv_adv);
950 
951  state->irs = tcpHeader->getSequenceNo();
953 
954  if (tcpHeader->getAckBit()) {
955  state->snd_una = tcpHeader->getAckNo();
957 
958  if (state->sack_enabled)
960 
961  // although not mentioned in RFC 793, seems like we have to pick up
962  // initial snd_wnd from the segment here.
963  updateWndInfo(tcpHeader, true);
964  }
965 
966  // this also seems to be a good time to learn our local IP address
967  // (was probably unspecified at connection open)
968  tcpMain->updateSockPair(this, destAddr, srcAddr, tcpHeader->getDestPort(), tcpHeader->getSrcPort());
969 
970  //"
971  // If SND.UNA > ISS (our SYN has been ACKed), change the connection
972  // state to ESTABLISHED, form an ACK segment
973  //
974  // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
975  //
976  // and send it. Data or controls which were queued for
977  // transmission may be included. If there are other controls or
978  // text in the segment then continue processing at the sixth step
979  // below where the URG bit is checked, otherwise return.
980  //"
981  if (seqGreater(state->snd_una, state->iss)) {
982  EV_INFO << "SYN+ACK bits set, connection established.\n";
983 
984  // RFC says "continue processing at the sixth step below where
985  // the URG bit is checked". Those steps deal with: URG, segment text
986  // (and PSH), and FIN.
987  // Now: URG and PSH we don't support yet; in SYN+FIN we ignore FIN;
988  // with segment text we just take it easy and put it in the receiveQueue
989  // -- we'll forward it to the user when more data arrives.
990  if (tcpHeader->getFinBit())
991  EV_DETAIL << "SYN+ACK+FIN received: ignoring FIN\n";
992 
993  if (B(tcpSegment->getByteLength()) > tcpHeader->getHeaderLength()) {
995 
996  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpSegment, tcpHeader)) { // enough freeRcvBuffer in rcvQueue for new segment?
997  receiveQueue->insertBytesFromSegment(tcpSegment, tcpHeader); // TODO forward to app, etc.
998  }
999  else { // not enough freeRcvBuffer in rcvQueue for new segment
1000  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
1001 
1003 
1004  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
1005  return TCP_E_IGNORE;
1006  }
1007  }
1008 
1009  if (tcpHeader->getUrgBit() || tcpHeader->getPshBit())
1010  EV_DETAIL << "Ignoring URG and PSH bits in SYN+ACK\n"; // TODO
1011 
1012  if (tcpHeader->getHeaderLength() > TCP_MIN_HEADER_LENGTH) // Header options present?
1013  readHeaderOptions(tcpHeader);
1014 
1015  // notify tcpAlgorithm (it has to send ACK of SYN) and app layer
1016  state->ack_now = true;
1017  tcpAlgorithm->established(true);
1020 
1021  // ECN
1022  if (state->ecnSynSent) {
1023  if (tcpHeader->getEceBit() && !tcpHeader->getCwrBit()) {
1024  state->ect = true;
1025  EV << "ECN-setup SYN-ACK packet was received... ECN is enabled.\n";
1026  }
1027  else {
1028  state->ect = false;
1029  EV << "non-ECN-setup SYN-ACK packet was received... ECN is disabled.\n";
1030  }
1031  state->ecnSynSent = false;
1032  }
1033  else {
1034  state->ect = false;
1035  if (tcpHeader->getEceBit() && !tcpHeader->getCwrBit())
1036  EV << "ECN-setup SYN-ACK packet was received... ECN is disabled.\n";
1037  }
1038 
1039  // This will trigger transition to ESTABLISHED. Timers and notifying
1040  // app will be taken care of in stateEntered().
1041  return TCP_E_RCV_SYN_ACK;
1042  }
1043 
1044  //"
1045  // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment
1046  //
1047  // <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
1048  //
1049  // and send it. If there are other controls or text in the
1050  // segment, queue them for processing after the ESTABLISHED state
1051  // has been reached, return.
1052  //"
1053  EV_INFO << "SYN bit set: sending SYN+ACK\n";
1055  sendSynAck();
1057 
1058  // Note: code below is similar to processing SYN in LISTEN.
1059 
1060  // For consistency with that code, we ignore SYN+FIN here
1061  if (tcpHeader->getFinBit())
1062  EV_DETAIL << "SYN+FIN received: ignoring FIN\n";
1063 
1064  // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
1065  // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
1066  // so there's only URG and PSH left to handle.
1067  if (B(tcpSegment->getByteLength()) > tcpHeader->getHeaderLength()) {
1069 
1070  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpSegment, tcpHeader)) { // enough freeRcvBuffer in rcvQueue for new segment?
1071  receiveQueue->insertBytesFromSegment(tcpSegment, tcpHeader); // TODO forward to app, etc.
1072  }
1073  else { // not enough freeRcvBuffer in rcvQueue for new segment
1074  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
1075 
1077 
1078  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
1079  return TCP_E_IGNORE;
1080  }
1081  }
1082 
1083  if (tcpHeader->getUrgBit() || tcpHeader->getPshBit())
1084  EV_DETAIL << "Ignoring URG and PSH bits in SYN\n"; // TODO
1085 
1086  return TCP_E_RCV_SYN;
1087  }
1088 
1089  //"
1090  // fifth, if neither of the SYN or RST bits is set then drop the
1091  // segment and return.
1092  //"
1093  return TCP_E_IGNORE;
1094 }

Referenced by process_RCV_SEGMENT().

◆ processSynInListen()

TcpEventCode inet::tcp::TcpConnection::processSynInListen ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader,
L3Address  srcAddr,
L3Address  destAddr 
)
protectedvirtual
800 {
801  //"
802  // Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other
803  // control or text should be queued for processing later. ISS
804  // should be selected and a SYN segment sent of the form:
805  //
806  // <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
807  //
808  // SND.NXT is set to ISS+1 and SND.UNA to ISS. The connection
809  // state should be changed to SYN-RECEIVED.
810  //"
811  state->rcv_nxt = tcpHeader->getSequenceNo() + 1;
813 
814  emit(rcvAdvSignal, state->rcv_adv);
815 
816  state->irs = tcpHeader->getSequenceNo();
817  receiveQueue->init(state->rcv_nxt); // FIXME may init twice...
819 
820  // although not mentioned in RFC 793, seems like we have to pick up
821  // initial snd_wnd from the segment here.
822  updateWndInfo(tcpHeader, true);
823 
824  if (tcpHeader->getHeaderLength() > TCP_MIN_HEADER_LENGTH) // Header options present?
825  readHeaderOptions(tcpHeader);
826 
827  state->ack_now = true;
828 
829  // ECN
830  if (tcpHeader->getEceBit() == true && tcpHeader->getCwrBit() == true) {
831  state->endPointIsWillingECN = true;
832  EV << "ECN-setup SYN packet received\n";
833  }
834 
835  sendSynAck();
837 
838  if (!connEstabTimer->isScheduled())
839  scheduleAfter(TCP_TIMEOUT_CONN_ESTAB, connEstabTimer);
840 
841  //"
842  // Note that any other incoming control or data (combined with SYN)
843  // will be processed in the SYN-RECEIVED state, but processing of SYN
844  // and ACK should not be repeated.
845  //"
846  // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
847  // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
848  // so there's only URG and PSH left to handle.
849  //
850  if (B(tcpSegment->getByteLength()) > tcpHeader->getHeaderLength()) {
852 
853  if (hasEnoughSpaceForSegmentInReceiveQueue(tcpSegment, tcpHeader)) { // enough freeRcvBuffer in rcvQueue for new segment?
854  receiveQueue->insertBytesFromSegment(tcpSegment, tcpHeader);
855  }
856  else { // not enough freeRcvBuffer in rcvQueue for new segment
857  state->tcpRcvQueueDrops++; // update current number of tcp receive queue drops
858 
860 
861  EV_WARN << "RcvQueueBuffer has run out, dropping segment\n";
862  return TCP_E_IGNORE;
863  }
864  }
865 
866  if (tcpHeader->getUrgBit() || tcpHeader->getPshBit())
867  EV_DETAIL << "Ignoring URG and PSH bits in SYN\n"; // TODO
868 
869  return TCP_E_RCV_SYN; // this will take us to SYN_RCVD
870 }

Referenced by processSegmentInListen().

◆ processTCPSegment()

bool inet::tcp::TcpConnection::processTCPSegment ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader,
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).

283 {
284  Enter_Method("processTCPSegment");
285 
286  take(tcpSegment);
287  printConnBrief();
288  if (!localAddr.isUnspecified()) {
289  ASSERT(localAddr == segDestAddr);
290  ASSERT(localPort == tcpHeader->getDestPort());
291  }
292 
293  if (!remoteAddr.isUnspecified()) {
294  ASSERT(remoteAddr == segSrcAddr);
295  ASSERT(remotePort == tcpHeader->getSrcPort());
296  }
297 
298  if (tryFastRoute(tcpHeader))
299  return true;
300 
301  // first do actions
302  TcpEventCode event = process_RCV_SEGMENT(tcpSegment, tcpHeader, segSrcAddr, segDestAddr);
303 
304  // then state transitions
305  return performStateTransition(event);
306 }

Referenced by inet::tcp::Tcp::handleLowerPacket().

◆ processTimer()

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).

250 {
251  printConnBrief();
252  EV_DETAIL << msg->getName() << " timer expired\n";
253 
254  // first do actions
255  TcpEventCode event;
256 
257  if (msg == the2MSLTimer) {
258  event = TCP_E_TIMEOUT_2MSL;
260  }
261  else if (msg == connEstabTimer) {
262  event = TCP_E_TIMEOUT_CONN_ESTAB;
264  }
265  else if (msg == finWait2Timer) {
266  event = TCP_E_TIMEOUT_FIN_WAIT_2;
268  }
269  else if (msg == synRexmitTimer) {
270  event = TCP_E_IGNORE;
272  }
273  else {
274  event = TCP_E_IGNORE;
275  tcpAlgorithm->processTimer(msg, event);
276  }
277 
278  // then state transitions
279  return performStateTransition(event);
280 }

Referenced by handleMessage().

◆ processTSOption()

bool inet::tcp::TcpConnection::processTSOption ( const Ptr< const TcpHeader > &  tcpHeader,
const TcpOptionTimestamp option 
)
protectedvirtual
1175 {
1176  if (option.getLength() != 10) {
1177  EV_ERROR << "ERROR: length incorrect\n";
1178  return false;
1179  }
1180 
1181  if ((!state->ts_enabled && fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) ||
1182  (state->ts_enabled && fsm.getState() != TCP_S_SYN_RCVD && fsm.getState() != TCP_S_ESTABLISHED &&
1183  fsm.getState() != TCP_S_FIN_WAIT_1 && fsm.getState() != TCP_S_FIN_WAIT_2))
1184  {
1185  EV_ERROR << "ERROR: Tcp Header Option TS received, but in unexpected state\n";
1186  return false;
1187  }
1188 
1189  if (!state->ts_enabled) {
1190  state->rcv_initial_ts = true;
1192  EV_INFO << "Tcp Header Option TS(TSval=" << option.getSenderTimestamp() << ", TSecr=" << option.getEchoedTimestamp() << ") received, TS (ts_enabled) is set to " << state->ts_enabled << "\n";
1193  }
1194  else
1195  EV_INFO << "Tcp Header Option TS(TSval=" << option.getSenderTimestamp() << ", TSecr=" << option.getEchoedTimestamp() << ") received\n";
1196 
1197  // RFC 1323, page 35:
1198  // "Check whether the segment contains a Timestamps option and bit
1199  // Snd.TS.OK is on. If so:
1200  // If SEG.TSval < TS.Recent, then test whether connection has
1201  // been idle less than 24 days; if both are true, then the
1202  // segment is not acceptable; follow steps below for an
1203  // unacceptable segment.
1204  // If SEG.SEQ is equal to Last.ACK.sent, then save SEG.[TSval] in
1205  // variable TS.Recent."
1206  if (state->ts_enabled) {
1207  if (seqLess(option.getSenderTimestamp(), state->ts_recent)) {
1208  if ((simTime() - state->time_last_data_sent) > PAWS_IDLE_TIME_THRESH) { // PAWS_IDLE_TIME_THRESH = 24 days
1209  EV_DETAIL << "PAWS: Segment is not acceptable, TSval=" << option.getSenderTimestamp() << " in " << stateName(fsm.getState()) << " state received: dropping segment\n";
1210  return false;
1211  }
1212  }
1213  else if (seqLE(tcpHeader->getSequenceNo(), state->last_ack_sent)) { // Note: test is modified according to the latest proposal of the tcplw@cray.com list (Braden 1993/04/26)
1214  state->ts_recent = option.getSenderTimestamp();
1215  EV_DETAIL << "Updating ts_recent from segment: new ts_recent=" << state->ts_recent << "\n";
1216  }
1217  }
1218 
1219  return true;
1220 }

Referenced by readHeaderOptions().

◆ processWSOption()

bool inet::tcp::TcpConnection::processWSOption ( const Ptr< const TcpHeader > &  tcpHeader,
const TcpOptionWindowScale option 
)
protectedvirtual
1150 {
1151  if (option.getLength() != 3) {
1152  EV_ERROR << "ERROR: length incorrect\n";
1153  return false;
1154  }
1155 
1156  if (fsm.getState() != TCP_S_LISTEN && fsm.getState() != TCP_S_SYN_SENT) {
1157  EV_ERROR << "ERROR: Tcp Header Option WS received, but in unexpected state\n";
1158  return false;
1159  }
1160 
1161  state->rcv_ws = true;
1163  state->snd_wnd_scale = option.getWindowScale();
1164  EV_INFO << "Tcp Header Option WS(=" << state->snd_wnd_scale << ") received, WS (ws_enabled) is set to " << state->ws_enabled << "\n";
1165 
1166  if (state->snd_wnd_scale > 14) { // RFC 1323, page 11: "the shift count must be limited to 14"
1167  EV_ERROR << "ERROR: Tcp Header Option WS received but shift count value is exceeding 14\n";
1168  state->snd_wnd_scale = 14;
1169  }
1170 
1171  return true;
1172 }

Referenced by readHeaderOptions().

◆ readHeaderOptions()

void inet::tcp::TcpConnection::readHeaderOptions ( const Ptr< const TcpHeader > &  tcpHeader)
protectedvirtual

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

1063 {
1064  EV_INFO << "Tcp Header Option(s) received:\n";
1065 
1066  for (uint i = 0; i < tcpHeader->getHeaderOptionArraySize(); i++) {
1067  const TcpOption *option = tcpHeader->getHeaderOption(i);
1068  short kind = option->getKind();
1069  short length = option->getLength();
1070  bool ok = true;
1071 
1072  EV_DETAIL << "Option type " << kind << " (" << optionName(kind) << "), length " << length << "\n";
1073 
1074  switch (kind) {
1075  case TCPOPTION_END_OF_OPTION_LIST: // EOL=0
1076  case TCPOPTION_NO_OPERATION: // NOP=1
1077  if (length != 1) {
1078  EV_ERROR << "ERROR: option length incorrect\n";
1079  ok = false;
1080  }
1081  break;
1082 
1083  case TCPOPTION_MAXIMUM_SEGMENT_SIZE: // MSS=2
1084  ok = processMSSOption(tcpHeader, *check_and_cast<const TcpOptionMaxSegmentSize *>(option));
1085  break;
1086 
1087  case TCPOPTION_WINDOW_SCALE: // WS=3
1088  ok = processWSOption(tcpHeader, *check_and_cast<const TcpOptionWindowScale *>(option));
1089  break;
1090 
1091  case TCPOPTION_SACK_PERMITTED: // SACK_PERMITTED=4
1092  ok = processSACKPermittedOption(tcpHeader, *check_and_cast<const TcpOptionSackPermitted *>(option));
1093  break;
1094 
1095  case TCPOPTION_SACK: // SACK=5
1096  ok = processSACKOption(tcpHeader, *check_and_cast<const TcpOptionSack *>(option));
1097  break;
1098 
1099  case TCPOPTION_TIMESTAMP: // TS=8
1100  ok = processTSOption(tcpHeader, *check_and_cast<const TcpOptionTimestamp *>(option));
1101  break;
1102 
1103  // TODO add new TCPOptions here once they are implemented
1104  // TODO delegate to TcpAlgorithm as well -- it may want to recognized additional options
1105 
1106  default:
1107  EV_ERROR << "ERROR: Unsupported Tcp option kind " << kind << "\n";
1108  break;
1109  }
1110  (void)ok; // unused
1111  }
1112 }

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

◆ retransmitData()

void inet::tcp::TcpConnection::retransmitData ( )
virtual

Utility: retransmit all from snd_una to snd_max.

1016 {
1017  // rfc-3168, page 20:
1018  // ECN-capable TCP implementations MUST NOT set either ECT codepoint
1019  // (ECT(0) or ECT(1)) in the IP header for retransmitted data packets
1020  if (state && state->ect)
1021  state->rexmit = true;
1022 
1023  // retransmit everything from snd_una
1024  state->snd_nxt = state->snd_una;
1025 
1026  uint32_t bytesToSend = state->snd_max - state->snd_nxt;
1027 
1028  // FIN (without user data) needs to be resent
1029  if (bytesToSend == 0 && state->send_fin && state->snd_fin_seq == sendQueue->getBufferEndSeq()) {
1031  EV_DETAIL << "No outstanding DATA, resending FIN, advancing snd_nxt over the FIN\n";
1032  state->snd_nxt = state->snd_max;
1033  sendFin();
1034  state->snd_max = ++state->snd_nxt;
1035 
1037  return;
1038  }
1039 
1040  ASSERT(bytesToSend != 0);
1041 
1042  // TODO - avoid to send more than allowed - check cwnd and rwnd before retransmitting data!
1043  while (bytesToSend > 0) {
1044  uint32_t bytes = std::min(bytesToSend, state->snd_mss);
1045  bytes = std::min(bytes, sendQueue->getBytesAvailable(state->snd_nxt));
1046  uint32_t sentBytes = sendSegment(bytes);
1047 
1048  // Do not send packets after the FIN.
1049  // fixes bug that occurs in examples/inet/bulktransfer at event #64043 T=13.861159213744
1050  if (state->send_fin && state->snd_nxt == state->snd_fin_seq + 1)
1051  break;
1052 
1053  ASSERT(bytesToSend >= sentBytes);
1054  bytesToSend -= sentBytes;
1055  }
1057 
1058  if (state && state->ect)
1059  state->rexmit = false;
1060 }

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

◆ retransmitOneSegment()

void inet::tcp::TcpConnection::retransmitOneSegment ( bool  called_at_rto)
virtual

Utility: retransmit one segment from snd_una.

961 {
962  // rfc-3168, page 20:
963  // ECN-capable TCP implementations MUST NOT set either ECT codepoint
964  // (ECT(0) or ECT(1)) in the IP header for retransmitted data packets
965  if (state && state->ect)
966  state->rexmit = true;
967 
968  uint32_t old_snd_nxt = state->snd_nxt;
969 
970  // retransmit one segment at snd_una, and set snd_nxt accordingly (if not called at RTO)
972 
973  // When FIN sent the snd_max - snd_nxt larger than bytes available in queue
974  uint32_t bytes = std::min(std::min(state->snd_mss, state->snd_max - state->snd_nxt),
976 
977  // FIN (without user data) needs to be resent
978  if (bytes == 0 && state->send_fin && state->snd_fin_seq == sendQueue->getBufferEndSeq()) {
980  EV_DETAIL << "No outstanding DATA, resending FIN, advancing snd_nxt over the FIN\n";
982  sendFin();
984  state->snd_max = ++state->snd_nxt;
985 
987  }
988  else {
989  ASSERT(bytes != 0);
990 
991  sendSegment(bytes);
993 
994  if (!called_at_rto) {
995  if (seqGreater(old_snd_nxt, state->snd_nxt))
996  state->snd_nxt = old_snd_nxt;
997  }
998 
999  // notify
1000  tcpAlgorithm->ackSent();
1001 
1002  if (state->sack_enabled) {
1003  // RFC 3517, page 7: "(3) Retransmit the first data segment presumed dropped -- the segment
1004  // starting with sequence number HighACK + 1. To prevent repeated
1005  // retransmission of the same data, set HighRxt to the highest
1006  // sequence number in the retransmitted segment."
1008  }
1009  }
1010 
1011  if (state && state->ect)
1012  state->rexmit = false;
1013 }

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::TcpNewReno::receivedDuplicateAck(), inet::tcp::TcpReno::receivedDuplicateAck(), inet::tcp::TcpTahoe::receivedDuplicateAck(), inet::tcp::TcpWestwood::receivedDuplicateAck(), and inet::tcp::TcpVegas::receivedDuplicateAck().

◆ segmentArrivalWhileClosed()

void inet::tcp::TcpConnection::segmentArrivalWhileClosed ( Packet tcpSegment,
const Ptr< const TcpHeader > &  tcpHeader,
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.

29 {
30  EV_INFO << "Seg arrived: ";
31  printSegmentBrief(tcpSegment, tcpHeader);
32 
33  // This segment doesn't belong to any connection, so this object
34  // must be a temp object created solely for the purpose of calling us
35 
36  ASSERT(state == nullptr);
37 
38  EV_INFO << "Segment doesn't belong to any existing connection\n";
39 
40  // RFC 793:
41  //"
42  // all data in the incoming segment is discarded. An incoming
43  // segment containing a RST is discarded. An incoming segment not
44  // containing a RST causes a RST to be sent in response. The
45  // acknowledgment and sequence field values are selected to make the
46  // reset sequence acceptable to the TCP that sent the offending
47  // segment.
48  //
49  // If the ACK bit is off, sequence number zero is used,
50  //
51  // <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
52  //
53  // If the ACK bit is on,
54  //
55  // <SEQ=SEG.ACK><CTL=RST>
56  //
57  // ...
58  //
59  // SEG.LEN = the number of octets occupied by the data in the segment
60  // (counting SYN and FIN)
61  //"
62  if (tcpHeader->getRstBit()) {
63  EV_DETAIL << "RST bit set: dropping segment\n";
64  return;
65  }
66 
67  if (!tcpHeader->getAckBit()) {
68  EV_DETAIL << "ACK bit not set: sending RST+ACK\n";
69  uint32_t ackNo = tcpHeader->getSequenceNo() + tcpSegment->getByteLength() - B(tcpHeader->getHeaderLength()).get() + tcpHeader->getSynFinLen();
70  sendRstAck(0, ackNo, destAddr, srcAddr, tcpHeader->getDestPort(), tcpHeader->getSrcPort());
71  }
72  else {
73  EV_DETAIL << "ACK bit set: sending RST\n";
74  sendRst(tcpHeader->getAckNo(), destAddr, srcAddr, tcpHeader->getDestPort(), tcpHeader->getSrcPort());
75  }
76 }

◆ selectInitialSeqNum()

void inet::tcp::TcpConnection::selectInitialSeqNum ( )
protectedvirtual

Utility: generates ISS and initializes corresponding state variables.

476 {
477  // set the initial send sequence number
478  state->iss = (unsigned long)fmod(SIMTIME_DBL(simTime()) * 250000.0, 1.0 + (double)(unsigned)0xffffffffUL) & 0xffffffffUL;
479 
481 
482  sendQueue->init(state->iss + 1); // + 1 is for SYN
483  rexmitQueue->init(state->iss + 1); // + 1 is for SYN
484 }

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

◆ sendAck()

void inet::tcp::TcpConnection::sendAck ( )
virtual

Utility: send ACK.

680 {
681  const auto& tcpHeader = makeShared<TcpHeader>();
682 
683  tcpHeader->setAckBit(true);
684  tcpHeader->setSequenceNo(state->snd_nxt);
685  tcpHeader->setAckNo(state->rcv_nxt);
686  tcpHeader->setWindow(updateRcvWnd());
687 
688  // rfc-3168, pages 19-20:
689  // When TCP receives a CE data packet at the destination end-system, the
690  // TCP data receiver sets the ECN-Echo flag in the TCP header of the
691  // subsequent ACK packet.
692  // ...
693  // After a TCP receiver sends an ACK packet with the ECN-Echo bit set,
694  // that TCP receiver continues to set the ECN-Echo flag in all the ACK
695  // packets it sends (whether they acknowledge CE data packets or non-CE
696  // data packets) until it receives a CWR packet (a packet with the CWR
697  // flag set). After the receipt of the CWR packet, acknowledgments for
698  // subsequent non-CE data packets do not have the ECN-Echo flag set.
699 
700  TcpStateVariables *state = getState();
701  if (state && state->ect) {
702  if (tcpAlgorithm->shouldMarkAck()) {
703  tcpHeader->setEceBit(true);
704  EV_INFO << "In ecnEcho state... send ACK with ECE bit set\n";
705  }
706  }
707 
708  // write header options
709  writeHeaderOptions(tcpHeader);
710  Packet *fp = new Packet("TcpAck");
711 
712  // rfc-3168 page 20: pure ack packets must be sent with not-ECT codepoint
713  state->sndAck = true;
714 
715  // send it
716  sendToIP(fp, tcpHeader);
717 
718  state->sndAck = false;
719 
720  // notify
722 }

Referenced by inet::tcp::TcpNoCongestionControl::established(), 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().

◆ sendAvailableDataToApp()

void inet::tcp::TcpConnection::sendAvailableDataToApp ( )
protectedvirtual

Utility: sends data or data notification to application.

388 {
391  auto indication = new Indication("Data Notification", TCP_I_DATA_NOTIFICATION); // TODO currently we never send TCP_I_URGENT_DATA
392  TcpCommand *cmd = new TcpCommand();
393  indication->addTag<SocketInd>()->setSocketId(socketId);
394  indication->setControlInfo(cmd);
395  sendToApp(indication);
396  }
397  else {
398  while (auto msg = receiveQueue->extractBytesUpTo(state->rcv_nxt)) {
399  msg->setKind(TCP_I_DATA); // TODO currently we never send TCP_I_URGENT_DATA
400  msg->addTag<SocketInd>()->setSocketId(socketId);
401  sendToApp(msg);
402  }
403  }
404  }
405 }

Referenced by process_ACCEPT(), and processSegment1stThru8th().

◆ sendAvailableIndicationToApp()

void inet::tcp::TcpConnection::sendAvailableIndicationToApp ( )
protectedvirtual

Utility: sends TCP_I_AVAILABLE indication with TcpAvailableInfo to application.

353 {
354  EV_INFO << "Notifying app: " << indicationName(TCP_I_AVAILABLE) << "\n";
355  auto indication = new Indication(indicationName(TCP_I_AVAILABLE), TCP_I_AVAILABLE);
356  TcpAvailableInfo *ind = new TcpAvailableInfo();
357  ind->setNewSocketId(socketId);
358  ind->setLocalAddr(localAddr);
359  ind->setRemoteAddr(remoteAddr);
360  ind->setLocalPort(localPort);
361  ind->setRemotePort(remotePort);
362 
363  indication->addTag<SocketInd>()->setSocketId(listeningSocketId);
364  indication->setControlInfo(ind);
365  sendToApp(indication);
366 }

Referenced by processSegment1stThru8th().

◆ sendData()

bool inet::tcp::TcpConnection::sendData ( uint32_t  congestionWindow)
virtual

Utility: Send data from sendQueue, at most congestionWindow.

849 {
850  // we'll start sending from snd_max, if not after RTO
851  if (!state->afterRto)
853 
854  uint32_t old_highRxt = 0;
855 
856  if (state->sack_enabled)
857  old_highRxt = rexmitQueue->getHighestRexmittedSeqNum();
858 
859  // check how many bytes we have
860  uint32_t buffered = sendQueue->getBytesAvailable(state->snd_nxt);
861 
862  if (buffered == 0)
863  return false;
864 
865  // maxWindow is minimum of snd_wnd and congestionWindow (snd_cwnd)
866  uint32_t maxWindow = std::min(state->snd_wnd, congestionWindow);
867 
868  // effectiveWindow: number of bytes we're allowed to send now
869  int64_t effectiveWin = (int64_t)maxWindow - (state->snd_nxt - state->snd_una);
870 
871  if (effectiveWin <= 0) {
872  EV_WARN << "Effective window is zero (advertised window " << state->snd_wnd
873  << ", congestion window " << congestionWindow << "), cannot send.\n";
874  return false;
875  }
876 
877  uint32_t bytesToSend = std::min(buffered, (uint32_t)effectiveWin);
878 
879  // make a temporary tcp header for detecting tcp options length (copied from 'TcpConnection::sendSegment(uint32_t bytes)' )
880  const auto& tmpTcpHeader = makeShared<TcpHeader>();
881  tmpTcpHeader->setAckBit(true); // needed for TS option, otherwise TSecr will be set to 0
882  writeHeaderOptions(tmpTcpHeader);
883  uint options_len = B(tmpTcpHeader->getHeaderLength() - TCP_MIN_HEADER_LENGTH).get();
884  ASSERT(options_len < state->snd_mss);
885  uint32_t effectiveMss = state->snd_mss - options_len;
886 
887  uint32_t old_snd_nxt = state->snd_nxt;
888 
889  // start sending 'bytesToSend' bytes
890  EV_INFO << "May send " << bytesToSend << " bytes (effectiveWindow " << effectiveWin << ", in buffer " << buffered << " bytes)\n";
891 
892  // send whole segments
893  while (bytesToSend >= effectiveMss) {
894  uint32_t sentBytes = sendSegment(effectiveMss);
895  ASSERT(bytesToSend >= sentBytes);
896  bytesToSend -= sentBytes;
897  }
898 
899  if (bytesToSend > 0) {
900  // Nagle's algorithm: when a TCP connection has outstanding data that has not
901  // yet been acknowledged, small segments cannot be sent until the outstanding
902  // data is acknowledged.
903  bool unacknowledgedData = (state->snd_una != state->snd_max);
904  bool containsFin = state->send_fin && (state->snd_nxt + bytesToSend) == state->snd_fin_seq;
905  if (state->nagle_enabled && unacknowledgedData && !containsFin)
906  EV_WARN << "Cannot send (last) segment due to Nagle, not enough data for a full segment\n";
907  else
908  sendSegment(bytesToSend);
909  }
910 
911  if (old_snd_nxt == state->snd_nxt)
912  return false; // no data sent
913 
915 
916  // notify (once is enough)
918 
919  if (state->sack_enabled && state->lossRecovery && old_highRxt != state->highRxt) {
920  // Note: Restart of REXMIT timer on retransmission is not part of RFC 2581, however optional in RFC 3517 if sent during recovery.
921  EV_DETAIL << "Retransmission sent during recovery, restarting REXMIT timer.\n";
923  }
924  else // don't measure RTT for retransmitted packets
925  tcpAlgorithm->dataSent(old_snd_nxt);
926 
927  return true;
928 }

Referenced by inet::tcp::DumbTcp::established(), inet::tcp::DumbTcp::receivedDataAck(), inet::tcp::DumbTcp::sendCommandInvoked(), inet::tcp::TcpNoCongestionControl::sendData(), and inet::tcp::TcpBaseAlg::sendData().

◆ sendDataDuringLossRecoveryPhase()

void inet::tcp::TcpConnection::sendDataDuringLossRecoveryPhase ( uint32_t  congestionWindow)
virtual

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

330 {
331  ASSERT(state->sack_enabled && state->lossRecovery);
332 
333  // RFC 3517 pages 7 and 8: "(5) In order to take advantage of potential additional available
334  // cwnd, proceed to step (C) below.
335  // (...)
336  // (C) If cwnd - pipe >= 1 SMSS the sender SHOULD transmit one or more
337  // segments as follows:
338  // (...)
339  // (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1)"
340  while (((int)congestionWindow - (int)state->pipe) >= (int)state->snd_mss) { // Note: Typecast needed to avoid prohibited transmissions
341  // RFC 3517 pages 7 and 8: "(C.1) The scoreboard MUST be queried via NextSeg () for the
342  // sequence number range of the next segment to transmit (if any),
343  // and the given segment sent. If NextSeg () returns failure (no
344  // data to send) return without sending anything (i.e., terminate
345  // steps C.1 -- C.5)."
346 
347  uint32_t seqNum;
348 
349  if (!nextSeg(seqNum)) // if nextSeg() returns false (=failure): terminate steps C.1 -- C.5
350  break;
351 
352  uint32_t sentBytes = sendSegmentDuringLossRecoveryPhase(seqNum);
353  // RFC 3517 page 8: "(C.4) The estimate of the amount of data outstanding in the
354  // network must be updated by incrementing pipe by the number of
355  // octets transmitted in (C.1)."
356  state->pipe += sentBytes;
357  }
358 }

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

◆ sendEstabIndicationToApp()

void inet::tcp::TcpConnection::sendEstabIndicationToApp ( )
protectedvirtual

Utility: sends TCP_I_ESTABLISHED indication with TcpConnectInfo to application.

369 {
370  EV_INFO << "Notifying app: " << indicationName(TCP_I_ESTABLISHED) << "\n";
371  auto indication = new Indication(indicationName(TCP_I_ESTABLISHED), TCP_I_ESTABLISHED);
372  TcpConnectInfo *ind = new TcpConnectInfo();
373  ind->setLocalAddr(localAddr);
374  ind->setRemoteAddr(remoteAddr);
375  ind->setLocalPort(localPort);
376  ind->setRemotePort(remotePort);
377  indication->addTag<SocketInd>()->setSocketId(socketId);
378  indication->setControlInfo(ind);
379  sendToApp(indication);
380 }

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

◆ sendFin()

void inet::tcp::TcpConnection::sendFin ( )
virtual

Utility: sends FIN.

725 {
726  const auto& tcpHeader = makeShared<TcpHeader>();
727 
728  // Note: ACK bit *must* be set for both FIN and FIN+ACK. What makes
729  // the difference for FIN+ACK is that its ackNo acks the remote Tcp's FIN.
730  tcpHeader->setFinBit(true);
731  tcpHeader->setAckBit(true);
732  tcpHeader->setAckNo(state->rcv_nxt);
733  tcpHeader->setSequenceNo(state->snd_nxt);
734  tcpHeader->setWindow(updateRcvWnd());
735  Packet *fp = new Packet("FIN");
736 
737  // send it
738  sendToIP(fp, tcpHeader);
739 
740  // notify
742 }

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

◆ sendIndicationToApp()

void inet::tcp::TcpConnection::sendIndicationToApp ( int  code,
const int  id = 0 
)
protectedvirtual

Utility: sends status indication (TCP_I_xxx) to application.

342 {
343  EV_INFO << "Notifying app: " << indicationName(code) << "\n";
344  auto indication = new Indication(indicationName(code), code);
345  TcpCommand *ind = new TcpCommand();
346  ind->setUserId(id);
347  indication->addTag<SocketInd>()->setSocketId(socketId);
348  indication->setControlInfo(ind);
349  sendToApp(indication);
350 }

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

◆ sendOneNewSegment()

void inet::tcp::TcpConnection::sendOneNewSegment ( bool  fullSegmentsOnly,
uint32_t  congestionWindow 
)
virtual

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

1514 {
1516 
1517  // RFC 3042, page 3:
1518  // "When a TCP sender has previously unsent data queued for transmission
1519  // it SHOULD use the Limited Transmit algorithm, which calls for a TCP
1520  // sender to transmit new data upon the arrival of the first two
1521  // consecutive duplicate ACKs when the following conditions are
1522  // satisfied:
1523  //
1524  // * The receiver's advertised window allows the transmission of the
1525  // segment.
1526  //
1527  // * The amount of outstanding data would remain less than or equal
1528  // to the congestion window plus 2 segments. In other words, the
1529  // sender can only send two segments beyond the congestion window
1530  // (cwnd).
1531  //
1532  // The congestion window (cwnd) MUST NOT be changed when these new
1533  // segments are transmitted. Assuming that these new segments and the
1534  // corresponding ACKs are not dropped, this procedure allows the sender
1535  // to infer loss using the standard Fast Retransmit threshold of three
1536  // duplicate ACKs [RFC2581]. This is more robust to reordered packets
1537  // than if an old packet were retransmitted on the first or second
1538  // duplicate ACK.
1539  //
1540  // Note: If the connection is using selective acknowledgments [RFC2018],
1541  // the data sender MUST NOT send new segments in response to duplicate
1542  // ACKs that contain no new SACK information, as a misbehaving receiver
1543  // can generate such ACKs to trigger inappropriate transmission of data
1544  // segments. See [SCWA99] for a discussion of attacks by misbehaving
1545  // receivers."
1547  // check how many bytes we have
1548  uint32_t buffered = sendQueue->getBytesAvailable(state->snd_max);
1549 
1550  if (buffered >= state->snd_mss || (!fullSegmentsOnly && buffered > 0)) {
1551  uint32_t outstandingData = state->snd_max - state->snd_una;
1552 
1553  // check conditions from RFC 3042
1554  if (outstandingData + state->snd_mss <= state->snd_wnd &&
1555  outstandingData + state->snd_mss <= congestionWindow + 2 * state->snd_mss)
1556  {
1557  // RFC 3042, page 3: "(...)the sender can only send two segments beyond the congestion window (cwnd)."
1558  uint32_t effectiveWin = std::min(state->snd_wnd, congestionWindow) - outstandingData + 2 * state->snd_mss;
1559 
1560  // bytes: number of bytes we're allowed to send now
1561  uint32_t bytes = std::min(effectiveWin, state->snd_mss);
1562 
1563  if (bytes >= state->snd_mss || (!fullSegmentsOnly && bytes > 0)) {
1564  uint32_t old_snd_nxt = state->snd_nxt;
1565  // we'll start sending from snd_max
1566  state->snd_nxt = state->snd_max;
1567 
1568  EV_DETAIL << "Limited Transmit algorithm enabled. Sending one new segment.\n";
1569  uint32_t sentBytes = sendSegment(bytes);
1570 
1572  state->snd_max = state->snd_nxt;
1573 
1575 
1576  // reset snd_nxt if needed
1577  if (state->afterRto)
1578  state->snd_nxt = old_snd_nxt + sentBytes;
1579 
1580  // notify
1581  tcpAlgorithm->ackSent();
1582  tcpAlgorithm->dataSent(old_snd_nxt);
1583  }
1584  }
1585  }
1586  }
1587 }

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

◆ sendProbe()

bool inet::tcp::TcpConnection::sendProbe ( )
virtual

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

931 {
932  // we'll start sending from snd_max
934 
935  // check we have 1 byte to send
937  EV_WARN << "Cannot send probe because send buffer is empty\n";
938  return false;
939  }
940 
941  uint32_t old_snd_nxt = state->snd_nxt;
942 
943  EV_INFO << "Sending 1 byte as probe, with seq=" << state->snd_nxt << "\n";
944  sendSegment(1);
945 
946  // remember highest seq sent (snd_nxt may be set back on retransmission,
947  // but we'll need snd_max to check validity of ACKs -- they must ack
948  // something we really sent)
950 
952 
953  // notify
955  tcpAlgorithm->dataSent(old_snd_nxt);
956 
957  return true;
958 }

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

◆ sendRst() [1/2]

void inet::tcp::TcpConnection::sendRst ( uint32_t  seq,
L3Address  src,
L3Address  dest,
int  srcPort,
int  destPort 
)
virtual

Utility: sends RST; does not use connection state.

638 {
639  const auto& tcpHeader = makeShared<TcpHeader>();
640 
641  tcpHeader->setSrcPort(srcPort);
642  tcpHeader->setDestPort(destPort);
643 
644  tcpHeader->setRstBit(true);
645  tcpHeader->setSequenceNo(seq);
646  tcpHeader->setCrcMode(tcpMain->crcMode);
647  tcpHeader->setCrc(0);
648 
649  Packet *fp = new Packet("RST");
650 
651  // send it
652  sendToIP(fp, tcpHeader, src, dest);
653 }

◆ sendRst() [2/2]

void inet::tcp::TcpConnection::sendRst ( uint32_t  seqNo)
virtual

◆ sendRstAck()

void inet::tcp::TcpConnection::sendRstAck ( uint32_t  seq,
uint32_t  ack,
L3Address  src,
L3Address  dest,
int  srcPort,
int  destPort 
)
virtual

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

656 {
657  const auto& tcpHeader = makeShared<TcpHeader>();
658 
659  tcpHeader->setSrcPort(srcPort);
660  tcpHeader->setDestPort(destPort);
661 
662  tcpHeader->setRstBit(true);
663  tcpHeader->setAckBit(true);
664  tcpHeader->setSequenceNo(seq);
665  tcpHeader->setAckNo(ack);
666  tcpHeader->setCrcMode(tcpMain->crcMode);
667  tcpHeader->setCrc(0);
668 
669  Packet *fp = new Packet("RST+ACK");
670 
671  // send it
672  sendToIP(fp, tcpHeader, src, dest);
673 
674  // notify
675  if (tcpAlgorithm)
677 }

Referenced by segmentArrivalWhileClosed().

◆ sendSegment()

uint32_t inet::tcp::TcpConnection::sendSegment ( uint32_t  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. Returns the number of bytes sent.

745 {
746  // FIXME check it: where is the right place for the next code (sacked/rexmitted)
747  if (state->sack_enabled && state->afterRto) {
748  // check rexmitQ and try to forward snd_nxt before sending new data
750 
751  if (forward > 0) {
752  EV_INFO << "sendSegment(" << bytes << ") forwarded " << forward << " bytes of snd_nxt from " << state->snd_nxt;
753  state->snd_nxt += forward;
754  EV_INFO << " to " << state->snd_nxt << endl;
755  EV_DETAIL << rexmitQueue->detailedInfo();
756  }
757  }
758 
759  uint32_t buffered = sendQueue->getBytesAvailable(state->snd_nxt);
760 
761  if (bytes > buffered) // last segment?
762  bytes = buffered;
763 
764  // if header options will be added, this could reduce the number of data bytes allowed for this segment,
765  // because following condition must to be respected:
766  // bytes + options_len <= snd_mss
767  const auto& tmpTcpHeader = makeShared<TcpHeader>();
768  tmpTcpHeader->setAckBit(true); // needed for TS option, otherwise TSecr will be set to 0
769  writeHeaderOptions(tmpTcpHeader);
770  uint options_len = B(tmpTcpHeader->getHeaderLength() - TCP_MIN_HEADER_LENGTH).get();
771 
772  ASSERT(options_len < state->snd_mss);
773 
774  if (bytes + options_len > state->snd_mss)
775  bytes = state->snd_mss - options_len;
776 
777  uint32_t sentBytes = bytes;
778 
779  // send one segment of 'bytes' bytes from snd_nxt, and advance snd_nxt
780  Packet *tcpSegment = sendQueue->createSegmentWithBytes(state->snd_nxt, bytes);
781  const auto& tcpHeader = makeShared<TcpHeader>();
782  tcpHeader->setSequenceNo(state->snd_nxt);
783  ASSERT(tcpHeader != nullptr);
784 
785  // Remember old_snd_next to store in SACK rexmit queue.
786  uint32_t old_snd_nxt = state->snd_nxt;
787 
788  tcpHeader->setAckNo(state->rcv_nxt);
789  tcpHeader->setAckBit(true);
790  tcpHeader->setWindow(updateRcvWnd());
791 
792  // ECN
793  if (state->ect && state->sndCwr) {
794  tcpHeader->setCwrBit(true);
795  EV_INFO << "set CWR bit\n";
796  state->sndCwr = false;
797  }
798 
799  // TODO when to set PSH bit?
800  // TODO set URG bit if needed
801  ASSERT(bytes == tcpSegment->getByteLength());
802 
803  state->snd_nxt += bytes;
804 
805  // check if afterRto bit can be reset
807  state->afterRto = false;
808 
809  if (state->send_fin && state->snd_nxt == state->snd_fin_seq) {
810  EV_DETAIL << "Setting FIN on segment\n";
811  tcpHeader->setFinBit(true);
812  state->snd_nxt = state->snd_fin_seq + 1;
813  }
814 
815  // if sack_enabled copy region of tcpHeader to rexmitQueue
816  if (state->sack_enabled)
817  rexmitQueue->enqueueSentData(old_snd_nxt, state->snd_nxt);
818 
819  // add header options and update header length (from tcpseg_temp)
820  for (uint i = 0; i < tmpTcpHeader->getHeaderOptionArraySize(); i++)
821  tcpHeader->appendHeaderOption(tmpTcpHeader->getHeaderOption(i)->dup());
822  tcpHeader->setHeaderLength(TCP_MIN_HEADER_LENGTH + tcpHeader->getHeaderOptionArrayLength());
823  tcpHeader->setChunkLength(B(tcpHeader->getHeaderLength()));
824 
825  ASSERT(tcpHeader->getHeaderLength() == tmpTcpHeader->getHeaderLength());
826 
827  // send it
828  sendToIP(tcpSegment, tcpHeader);
829 
830  // let application fill queue again, if there is space
831  const uint32_t alreadyQueued = sendQueue->getBytesAvailable(sendQueue->getBufferStartSeq());
832  const uint32_t abated = (state->sendQueueLimit > alreadyQueued) ? state->sendQueueLimit - alreadyQueued : 0;
833  if ((state->sendQueueLimit > 0) && !state->queueUpdate && (abated >= state->snd_mss)) { // request more data if space >= 1 MSS
834  // Tell upper layer readiness to accept more data
836  state->queueUpdate = true;
837  }
838 
839  // remember highest seq sent (snd_nxt may be set back on retransmission,
840  // but we'll need snd_max to check validity of ACKs -- they must ack
841  // something we really sent)
844 
845  return sentBytes;
846 }

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

◆ sendSegmentDuringLossRecoveryPhase()

uint32_t inet::tcp::TcpConnection::sendSegmentDuringLossRecoveryPhase ( uint32_t  seqNum)
virtual

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

Returns the number of bytes sent.

361 {
362  ASSERT(state->sack_enabled && state->lossRecovery);
363 
364  // start sending from seqNum
365  state->snd_nxt = seqNum;
366 
367  uint32_t old_highRxt = rexmitQueue->getHighestRexmittedSeqNum();
368 
369  // no need to check cwnd and rwnd - has already be done before
370  // no need to check nagle - sending mss bytes
371  uint32_t sentBytes = sendSegment(state->snd_mss);
372 
373  uint32_t sentSeqNum = seqNum + sentBytes;
374 
375  if (state->send_fin && sentSeqNum == state->snd_fin_seq)
376  sentSeqNum = sentSeqNum + 1;
377 
378  ASSERT(seqLE(state->snd_nxt, sentSeqNum));
379 
380  // RFC 3517 page 8: "(C.2) If any of the data octets sent in (C.1) are below HighData,
381  // HighRxt MUST be set to the highest sequence number of the
382  // retransmitted segment."
383  if (seqLess(seqNum, state->snd_max)) { // HighData = snd_max
385  }
386 
387  // RFC 3517 page 8: "(C.3) If any of the data octets sent in (C.1) are above HighData,
388  // HighData must be updated to reflect the transmission of
389  // previously unsent data."
390  if (seqGreater(sentSeqNum, state->snd_max)) // HighData = snd_max
391  state->snd_max = sentSeqNum;
392 
394 
395  // RFC 3517, page 9: "6 Managing the RTO Timer
396  //
397  // The standard TCP RTO estimator is defined in [RFC2988]. Due to the
398  // fact that the SACK algorithm in this document can have an impact on
399  // the behavior of the estimator, implementers may wish to consider how
400  // the timer is managed. [RFC2988] calls for the RTO timer to be
401  // re-armed each time an ACK arrives that advances the cumulative ACK
402  // point. Because the algorithm presented in this document can keep the
403  // ACK clock going through a fairly significant loss event,
404  // (comparatively longer than the algorithm described in [RFC2581]), on
405  // some networks the loss event could last longer than the RTO. In this
406  // case the RTO timer would expire prematurely and a segment that need
407  // not be retransmitted would be resent.
408  //
409  // Therefore we give implementers the latitude to use the standard
410  // [RFC2988] style RTO management or, optionally, a more careful variant
411  // that re-arms the RTO timer on each retransmission that is sent during
412  // recovery MAY be used. This provides a more conservative timer than
413  // specified in [RFC2988], and so may not always be an attractive
414  // alternative. However, in some cases it may prevent needless
415  // retransmissions, go-back-N transmission and further reduction of the
416  // congestion window."
418 
419  if (old_highRxt != state->highRxt) {
420  // Note: Restart of REXMIT timer on retransmission is not part of RFC 2581, however optional in RFC 3517 if sent during recovery.
421  EV_INFO << "Retransmission sent during recovery, restarting REXMIT timer.\n";
423  }
424  else // don't measure RTT for retransmitted packets
425  tcpAlgorithm->dataSent(seqNum); // seqNum = old_snd_nxt
426 
427  return sentBytes;
428 }

Referenced by sendDataDuringLossRecoveryPhase().

◆ sendSyn()

void inet::tcp::TcpConnection::sendSyn ( )
protectedvirtual

Utility: send SYN.

539 {
540  if (remoteAddr.isUnspecified() || remotePort == -1)
541  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: foreign socket unspecified");
542 
543  if (localPort == -1)
544  throw cRuntimeError(tcpMain, "Error processing command OPEN_ACTIVE: local port unspecified");
545 
546  // create segment
547  const auto& tcpHeader = makeShared<TcpHeader>();
548  tcpHeader->setSequenceNo(state->iss);
549  tcpHeader->setSynBit(true);
550  updateRcvWnd();
551  tcpHeader->setWindow(state->rcv_wnd);
552 
553  state->snd_max = state->snd_nxt = state->iss + 1;
554 
555  // ECN
556  if (state->ecnWillingness) {
557  tcpHeader->setEceBit(true);
558  tcpHeader->setCwrBit(true);
559  state->ecnSynSent = true;
560  EV << "ECN-setup SYN packet sent\n";
561  }
562  else {
563  // rfc 3168 page 16:
564  // A host that is not willing to use ECN on a TCP connection SHOULD
565  // clear both the ECE and CWR flags in all non-ECN-setup SYN and/or
566  // SYN-ACK packets that it sends to indicate this unwillingness.
567  tcpHeader->setEceBit(false);
568  tcpHeader->setCwrBit(false);
569  state->ecnSynSent = false;
570 // EV << "non-ECN-setup SYN packet sent\n";
571  }
572 
573  // write header options
574  writeHeaderOptions(tcpHeader);
575  Packet *fp = new Packet("SYN");
576 
577  // send it
578  sendToIP(fp, tcpHeader);
579 }

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

◆ sendSynAck()

void inet::tcp::TcpConnection::sendSynAck ( )
protectedvirtual

Utility: send SYN+ACK.

582 {
583  // create segment
584  const auto& tcpHeader = makeShared<TcpHeader>();
585  tcpHeader->setSequenceNo(state->iss);
586  tcpHeader->setAckNo(state->rcv_nxt);
587  tcpHeader->setSynBit(true);
588  tcpHeader->setAckBit(true);
589  updateRcvWnd();
590  tcpHeader->setWindow(state->rcv_wnd);
591 
592  state->snd_max = state->snd_nxt = state->iss + 1;
593 
594  // ECN
595  if (state->ecnWillingness) {
596  tcpHeader->setEceBit(true);
597  tcpHeader->setCwrBit(false);
598  EV << "ECN-setup SYN-ACK packet sent\n";
599  }
600  else {
601  tcpHeader->setEceBit(false);
602  tcpHeader->setCwrBit(false);
604  EV << "non-ECN-setup SYN-ACK packet sent\n";
605  }
607  state->ect = true;
608  EV << "both end-points are willing to use ECN... ECN is enabled\n";
609  }
610  else { // TODO not sure if we have to.
611  // rfc-3168, page 16:
612  // A host that is not willing to use ECN on a TCP connection SHOULD
613  // clear both the ECE and CWR flags in all non-ECN-setup SYN and/or
614  // SYN-ACK packets that it sends to indicate this unwillingness.
615  state->ect = false;
617  EV << "ECN is disabled\n";
618  }
619 
620  // write header options
621  writeHeaderOptions(tcpHeader);
622 
623  Packet *fp = new Packet("SYN+ACK");
624 
625  // send it
626  sendToIP(fp, tcpHeader);
627 
628  // notify
630 }

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

◆ sendToApp()

void inet::tcp::TcpConnection::sendToApp ( cMessage *  msg)
protectedvirtual

Utility: sends packet to application.

383 {
384  tcpMain->sendFromConn(msg, "appOut");
385 }

Referenced by process_READ_REQUEST(), process_STATUS(), sendAvailableDataToApp(), sendAvailableIndicationToApp(), sendEstabIndicationToApp(), and sendIndicationToApp().

◆ sendToIP() [1/2]

void inet::tcp::TcpConnection::sendToIP ( Packet pkt,
const Ptr< TcpHeader > &  tcpHeader,
L3Address  src,
L3Address  dest 
)
protectedvirtual

Utility: send IP packet.

309 {
310  EV_STATICCONTEXT;
311  EV_INFO << "Sending: ";
312  printSegmentBrief(tcpSegment, tcpHeader);
313 
314  IL3AddressType *addressType = dest.getAddressType();
315  ASSERT(tcpHeader->getChunkLength() == tcpHeader->getHeaderLength());
316  tcpSegment->addTagIfAbsent<DispatchProtocolReq>()->setProtocol(addressType->getNetworkProtocol());
317 
318  if (ttl != -1 && tcpSegment->findTag<HopLimitReq>() == nullptr)
319  tcpSegment->addTag<HopLimitReq>()->setHopLimit(ttl);
320 
321  if (dscp != -1 && tcpSegment->findTag<DscpReq>() == nullptr)
322  tcpSegment->addTag<DscpReq>()->setDifferentiatedServicesCodePoint(dscp);
323 
324  if (tos != -1 && tcpSegment->findTag<TosReq>() == nullptr)
325  tcpSegment->addTag<TosReq>()->setTos(tos);
326 
327  auto addresses = tcpSegment->addTagIfAbsent<L3AddressReq>();
328  addresses->setSrcAddress(src);
329  addresses->setDestAddress(dest);
330 
331  insertTransportProtocolHeader(tcpSegment, Protocol::tcp, tcpHeader);
332 
333  tcpMain->sendFromConn(tcpSegment, "ipOut");
334 }

◆ sendToIP() [2/2]

void inet::tcp::TcpConnection::sendToIP ( Packet tcpSegment,
const Ptr< TcpHeader > &  tcpHeader 
)
virtual

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

247 {
248  // record seq (only if we do send data) and ackno
249  if (tcpSegment->getByteLength() > B(tcpHeader->getChunkLength()).get())
250  emit(sndNxtSignal, tcpHeader->getSequenceNo());
251 
252  emit(sndAckSignal, tcpHeader->getAckNo());
253 
254  // final touches on the segment before sending
255  tcpHeader->setSrcPort(localPort);
256  tcpHeader->setDestPort(remotePort);
257  ASSERT(tcpHeader->getHeaderLength() >= TCP_MIN_HEADER_LENGTH);
258  ASSERT(tcpHeader->getHeaderLength() <= TCP_MAX_HEADER_LENGTH);
259  ASSERT(tcpHeader->getChunkLength() == tcpHeader->getHeaderLength());
260 
261  EV_INFO << "Sending: ";
262  printSegmentBrief(tcpSegment, tcpHeader);
263 
264  // TODO reuse next function for sending
265 
266  IL3AddressType *addressType = remoteAddr.getAddressType();
267  tcpSegment->addTagIfAbsent<DispatchProtocolReq>()->setProtocol(addressType->getNetworkProtocol());
268 
269  if (ttl != -1 && tcpSegment->findTag<HopLimitReq>() == nullptr)
270  tcpSegment->addTag<HopLimitReq>()->setHopLimit(ttl);
271 
272  if (dscp != -1 && tcpSegment->findTag<DscpReq>() == nullptr)
273  tcpSegment->addTag<DscpReq>()->setDifferentiatedServicesCodePoint(dscp);
274 
275  if (tos != -1 && tcpSegment->findTag<TosReq>() == nullptr)
276  tcpSegment->addTag<TosReq>()->setTos(tos);
277 
278  auto addresses = tcpSegment->addTagIfAbsent<L3AddressReq>();
279  addresses->setSrcAddress(localAddr);
280  addresses->setDestAddress(remoteAddr);
281 
282  // ECN:
283  // We decided to use ECT(1) to indicate ECN capable transport.
284  //
285  // rfc-3168, page 6:
286  // Routers treat the ECT(0) and ECT(1) codepoints
287  // as equivalent. Senders are free to use either the ECT(0) or the
288  // ECT(1) codepoint to indicate ECT.
289  //
290  // rfc-3168, page 20:
291  // For the current generation of TCP congestion control algorithms, pure
292  // acknowledgement packets (e.g., packets that do not contain any
293  // accompanying data) MUST be sent with the not-ECT codepoint.
294  //
295  // rfc-3168, page 20:
296  // ECN-capable TCP implementations MUST NOT set either ECT codepoint
297  // (ECT(0) or ECT(1)) in the IP header for retransmitted data packets
298  tcpSegment->addTagIfAbsent<EcnReq>()->setExplicitCongestionNotification((state->ect && !state->sndAck && !state->rexmit) ? IP_ECN_ECT_1 : IP_ECN_NOT_ECT);
299 
300  tcpHeader->setCrc(0);
301  tcpHeader->setCrcMode(tcpMain->crcMode);
302 
303  insertTransportProtocolHeader(tcpSegment, Protocol::tcp, tcpHeader);
304 
305  tcpMain->sendFromConn(tcpSegment, "ipOut");
306 }

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

◆ setPipe()

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."

142 {
143  ASSERT(state->sack_enabled);
144 
145  // RFC 3517, pages 1 and 2: "
146  // "HighACK" is the sequence number of the highest byte of data that
147  // has been cumulatively ACKed at a given point.
148  //
149  // "HighData" is the highest sequence number transmitted at a given
150  // point.
151  //
152  // "HighRxt" is the highest sequence number which has been
153  // retransmitted during the current loss recovery phase.
154  //
155  // "Pipe" is a sender's estimate of the number of bytes outstanding
156  // in the network. This is used during recovery for limiting the
157  // sender's sending rate. The pipe variable allows TCP to use a
158  // fundamentally different congestion control than specified in
159  // [RFC2581]. The algorithm is often referred to as the "pipe
160  // algorithm"."
161  // HighAck = snd_una
162  // HighData = snd_max
163 
165  state->pipe = 0;
166  uint32_t length = 0; // required for rexmitQueue->checkSackBlock()
167  bool sacked; // required for rexmitQueue->checkSackBlock()
168  bool rexmitted; // required for rexmitQueue->checkSackBlock()
169 
170  // RFC 3517, page 3: "This routine traverses the sequence space from HighACK to HighData
171  // and MUST set the "pipe" variable to an estimate of the number of
172  // octets that are currently in transit between the TCP sender and
173  // the TCP receiver. After initializing pipe to zero the following
174  // steps are taken for each octet 'S1' in the sequence space between
175  // HighACK and HighData that has not been SACKed:"
176  for (uint32_t s1 = state->snd_una; seqLess(s1, state->snd_max); s1 += length) {
177  rexmitQueue->checkSackBlock(s1, length, sacked, rexmitted);
178 
179  if (!sacked) {
180  // RFC 3517, page 3: "(a) If IsLost (S1) returns false:
181  //
182  // Pipe is incremented by 1 octet.
183  //
184  // The effect of this condition is that pipe is incremented for
185  // packets that have not been SACKed and have not been determined
186  // to have been lost (i.e., those segments that are still assumed
187  // to be in the network)."
188  if (isLost(s1) == false)
189  state->pipe += length;
190 
191  // RFC 3517, pages 3 and 4: "(b) If S1 <= HighRxt:
192  //
193  // Pipe is incremented by 1 octet.
194  //
195  // The effect of this condition is that pipe is incremented for
196  // the retransmission of the octet.
197  //
198  // Note that octets retransmitted without being considered lost are
199  // counted twice by the above mechanism."
200  if (seqLess(s1, state->highRxt))
201  state->pipe += length;
202  }
203  }
204 
205  emit(pipeSignal, state->pipe);
206 }

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

◆ setSocketId()

void inet::tcp::TcpConnection::setSocketId ( int  newSocketId)
inline

◆ signalConnectionTimeout()

void inet::tcp::TcpConnection::signalConnectionTimeout ( )
virtual

Utility: signal to user that connection timed out.

337 {
339 }

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

◆ startSynRexmitTimer()

void inet::tcp::TcpConnection::startSynRexmitTimer ( )
virtual

Utility: start SYN-REXMIT timer.

1333 {
1334  state->syn_rexmit_count = 0;
1336  rescheduleAfter(state->syn_rexmit_timeout, synRexmitTimer);
1337 }

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

◆ stateEntered()

void inet::tcp::TcpConnection::stateEntered ( int  state,
int  oldState,
TcpEventCode  event 
)
protectedvirtual

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

cancelling timers

693 {
694  // cancel timers
695  switch (state) {
696  case TCP_S_INIT:
697  // we'll never get back to INIT
698  break;
699 
700  case TCP_S_LISTEN:
701  // we may get back to LISTEN from SYN_RCVD
702  ASSERT(connEstabTimer && synRexmitTimer);
703  cancelEvent(connEstabTimer);
704  cancelEvent(synRexmitTimer);
705  break;
706 
707  case TCP_S_SYN_RCVD:
708  case TCP_S_SYN_SENT:
709  break;
710 
711  case TCP_S_ESTABLISHED:
712  // we're in ESTABLISHED, these timers are no longer needed
713  delete cancelEvent(connEstabTimer);
714  delete cancelEvent(synRexmitTimer);
715  connEstabTimer = synRexmitTimer = nullptr;
716  // TCP_I_ESTAB notification moved inside event processing
717  break;
718 
719  case TCP_S_CLOSE_WAIT:
720  case TCP_S_LAST_ACK:
721  case TCP_S_FIN_WAIT_1:
722  case TCP_S_FIN_WAIT_2:
723  case TCP_S_CLOSING:
724  if (state == TCP_S_CLOSE_WAIT)
726  // whether connection setup succeeded (ESTABLISHED) or not (others),
727  // cancel these timers
728  if (connEstabTimer)
729  cancelEvent(connEstabTimer);
730  if (synRexmitTimer)
731  cancelEvent(synRexmitTimer);
732  break;
733 
734  case TCP_S_TIME_WAIT:
736  break;
737 
738  case TCP_S_CLOSED:
739  if (oldState != TCP_S_TIME_WAIT && event != TCP_E_ABORT)
741  // all timers need to be cancelled
742  if (the2MSLTimer)
743  cancelEvent(the2MSLTimer);
744  if (connEstabTimer)
745  cancelEvent(connEstabTimer);
746  if (finWait2Timer)
747  cancelEvent(finWait2Timer);
748  if (synRexmitTimer)
749  cancelEvent(synRexmitTimer);
751  break;
752  }
753 }

Referenced by performStateTransition().

◆ stateName()

const char * inet::tcp::TcpConnection::stateName ( int  state)
static

Utility: returns name of TCP_S_xxx constants.

43 {
44 #define CASE(x) case x: \
45  s = (char *)#x + 6; break
46  const char *s = "unknown";
47  switch (state) {
60  }
61  return s;
62 #undef CASE
63 }

Referenced by inet::tcp::operator<<(), performStateTransition(), printConnBrief(), process_STATUS(), process_TIMEOUT_2MSL(), process_TIMEOUT_CONN_ESTAB(), process_TIMEOUT_FIN_WAIT_2(), process_TIMEOUT_SYN_REXMIT(), processSegment1stThru8th(), and processTSOption().

◆ tryFastRoute()

bool inet::tcp::TcpConnection::tryFastRoute ( const Ptr< const TcpHeader > &  tcpHeader)
protectedvirtual

Shortcut to process most common case as fast as possible.

Returns false if segment requires normal (slow) route.

23 {
24  // fast route processing not yet implemented
25  return false;
26 }

Referenced by processTCPSegment().

◆ updateRcvQueueVars()

void inet::tcp::TcpConnection::updateRcvQueueVars ( )
virtual

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

1427 {
1428  // update receive queue related state variables
1431 
1432  // update receive queue related statistics
1434 
1435 // tcpEV << "receiveQ: receiveQLength=" << receiveQueue->getQueueLength() << " maxRcvBuffer=" << state->maxRcvBuffer << " usedRcvBuffer=" << state->usedRcvBuffer << " freeRcvBuffer=" << state->freeRcvBuffer << "\n";
1436 }

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

◆ updateRcvWnd()

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.

1439 {
1440  uint32_t win = 0;
1441 
1442  // update receive queue related state variables and statistics
1444  win = state->freeRcvBuffer;
1445 
1446  // Following lines are based on [Stevens, W.R.: TCP/IP Illustrated, Volume 2, chapter 26.7, pages 878-879]:
1447  // Don't advertise less than one full-sized segment to avoid SWS
1448  if (win < (state->maxRcvBuffer / 4) && win < state->snd_mss)
1449  win = 0;
1450 
1451  // Do not shrink window
1452  // (rcv_adv minus rcv_nxt) is the amount of space still available to the sender that was previously advertised
1453  if (win < state->rcv_adv - state->rcv_nxt)
1454  win = state->rcv_adv - state->rcv_nxt;
1455 
1456  // Observe upper limit for advertised window on this connection
1457  const uint32_t maxWin = (state->ws_enabled && state->rcv_wnd_scale) ? (TCP_MAX_WIN << state->rcv_wnd_scale) : TCP_MAX_WIN; // TCP_MAX_WIN = 65535 (16 bit)
1458  if (win > maxWin)
1459  win = maxWin; // Note: The window size is limited to a 16 bit value in the TCP header if WINDOW SCALE option (RFC 1323) is not used
1460 
1461  // 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
1462 
1463  // update rcv_adv if needed
1464  if (win > 0 && seqGE(state->rcv_nxt + win, state->rcv_adv)) {
1465  state->rcv_adv = state->rcv_nxt + win;
1466 
1467  emit(rcvAdvSignal, state->rcv_adv);
1468  }
1469 
1470  state->rcv_wnd = win;
1471 
1472  emit(rcvWndSignal, state->rcv_wnd);
1473 
1474  // scale rcv_wnd:
1475  uint32_t scaled_rcv_wnd = state->rcv_wnd;
1476  if (state->ws_enabled && state->rcv_wnd_scale) {
1477  ASSERT(state->rcv_wnd_scale <= 14); // RFC 1323, page 11: "the shift count must be limited to 14"
1478  scaled_rcv_wnd = scaled_rcv_wnd >> state->rcv_wnd_scale;
1479  }
1480 
1481  ASSERT(scaled_rcv_wnd == (unsigned short)scaled_rcv_wnd);
1482 
1483  return (unsigned short)scaled_rcv_wnd;
1484 }

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

◆ updateWndInfo()

void inet::tcp::TcpConnection::updateWndInfo ( const Ptr< const TcpHeader > &  tcpHeader,
bool  doAlways = false 
)
virtual

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

1487 {
1488  uint32_t true_window = tcpHeader->getWindow();
1489  // RFC 1323, page 10:
1490  // "The window field (SEG.WND) in the header of every incoming
1491  // segment, with the exception of SYN segments, is left-shifted
1492  // by Snd.Wind.Scale bits before updating SND.WND:
1493  // SND.WND = SEG.WND << Snd.Wind.Scale"
1494  if (state->ws_enabled && !tcpHeader->getSynBit())
1495  true_window = tcpHeader->getWindow() << state->snd_wnd_scale;
1496 
1497  // Following lines are based on [Stevens, W.R.: TCP/IP Illustrated, Volume 2, page 982]:
1498  if (doAlways || (tcpHeader->getAckBit()
1499  && (seqLess(state->snd_wl1, tcpHeader->getSequenceNo()) ||
1500  (state->snd_wl1 == tcpHeader->getSequenceNo() && seqLE(state->snd_wl2, tcpHeader->getAckNo())) ||
1501  (state->snd_wl2 == tcpHeader->getAckNo() && true_window > state->snd_wnd))))
1502  {
1503  // send window should be updated
1504  state->snd_wnd = true_window;
1505  EV_INFO << "Updating send window from segment: new wnd=" << state->snd_wnd << "\n";
1506  state->snd_wl1 = tcpHeader->getSequenceNo();
1507  state->snd_wl2 = tcpHeader->getAckNo();
1508 
1509  emit(sndWndSignal, state->snd_wnd);
1510  }
1511 }

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

◆ writeHeaderOptions()

TcpHeader inet::tcp::TcpConnection::writeHeaderOptions ( const Ptr< TcpHeader > &  tcpHeader)
protectedvirtual

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

1241 {
1242  // SYN flag set and connetion in INIT or LISTEN state (or after synRexmit timeout)
1243  if (tcpHeader->getSynBit() && (fsm.getState() == TCP_S_INIT || fsm.getState() == TCP_S_LISTEN
1244  || ((fsm.getState() == TCP_S_SYN_SENT || fsm.getState() == TCP_S_SYN_RCVD)
1245  && state->syn_rexmit_count > 0)))
1246  {
1247  // MSS header option
1248  if (state->snd_mss > 0) {
1249  TcpOptionMaxSegmentSize *option = new TcpOptionMaxSegmentSize();
1250  option->setMaxSegmentSize(state->snd_mss);
1251  tcpHeader->appendHeaderOption(option);
1252  EV_INFO << "Tcp Header Option MSS(=" << state->snd_mss << ") sent\n";
1253  }
1254 
1255  // WS header option
1256  if (state->ws_support && (state->rcv_ws || (fsm.getState() == TCP_S_INIT
1257  || (fsm.getState() == TCP_S_SYN_SENT && state->syn_rexmit_count > 0))))
1258  {
1259  // 1 padding byte
1260  tcpHeader->appendHeaderOption(new TcpOptionNop()); // NOP
1261 
1262  // Update WS variables
1263  if (state->ws_manual_scale > -1) {
1265  }
1266  else {
1267  ulong scaled_rcv_wnd = receiveQueue->getFirstSeqNo() + state->maxRcvBuffer - state->rcv_nxt;
1268  state->rcv_wnd_scale = 0;
1269 
1270  while (scaled_rcv_wnd > TCP_MAX_WIN && state->rcv_wnd_scale < 14) { // RFC 1323, page 11: "the shift count must be limited to 14"
1271  scaled_rcv_wnd = scaled_rcv_wnd >> 1;
1272  state->rcv_wnd_scale++;
1273  }
1274  }
1275 
1276  TcpOptionWindowScale *option = new TcpOptionWindowScale();
1277  option->setWindowScale(state->rcv_wnd_scale); // rcv_wnd_scale is also set in scaleRcvWnd()
1278  state->snd_ws = true;
1280  EV_INFO << "Tcp Header Option WS(=" << option->getWindowScale() << ") sent, WS (ws_enabled) is set to " << state->ws_enabled << "\n";
1281  tcpHeader->appendHeaderOption(option);
1282  }
1283 
1284  // SACK_PERMITTED header option
1285  if (state->sack_support && (state->rcv_sack_perm || (fsm.getState() == TCP_S_INIT
1286  || (fsm.getState() == TCP_S_SYN_SENT && state->syn_rexmit_count > 0))))
1287  {
1288  if (!state->ts_support) { // if TS is supported by host, do not add NOPs to this segment
1289  // 2 padding bytes
1290  tcpHeader->appendHeaderOption(new TcpOptionNop()); // NOP
1291  tcpHeader->appendHeaderOption(new TcpOptionNop()); // NOP
1292  }
1293 
1294  tcpHeader->appendHeaderOption(new TcpOptionSackPermitted());
1295 
1296  // Update SACK variables
1297  state->snd_sack_perm = true;
1299  EV_INFO << "Tcp Header Option SACK_PERMITTED sent, SACK (sack_enabled) is set to " << state->sack_enabled << "\n";
1300  }
1301 
1302  // TS header option
1303  if (state->ts_support && (state->rcv_initial_ts || (fsm.getState() == TCP_S_INIT
1304  || (fsm.getState() == TCP_S_SYN_SENT && state->syn_rexmit_count > 0))))
1305  {
1306  if (!state->sack_support) { // if SACK is supported by host, do not add NOPs to this segment
1307  // 2 padding bytes
1308  tcpHeader->appendHeaderOption(new TcpOptionNop()); // NOP
1309  tcpHeader->appendHeaderOption(new TcpOptionNop()); // NOP
1310  }
1311 
1312  TcpOptionTimestamp *option = new TcpOptionTimestamp();
1313 
1314  // Update TS variables
1315  // RFC 1323, page 13: "The Timestamp Value field (TSval) contains the current value of the timestamp clock of the Tcp sending the option."
1316  option->setSenderTimestamp(convertSimtimeToTS(simTime()));
1317 
1318  // RFC 1323, page 16: "(3) When a TSopt is sent, its TSecr field is set to the current TS.Recent value."
1319  // RFC 1323, page 13:
1320  // "The Timestamp Echo Reply field (TSecr) is only valid if the ACK
1321  // bit is set in the Tcp header; if it is valid, it echos a times-
1322  // tamp value that was sent by the remote Tcp in the TSval field
1323  // of a Timestamps option. When TSecr is not valid, its value
1324  // must be zero."
1325  option->setEchoedTimestamp(tcpHeader->getAckBit() ? state->ts_recent : 0);
1326 
1327  state->snd_initial_ts = true;
1329  EV_INFO << "Tcp Header Option TS(TSval=" << option->getSenderTimestamp() << ", TSecr=" << option->getEchoedTimestamp() << ") sent, TS (ts_enabled) is set to " << state->ts_enabled << "\n";
1330  tcpHeader->appendHeaderOption(option);
1331  }
1332 
1333  // TODO add new TCPOptions here once they are implemented
1334  }
1335  else if (fsm.getState() == TCP_S_SYN_SENT || fsm.getState() == TCP_S_SYN_RCVD
1336  || fsm.getState() == TCP_S_ESTABLISHED || fsm.getState() == TCP_S_FIN_WAIT_1
1337  || fsm.getState() == TCP_S_FIN_WAIT_2 || fsm.getState() == TCP_S_CLOSE_WAIT) // connetion is not in INIT or LISTEN state
1338  {
1339  // TS header option
1340  if (state->ts_enabled) { // Is TS enabled?
1341  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
1342  // 2 padding bytes
1343  tcpHeader->appendHeaderOption(new TcpOptionNop()); // NOP
1344  tcpHeader->appendHeaderOption(new TcpOptionNop()); // NOP
1345  }
1346 
1347  TcpOptionTimestamp *option = new TcpOptionTimestamp();
1348 
1349  // Update TS variables
1350  // RFC 1323, page 13: "The Timestamp Value field (TSval) contains the current value of the timestamp clock of the Tcp sending the option."
1351  option->setSenderTimestamp(convertSimtimeToTS(simTime()));
1352 
1353  // RFC 1323, page 16: "(3) When a TSopt is sent, its TSecr field is set to the current TS.Recent value."
1354  // RFC 1323, page 13:
1355  // "The Timestamp Echo Reply field (TSecr) is only valid if the ACK
1356  // bit is set in the Tcp header; if it is valid, it echos a times-
1357  // tamp value that was sent by the remote Tcp in the TSval field
1358  // of a Timestamps option. When TSecr is not valid, its value
1359  // must be zero."
1360  option->setEchoedTimestamp(tcpHeader->getAckBit() ? state->ts_recent : 0);
1361 
1362  EV_INFO << "Tcp Header Option TS(TSval=" << option->getSenderTimestamp() << ", TSecr=" << option->getEchoedTimestamp() << ") sent\n";
1363  tcpHeader->appendHeaderOption(option);
1364  }
1365 
1366  // SACK header option
1367 
1368  // RFC 2018, page 4:
1369  // "If sent at all, SACK options SHOULD be included in all ACKs which do
1370  // not ACK the highest sequence number in the data receiver's queue. In
1371  // this situation the network has lost or mis-ordered data, such that
1372  // the receiver holds non-contiguous data in its queue. RFC 1122,
1373  // Section 4.2.2.21, discusses the reasons for the receiver to send ACKs
1374  // in response to additional segments received in this state. The
1375  // receiver SHOULD send an ACK for every valid segment that arrives
1376  // containing new data, and each of these "duplicate" ACKs SHOULD bear a
1377  // SACK option."
1378  if (state->sack_enabled && (state->snd_sack || state->snd_dsack)) {
1379  addSacks(tcpHeader);
1380  }
1381 
1382  // TODO add new TCPOptions here once they are implemented
1383  // TODO delegate to TcpAlgorithm as well -- it may want to append additional options
1384  }
1385 
1386  if (tcpHeader->getHeaderOptionArraySize() != 0) {
1387  B options_len = tcpHeader->getHeaderOptionArrayLength();
1388 
1389  if (options_len <= TCP_OPTIONS_MAX_SIZE) { // Options length allowed? - maximum: 40 Bytes
1390  tcpHeader->setHeaderLength(TCP_MIN_HEADER_LENGTH + options_len);
1391  tcpHeader->setChunkLength(B(TCP_MIN_HEADER_LENGTH + options_len));
1392  }
1393  else {
1394  tcpHeader->dropHeaderOptions(); // drop all options
1395  tcpHeader->setHeaderLength(TCP_MIN_HEADER_LENGTH);
1396  tcpHeader->setChunkLength(TCP_MIN_HEADER_LENGTH);
1397  EV_ERROR << "ERROR: Options length exceeded! Segment will be sent without options" << "\n";
1398  }
1399  }
1400 
1401  return *tcpHeader;
1402 }

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

Member Data Documentation

◆ connEstabTimer

cMessage* inet::tcp::TcpConnection::connEstabTimer = nullptr
protected

◆ dscp

short inet::tcp::TcpConnection::dscp = -1

Referenced by process_OPTIONS(), and sendToIP().

◆ dupAcksSignal

simsignal_t inet::tcp::TcpConnection::dupAcksSignal = registerSignal("dupAcks")
static

◆ finWait2Timer

cMessage* inet::tcp::TcpConnection::finWait2Timer = nullptr
protected

◆ fsm

◆ listeningSocketId

int inet::tcp::TcpConnection::listeningSocketId = -1

◆ localAddr

◆ localPort

◆ pipeSignal

simsignal_t inet::tcp::TcpConnection::pipeSignal = registerSignal("pipe")
static

Referenced by setPipe().

◆ rcvAckSignal

simsignal_t inet::tcp::TcpConnection::rcvAckSignal = registerSignal("rcvAck")
static

Referenced by process_RCV_SEGMENT().

◆ rcvAdvSignal

simsignal_t inet::tcp::TcpConnection::rcvAdvSignal = registerSignal("rcvAdv")
static

◆ rcvNASegSignal

simsignal_t inet::tcp::TcpConnection::rcvNASegSignal = registerSignal("rcvNASeg")
static

◆ rcvOooSegSignal

simsignal_t inet::tcp::TcpConnection::rcvOooSegSignal = registerSignal("rcvOooSeg")
static

◆ rcvSacksSignal

simsignal_t inet::tcp::TcpConnection::rcvSacksSignal = registerSignal("rcvSacks")
static

Referenced by processSACKOption().

◆ rcvSeqSignal

simsignal_t inet::tcp::TcpConnection::rcvSeqSignal = registerSignal("rcvSeq")
static

Referenced by process_RCV_SEGMENT().

◆ rcvWndSignal

simsignal_t inet::tcp::TcpConnection::rcvWndSignal = registerSignal("rcvWnd")
static

Referenced by updateRcvWnd().

◆ receiveQueue

◆ remoteAddr

◆ remotePort

◆ rexmitQueue

◆ sackedBytesSignal

simsignal_t inet::tcp::TcpConnection::sackedBytesSignal = registerSignal("sackedBytes")
static

Referenced by processSACKOption().

◆ sendQueue

◆ sndAckSignal

simsignal_t inet::tcp::TcpConnection::sndAckSignal = registerSignal("sndAck")
static

Referenced by sendToIP().

◆ sndNxtSignal

simsignal_t inet::tcp::TcpConnection::sndNxtSignal = registerSignal("sndNxt")
static

Referenced by sendToIP().

◆ sndSacksSignal

simsignal_t inet::tcp::TcpConnection::sndSacksSignal = registerSignal("sndSacks")
static

Referenced by addSacks().

◆ sndWndSignal

simsignal_t inet::tcp::TcpConnection::sndWndSignal = registerSignal("sndWnd")
static

Referenced by updateWndInfo().

◆ socketId

◆ state

◆ stateSignal

simsignal_t inet::tcp::TcpConnection::stateSignal = registerSignal("state")
static

◆ synRexmitTimer

cMessage* inet::tcp::TcpConnection::synRexmitTimer = nullptr
protected

◆ tcpAlgorithm

◆ tcpConnectionAddedSignal

simsignal_t inet::tcp::TcpConnection::tcpConnectionAddedSignal
static

◆ tcpMain

◆ tcpRcvPayloadBytesSignal

simsignal_t inet::tcp::TcpConnection::tcpRcvPayloadBytesSignal = registerSignal("tcpRcvPayloadBytes")
static

Referenced by process_RCV_SEGMENT().

◆ tcpRcvQueueBytesSignal

simsignal_t inet::tcp::TcpConnection::tcpRcvQueueBytesSignal = registerSignal("tcpRcvQueueBytes")
static

Referenced by updateRcvQueueVars().

◆ tcpRcvQueueDropsSignal

simsignal_t inet::tcp::TcpConnection::tcpRcvQueueDropsSignal = registerSignal("tcpRcvQueueDrops")
static

◆ the2MSLTimer

cMessage* inet::tcp::TcpConnection::the2MSLTimer = nullptr
protected

◆ tos

short inet::tcp::TcpConnection::tos = -1

Referenced by process_OPTIONS(), and sendToIP().

◆ ttl

int inet::tcp::TcpConnection::ttl = -1

◆ unackedSignal

simsignal_t inet::tcp::TcpConnection::unackedSignal = registerSignal("unacked")
static

The documentation for this class was generated from the following files:
inet::TCP_I_TIMED_OUT
@ TCP_I_TIMED_OUT
Definition: TcpCommand_m.h:133
inet::tcp::TcpConnection::finWait2Timer
cMessage * finWait2Timer
Definition: TcpConnection.h:384
inet::tcp::TcpConnection::process_TIMEOUT_FIN_WAIT_2
virtual void process_TIMEOUT_FIN_WAIT_2()
Definition: TcpConnectionRcvSegment.cc:1317
inet::tcp::TcpStateVariables::ws_manual_scale
int ws_manual_scale
Definition: TcpConnection.h:199
inet::tcp::TcpStateVariables::str
virtual std::string str() const override
Definition: TcpConnectionBase.cc:144
inet::tcp::TcpConnection::getTSval
virtual uint32_t getTSval(const Ptr< const TcpHeader > &tcpHeader) const
Utility: get TSval from segments TS header option.
Definition: TcpConnectionUtil.cc:1404
inet::tcp::TcpConnection::tcpRcvPayloadBytesSignal
static simsignal_t tcpRcvPayloadBytesSignal
Definition: TcpConnection.h:334
inet::ulong
unsigned long ulong
Definition: INETDefs.h:56
inet::tcp::TcpConnection::rcvSacksSignal
static simsignal_t rcvSacksSignal
Definition: TcpConnection.h:328
inet::tcp::TcpConnection::processTimer
virtual bool processTimer(cMessage *msg)
Process self-messages (timers).
Definition: TcpConnectionBase.cc:249
inet::tcp::TCP_E_SETOPTION
@ TCP_E_SETOPTION
Definition: TcpConnection.h:80
inet::tcp::TcpAlgorithm::receivedOutOfOrderSegment
virtual void receivedOutOfOrderSegment()=0
Called after receiving data which are in the window, but not at its left edge (seq !...
inet::tcp::TcpConnection::processSegment1stThru8th
virtual TcpEventCode processSegment1stThru8th(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
Definition: TcpConnectionRcvSegment.cc:125
TCP_TIMEOUT_CONN_ESTAB
#define TCP_TIMEOUT_CONN_ESTAB
Definition: TcpConnection.h:104
inet::tcp::TCP_E_TIMEOUT_CONN_ESTAB
@ TCP_E_TIMEOUT_CONN_ESTAB
Definition: TcpConnection.h:95
inet::tcp::TcpAlgorithm::dataSent
virtual void dataSent(uint32_t fromseq)=0
Called after we sent data.
inet::TCP_C_QUEUE_BYTES_LIMIT
@ TCP_C_QUEUE_BYTES_LIMIT
Definition: TcpCommand_m.h:89
inet::tcp::TcpStateVariables::full_sized_segment_counter
uint32_t full_sized_segment_counter
Definition: TcpConnection.h:184
inet::tcp::Tcp::addForkedConnection
virtual void addForkedConnection(TcpConnection *conn, TcpConnection *newConn, L3Address localAddr, L3Address remoteAddr, int localPort, int remotePort)
Update conn's socket pair, and register newConn (which'll keep LISTENing).
Definition: Tcp.cc:295
inet::tcp::TcpConnection::state
TcpStateVariables * state
Definition: TcpConnection.h:364
inet::TCP_C_SETOPTION
@ TCP_C_SETOPTION
Definition: TcpCommand_m.h:92
inet::tcp::TcpConnection::process_TIMEOUT_CONN_ESTAB
virtual void process_TIMEOUT_CONN_ESTAB()
Definition: TcpConnectionRcvSegment.cc:1275
inet::tcp::TcpSackRexmitQueue::setSackedBit
virtual void setSackedBit(uint32_t fromSeqNum, uint32_t toSeqNum)
Called when data sender received selective acknowledgments.
Definition: TcpSackRexmitQueue.cc:177
inet::tcp::TcpConnection::performStateTransition
virtual bool performStateTransition(const TcpEventCode &event)
Implemements the pure TCP state machine.
Definition: TcpConnectionBase.cc:414
inet::tcp::TcpStateVariables::fin_ack_rcvd
bool fin_ack_rcvd
Definition: TcpConnection.h:171
inet::tcp::TCP_MAX_HEADER_LENGTH
const B TCP_MAX_HEADER_LENGTH
Definition: TcpHeader_m.h:64
inet::tcp::TcpAlgorithm::established
virtual void established(bool active)=0
Called when the connection is going to ESTABLISHED from SYN_SENT or SYN_RCVD.
inet::tcp::TcpConnection::sndWndSignal
static simsignal_t sndWndSignal
Definition: TcpConnection.h:317
inet::tcp::TcpConnection::startSynRexmitTimer
virtual void startSynRexmitTimer()
Utility: start SYN-REXMIT timer.
Definition: TcpConnectionRcvSegment.cc:1332
inet::tcp::TcpConnection::isToBeAccepted
virtual bool isToBeAccepted() const
Utility: returns true if the connection is not yet accepted by the application.
Definition: TcpConnection.h:489
inet::tcp::TcpConnection::process_DESTROY
virtual void process_DESTROY(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:276
inet::TCP_I_CLOSED
@ TCP_I_CLOSED
Definition: TcpCommand_m.h:130
inet::tcp::TcpConnection::isLost
virtual bool isLost(uint32_t seqNum)
For SACK TCP.
Definition: TcpConnectionSackUtil.cc:123
inet::tcp::TcpStateVariables::rcv_naseg
uint32_t rcv_naseg
Definition: TcpConnection.h:240
inet::tcp::TCP_E_RCV_SYN_ACK
@ TCP_E_RCV_SYN_ACK
Definition: TcpConnection.h:86
TCP_TIMEOUT_SYN_REXMIT_MAX
#define TCP_TIMEOUT_SYN_REXMIT_MAX
Definition: TcpConnection.h:107
inet::tcp::TcpConnection::addSacks
virtual TcpHeader addSacks(const Ptr< TcpHeader > &tcpHeader)
Utility: adds SACKs to segments header options field.
Definition: TcpConnectionSackUtil.cc:430
inet::tcp::TcpConnection::isSegmentAcceptable
virtual bool isSegmentAcceptable(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader) const
Utility: check if segment is acceptable (all bytes are in receive window)
Definition: TcpConnectionUtil.cc:486
inet::tcp::TCP_E_RCV_FIN_ACK
@ TCP_E_RCV_FIN_ACK
Definition: TcpConnection.h:88
inet::tcp::TcpAlgorithm::initialize
virtual void initialize()
Should be redefined to initialize the object: create timers, etc.
Definition: TcpAlgorithm.h:70
inet::IP_ECN_NOT_ECT
@ IP_ECN_NOT_ECT
Definition: EcnTag_m.h:59
inet::tcp::TcpSendQueue::getBufferStartSeq
virtual uint32_t getBufferStartSeq() const
Returns the sequence number of the first byte stored in the buffer.
Definition: TcpSendQueue.cc:47
inet::tcp::TcpSackRexmitQueue::detailedInfo
virtual std::string detailedInfo() const
Prints the current rexmitQueue status for debug purposes.
Definition: TcpSackRexmitQueue.cc:40
inet::tcp::TcpStateVariables::limited_transmit_enabled
bool limited_transmit_enabled
Definition: TcpConnection.h:181
inet::tcp::TcpConnection::getState
const TcpStateVariables * getState() const
Definition: TcpConnection.h:613
inet::tcp::TcpSendQueue::createSegmentWithBytes
virtual Packet * createSegmentWithBytes(uint32_t fromSeq, uint32_t numBytes)
Called when the TCP wants to send or retransmit data, it constructs a TCP segment which contains the ...
Definition: TcpSendQueue.cc:62
DscpReq
removed DscpReq Ipv4ControlInfo Ipv6ControlInfo up L3AddressInd DispatchProtocolReq L4PortInd Ipv4ControlInfo Ipv6ControlInfo down DscpReq
Definition: IUdp-gates.txt:25
inet::tcp::Tcp::updateSockPair
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:333
inet::tcp::TcpConnection::sendAck
virtual void sendAck()
Utility: send ACK.
Definition: TcpConnectionUtil.cc:679
inet::tcp::TcpAlgorithm::receivedDuplicateAck
virtual void receivedDuplicateAck()=0
Called after we received a duplicate ACK (that is: ackNo == snd_una, no data in segment,...
inet::Protocol::tcp
static const Protocol tcp
Definition: Protocol.h:112
inet::TCP_I_ESTABLISHED
@ TCP_I_ESTABLISHED
Definition: TcpCommand_m.h:128
inet::tcp::TcpStateVariables::start_seqno
uint32_t start_seqno
Definition: TcpConnection.h:219
inet::tcp::TcpStateVariables::ts_recent
uint32_t ts_recent
Definition: TcpConnection.h:210
inet::tcp::TcpConnection::processTSOption
virtual bool processTSOption(const Ptr< const TcpHeader > &tcpHeader, const TcpOptionTimestamp &option)
Definition: TcpConnectionUtil.cc:1174
inet::tcp::TcpConnection::setSocketId
void setSocketId(int newSocketId)
Definition: TcpConnection.h:339
inet::tcp::TcpAlgorithm::processTimer
virtual void processTimer(cMessage *timer, TcpEventCode &event)=0
Place to process timers specific to this TcpAlgorithm class.
inet::tcp::TcpStateVariables::snd_initial_ts
bool snd_initial_ts
Definition: TcpConnection.h:208
inet::tcp::TCP_OPTION_HEAD_SIZE
const B TCP_OPTION_HEAD_SIZE
Definition: TcpHeader_m.h:67
inet::tcp::TcpConnection::rcvAckSignal
static simsignal_t rcvAckSignal
Definition: TcpConnection.h:323
inet::tcp::TcpConnection::sendRst
virtual void sendRst(uint32_t seqNo)
Utility: sends RST.
Definition: TcpConnectionUtil.cc:632
inet::tcp::TcpAlgorithm::rttMeasurementCompleteUsingTS
virtual void rttMeasurementCompleteUsingTS(uint32_t echoedTS)=0
Converting uint32_t echoedTS to simtime_t and calling rttMeasurementComplete() to update state vars w...
inet::TCP_I_PEER_CLOSED
@ TCP_I_PEER_CLOSED
Definition: TcpCommand_m.h:129
inet::tcp::TcpConnection::process_ABORT
virtual void process_ABORT(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:247
inet::tcp::TcpStateVariables::ws_support
bool ws_support
Definition: TcpConnection.h:197
inet::tcp::TcpStateVariables::snd_dsack
bool snd_dsack
Definition: TcpConnection.h:222
inet::tcp::TcpStateVariables::rcv_ws
bool rcv_ws
Definition: TcpConnection.h:201
inet::tcp::TcpStateVariables::rcv_wnd
uint32_t rcv_wnd
Definition: TcpConnection.h:158
inet::sctp::min
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SctpAssociation.h:261
inet::tcp::TcpStateVariables::freeRcvBuffer
uint32_t freeRcvBuffer
Definition: TcpConnection.h:245
inet::tcp::TcpStateVariables::dupacks
uint32_t dupacks
Definition: TcpConnection.h:236
inet::tcp::Tcp::removeConnection
virtual void removeConnection(TcpConnection *conn)
Definition: Tcp.cc:198
inet::tcp::TcpConnection::cloneListeningConnection
virtual TcpConnection * cloneListeningConnection()
Utility: clone a listening connection.
Definition: TcpConnectionUtil.cc:234
inet::tcp::TcpConnection::TcpConnection
TcpConnection()
Definition: TcpConnection.h:582
inet::tcp::TcpStateVariables::sackedBytes
uint32_t sackedBytes
Definition: TcpConnection.h:227
inet::tcp::TcpStateVariables::rcv_sacks
uint32_t rcv_sacks
Definition: TcpConnection.h:238
inet::tcp::TcpConnection::receiveQueue
TcpReceiveQueue * receiveQueue
Definition: TcpConnection.h:369
inet::tcp::TcpAlgorithm::connectionClosed
virtual void connectionClosed()=0
Called when the connection closes, it should cancel all running timers.
inet::TCP_I_AVAILABLE
@ TCP_I_AVAILABLE
Definition: TcpCommand_m.h:127
inet::tcp::TcpConnection::sendToApp
virtual void sendToApp(cMessage *msg)
Utility: sends packet to application.
Definition: TcpConnectionUtil.cc:382
inet::tcp::TcpConnection::process_READ_REQUEST
virtual void process_READ_REQUEST(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:159
inet::tcp::TCP_E_IGNORE
@ TCP_E_IGNORE
Definition: TcpConnection.h:66
inet::tcp::Tcp::crcMode
CrcMode crcMode
Definition: Tcp.h:135
inet::tcp::TcpConnection::sendSegmentDuringLossRecoveryPhase
virtual uint32_t sendSegmentDuringLossRecoveryPhase(uint32_t seqNum)
Utility: send segment during Loss Recovery phase (if SACK is enabled).
Definition: TcpConnectionSackUtil.cc:360
DispatchProtocolReq
removed DscpReq Ipv4ControlInfo Ipv6ControlInfo up L3AddressInd DispatchProtocolReq L4PortInd Ipv4ControlInfo Ipv6ControlInfo down DispatchProtocolReq
Definition: IUdp-gates.txt:25
inet::tcp::TcpReceiveQueue::extractBytesUpTo
virtual Packet * extractBytesUpTo(uint32_t seq)
Should create a packet to be passed up to the app, up to (but NOT including) the given sequence no (u...
Definition: TcpReceiveQueue.cc:80
inet::tcp::TcpConnection::rcvWndSignal
static simsignal_t rcvWndSignal
Definition: TcpConnection.h:318
inet::tcp::TcpConnection::tcpAlgorithm
TcpAlgorithm * tcpAlgorithm
Definition: TcpConnection.h:378
inet::tcp::TcpStateVariables::sack_support
bool sack_support
Definition: TcpConnection.h:215
inet::tcp::Tcp::createReceiveQueue
virtual TcpReceiveQueue * createReceiveQueue()
To be called from TcpConnection: create a new receive queue.
Definition: Tcp.cc:363
inet::tcp::TcpConnection::process_OPEN_ACTIVE
virtual void process_OPEN_ACTIVE(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:26
inet::TCP_C_ACCEPT
@ TCP_C_ACCEPT
Definition: TcpCommand_m.h:84
inet::tcp::TCPOPTION_SACK_PERMITTED
@ TCPOPTION_SACK_PERMITTED
Definition: TcpHeader_m.h:119
inet::tcp::TcpConnection::sendQueue
TcpSendQueue * sendQueue
Definition: TcpConnection.h:367
inet::tcp::TcpConnection::sendIndicationToApp
virtual void sendIndicationToApp(int code, const int id=0)
Utility: sends status indication (TCP_I_xxx) to application.
Definition: TcpConnectionUtil.cc:341
inet::tcp::TcpConnection::tryFastRoute
virtual bool tryFastRoute(const Ptr< const TcpHeader > &tcpHeader)
Shortcut to process most common case as fast as possible.
Definition: TcpConnectionRcvSegment.cc:22
inet::tcp::TcpStateVariables::irs
uint32_t irs
Definition: TcpConnection.h:160
inet::tcp::TcpConnection::remoteAddr
L3Address remoteAddr
Definition: TcpConnection.h:347
inet::tcp::TCP_E_RCV_ACK
@ TCP_E_RCV_ACK
Definition: TcpConnection.h:84
inet::tcp::TcpConnection::sendSegment
virtual uint32_t sendSegment(uint32_t bytes)
Utility: sends one segment of 'bytes' bytes from snd_nxt, and advances snd_nxt.
Definition: TcpConnectionUtil.cc:744
inet::tcp::TCP_S_INIT
@ TCP_S_INIT
Definition: TcpConnection.h:47
inet::tcp::TcpConnection::process_OPEN_PASSIVE
virtual void process_OPEN_PASSIVE(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:70
inet::tcp::TcpConnection::sndAckSignal
static simsignal_t sndAckSignal
Definition: TcpConnection.h:321
inet::tcp::seqLess
bool seqLess(uint32_t a, uint32_t b)
Definition: TcpHeader.h:21
inet::TCP_I_CONNECTION_RESET
@ TCP_I_CONNECTION_RESET
Definition: TcpCommand_m.h:132
inet::tcp::TcpSackRexmitQueue::setConnection
virtual void setConnection(TcpConnection *_conn)
Set the connection that owns this queue.
Definition: TcpSackRexmitQueue.h:51
inet::tcp::TcpStateVariables::ws_enabled
bool ws_enabled
Definition: TcpConnection.h:198
inet::tcp::TcpStateVariables::ecnEchoState
bool ecnEchoState
Definition: TcpConnection.h:249
inet::tcp::TcpConnection::updateRcvQueueVars
virtual void updateRcvQueueVars()
Utility: update receiver queue related variables and statistics - called before setting rcv_wnd.
Definition: TcpConnectionUtil.cc:1426
inet::tcp::TcpConnection::sackedBytesSignal
static simsignal_t sackedBytesSignal
Definition: TcpConnection.h:331
inet::TCP_I_DATA_NOTIFICATION
@ TCP_I_DATA_NOTIFICATION
Definition: TcpCommand_m.h:136
inet::tcp::seqLE
bool seqLE(uint32_t a, uint32_t b)
Definition: TcpHeader.h:22
inet::tcp::TCP_E_TIMEOUT_2MSL
@ TCP_E_TIMEOUT_2MSL
Definition: TcpConnection.h:94
inet::TCP_I_URGENT_DATA
@ TCP_I_URGENT_DATA
Definition: TcpCommand_m.h:126
inet::tcp::TCP_S_FIN_WAIT_1
@ TCP_S_FIN_WAIT_1
Definition: TcpConnection.h:55
inet::tcp::TcpReceiveQueue::init
virtual void init(uint32_t startSeq)
Set initial receive sequence number.
Definition: TcpReceiveQueue.cc:25
inet::tcp::TcpStateVariables::dupthresh
uint32_t dupthresh
Definition: TcpConnection.h:261
inet::tcp::TcpConnection::rcvAdvSignal
static simsignal_t rcvAdvSignal
Definition: TcpConnection.h:319
inet::tcp::TCP_E_DESTROY
@ TCP_E_DESTROY
Definition: TcpConnection.h:76
inet::utils::createOne
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:147
inet::tcp::TcpConnection::optionName
static const char * optionName(int option)
Utility: returns name of TCPOPTION_xxx constants.
Definition: TcpConnectionUtil.cc:118
inet::tcp::TcpConnection::initConnection
virtual void initConnection(TcpOpenCommand *openCmd)
Utility: creates send/receive queues and tcpAlgorithm.
Definition: TcpConnectionUtil.cc:407
inet::L3Address::isUnspecified
bool isUnspecified() const
Definition: L3Address.cc:138
inet::tcp::TcpSackRexmitQueue::checkRexmitQueueForSackedOrRexmittedSegments
virtual uint32_t checkRexmitQueueForSackedOrRexmittedSegments(uint32_t fromSeq) const
Checks rexmit queue for sacked of rexmitted segments and returns a certain offset (contiguous sacked ...
Definition: TcpSackRexmitQueue.cc:266
inet::tcp::TcpStateVariables::sackedBytes_old
uint32_t sackedBytes_old
Definition: TcpConnection.h:228
inet::tcp::TcpStateVariables::send_fin
bool send_fin
Definition: TcpConnection.h:173
inet::tcp::TcpStateVariables::snd_wnd
uint32_t snd_wnd
Definition: TcpConnection.h:150
TCP_MAX_WIN_SCALED
#define TCP_MAX_WIN_SCALED
Definition: TcpConnection.h:112
inet::tcp::TcpSendQueue::getBytesAvailable
virtual uint32_t getBytesAvailable(uint32_t fromSeq) const
Utility function: returns how many bytes are available in the queue, from (and including) the given s...
Definition: TcpSendQueue.cc:57
inet::tcp::TcpStateVariables::ts_enabled
bool ts_enabled
Definition: TcpConnection.h:207
inet::tcp::TcpAlgorithm::setConnection
void setConnection(TcpConnection *_conn)
Assign this object to a TcpConnection.
Definition: TcpAlgorithm.h:52
inet::tcp::TcpConnection::listeningSocketId
int listeningSocketId
Definition: TcpConnection.h:341
inet::TCP_C_SEND
@ TCP_C_SEND
Definition: TcpCommand_m.h:85
inet::tcp::TcpSendQueue::setConnection
virtual void setConnection(TcpConnection *_conn)
Set the connection that owns this queue.
Definition: TcpSendQueue.h:48
CASE
#define CASE(x)
inet::tcp::TcpConnection::processAckInEstabEtc
virtual bool processAckInEstabEtc(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
Definition: TcpConnectionRcvSegment.cc:1127
inet::tcp::TCP_E_RCV_UNEXP_SYN
@ TCP_E_RCV_UNEXP_SYN
Definition: TcpConnection.h:91
inet::tcp::TcpStateVariables::end_seqno
uint32_t end_seqno
Definition: TcpConnection.h:220
inet::tcp::TcpConnection::preanalyseAppCommandEvent
virtual TcpEventCode preanalyseAppCommandEvent(int commandCode)
Maps app command codes (msg kind of app command msgs) to TCP_E_xxx event codes.
Definition: TcpConnectionBase.cc:373
inet::tcp::TcpSendQueue::enqueueAppData
virtual void enqueueAppData(Packet *msg)
Called on SEND app command, it inserts in the queue the data the user wants to send.
Definition: TcpSendQueue.cc:38
inet::tcp::TcpStateVariables::snd_ws
bool snd_ws
Definition: TcpConnection.h:200
inet::tcp::TcpSackRexmitQueue::enqueueSentData
virtual void enqueueSentData(uint32_t fromSeqNum, uint32_t toSeqNum)
Inserts sent data to the rexmit queue.
Definition: TcpSackRexmitQueue.cc:78
inet::tcp::TcpReceiveQueue::getLE
virtual uint32_t getLE(uint32_t fromSeqNum)
Returns left edge of enqueued region.
Definition: TcpReceiveQueue.cc:130
inet::tcp::TcpSendQueue::discardUpTo
virtual void discardUpTo(uint32_t seqNum)
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed,...
Definition: TcpSendQueue.cc:75
inet::tcp::TcpConnection::process_RCV_SEGMENT
virtual TcpEventCode process_RCV_SEGMENT(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address src, L3Address dest)
Process incoming TCP segment.
Definition: TcpConnectionRcvSegment.cc:78
inet::tcp::TcpConnection::pipeSignal
static simsignal_t pipeSignal
Definition: TcpConnection.h:326
inet::tcp::TcpStateVariables::lossRecovery
bool lossRecovery
Definition: TcpConnection.h:229
inet::tcp::TcpStateVariables::snd_wl2
uint32_t snd_wl2
Definition: TcpConnection.h:153
inet::tcp::TCP_E_OPEN_ACTIVE
@ TCP_E_OPEN_ACTIVE
Definition: TcpConnection.h:70
inet::tcp::TcpConnection::process_STATUS
virtual void process_STATUS(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:283
inet::tcp::TcpStateVariables::last_ack_sent
uint32_t last_ack_sent
Definition: TcpConnection.h:211
inet::units::values::s
value< double, units::s > s
Definition: Units.h:1235
inet::tcp::TCP_OPTIONS_MAX_SIZE
const B TCP_OPTIONS_MAX_SIZE
Definition: TcpHeader_m.h:66
inet::units::units::B
intscale< b, 1, 8 > B
Definition: Units.h:1168
inet::tcp::TcpConnection::process_SEND
virtual void process_SEND(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:112
inet::tcp::TcpStateVariables::sacks_array
SackList sacks_array
Definition: TcpConnection.h:223
inet::tcp::TcpSendQueue::init
virtual void init(uint32_t startSeq)
Initialize the object.
Definition: TcpSendQueue.cc:24
inet::tcp::TcpStateVariables::nagle_enabled
bool nagle_enabled
Definition: TcpConnection.h:179
inet::tcp::TcpConnection::dscp
short dscp
Definition: TcpConnection.h:354
inet::tcp::TcpAlgorithm::ackSent
virtual void ackSent()=0
Called after we sent an ACK.
inet::tcp::TcpConnection::getTSecr
virtual uint32_t getTSecr(const Ptr< const TcpHeader > &tcpHeader) const
Utility: get TSecr from segments TS header option.
Definition: TcpConnectionUtil.cc:1415
inet::tcp::TCPOPTION_WINDOW_SCALE
@ TCPOPTION_WINDOW_SCALE
Definition: TcpHeader_m.h:118
inet::TCP_C_STATUS
@ TCP_C_STATUS
Definition: TcpCommand_m.h:88
inet::tcp::TcpConnection::tos
short tos
Definition: TcpConnection.h:355
inet::tcp::TCP_S_LISTEN
@ TCP_S_LISTEN
Definition: TcpConnection.h:49
inet::tcp::TCP_E_RCV_SYN
@ TCP_E_RCV_SYN
Definition: TcpConnection.h:85
inet::tcp::TcpReceiveQueue::getRE
virtual uint32_t getRE(uint32_t toSeqNum)
Returns right edge of enqueued region.
Definition: TcpReceiveQueue.cc:142
inet::tcp::TcpStateVariables::sndAck
bool sndAck
Definition: TcpConnection.h:257
inet::tcp::Tcp::useDataNotification
bool useDataNotification
Definition: Tcp.h:134
inet::tcp::TcpAlgorithm::restartRexmitTimer
virtual void restartRexmitTimer()=0
Restart REXMIT timer.
inet::tcp::TcpConnection::tcpMain
Tcp * tcpMain
Definition: TcpConnection.h:358
if
if(cwndVector) cwndVector -> record(state->snd_cwnd)
inet::tcp::TcpConnection::localPort
int localPort
Definition: TcpConnection.h:349
inet::tcp::TcpStateVariables::time_last_data_sent
simtime_t time_last_data_sent
Definition: TcpConnection.h:212
inet::tcp::TcpConnection::selectInitialSeqNum
virtual void selectInitialSeqNum()
Utility: generates ISS and initializes corresponding state variables.
Definition: TcpConnectionUtil.cc:475
inet::tcp::TcpConnection::sendEstabIndicationToApp
virtual void sendEstabIndicationToApp()
Utility: sends TCP_I_ESTABLISHED indication with TcpConnectInfo to application.
Definition: TcpConnectionUtil.cc:368
inet::tcp::TcpConnection::connEstabTimer
cMessage * connEstabTimer
Definition: TcpConnection.h:383
inet::tcp::TCP_S_CLOSED
@ TCP_S_CLOSED
Definition: TcpConnection.h:48
inet::tcp::Tcp::createSendQueue
virtual TcpSendQueue * createSendQueue()
To be called from TcpConnection: create a new send queue.
Definition: Tcp.cc:358
inet::tcp::TCP_S_ESTABLISHED
@ TCP_S_ESTABLISHED
Definition: TcpConnection.h:52
inet::tcp::TcpReceiveQueue::insertBytesFromSegment
virtual uint32_t insertBytesFromSegment(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
Called when a TCP segment arrives, it should extract the payload from the segment and store it in the...
Definition: TcpReceiveQueue.cc:44
inet::insertTransportProtocolHeader
void insertTransportProtocolHeader(Packet *packet, const Protocol &protocol, const Ptr< TransportHeaderBase > &header)
Definition: L4Tools.cc:77
inet::tcp::TCP_S_SYN_RCVD
@ TCP_S_SYN_RCVD
Definition: TcpConnection.h:51
inet::tcp::TcpStateVariables::snd_fin_seq
uint32_t snd_fin_seq
Definition: TcpConnection.h:174
inet::tcp::TcpStateVariables::tcpRcvQueueDrops
uint32_t tcpRcvQueueDrops
Definition: TcpConnection.h:246
inet::TCP_C_READ
@ TCP_C_READ
Definition: TcpCommand_m.h:90
HopLimitReq
removed HopLimitReq
Definition: IUdp-gates.txt:11
inet::tcp::TcpConnection::tcpRcvQueueDropsSignal
static simsignal_t tcpRcvQueueDropsSignal
Definition: TcpConnection.h:333
inet::tcp::TcpConnection::sendToIP
virtual void sendToIP(Packet *tcpSegment, const Ptr< TcpHeader > &tcpHeader)
Utility: adds control info to segment and sends it to IP.
Definition: TcpConnectionUtil.cc:246
inet::tcp::TcpStateVariables::snd_sacks
uint32_t snd_sacks
Definition: TcpConnection.h:237
inet::tcp::TcpStateVariables::ect
bool ect
Definition: TcpConnection.h:253
inet::tcp::TcpConnection::sendSynAck
virtual void sendSynAck()
Utility: send SYN+ACK.
Definition: TcpConnectionUtil.cc:581
inet::tcp::TcpStateVariables::afterRto
bool afterRto
Definition: TcpConnection.h:194
inet::tcp::TCP_E_SEND
@ TCP_E_SEND
Definition: TcpConnection.h:73
inet::tcp::TcpConnection::configureStateVariables
virtual void configureStateVariables()
Utility: set snd_mss, rcv_wnd and sack in newly created state variables block.
Definition: TcpConnectionUtil.cc:436
MAX_SYN_REXMIT_COUNT
#define MAX_SYN_REXMIT_COUNT
Definition: TcpConnection.h:110
inet::tcp::TcpSackRexmitQueue::discardUpTo
virtual void discardUpTo(uint32_t seqNum)
Tells the queue that bytes up to (but NOT including) seqNum have been transmitted and ACKed,...
Definition: TcpSackRexmitQueue.cc:56
inet::tcp::seqGE
bool seqGE(uint32_t a, uint32_t b)
Definition: TcpHeader.h:24
inet::tcp::TcpConnection::process_OPTIONS
virtual void process_OPTIONS(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:172
TCP_TIMEOUT_SYN_REXMIT
#define TCP_TIMEOUT_SYN_REXMIT
Definition: TcpConnection.h:106
inet::tcp::TcpConnection::processWSOption
virtual bool processWSOption(const Ptr< const TcpHeader > &tcpHeader, const TcpOptionWindowScale &option)
Definition: TcpConnectionUtil.cc:1149
inet::tcp::TcpConnection::rcvSeqSignal
static simsignal_t rcvSeqSignal
Definition: TcpConnection.h:322
inet::tcp::TCP_E_STATUS
@ TCP_E_STATUS
Definition: TcpConnection.h:77
inet::TCP_C_OPEN_PASSIVE
@ TCP_C_OPEN_PASSIVE
Definition: TcpCommand_m.h:83
inet::tcp::TcpConnection::socketId
int socketId
Definition: TcpConnection.h:337
inet::tcp::TcpReceiveQueue::setConnection
virtual void setConnection(TcpConnection *_conn)
Set the connection that owns this queue.
Definition: TcpReceiveQueue.h:67
inet::tcp::TcpStateVariables::snd_nxt
uint32_t snd_nxt
Definition: TcpConnection.h:148
inet::tcp::TCP_S_CLOSE_WAIT
@ TCP_S_CLOSE_WAIT
Definition: TcpConnection.h:53
inet::tcp::TcpStateVariables::sack_enabled
bool sack_enabled
Definition: TcpConnection.h:216
inet::tcp::TcpStateVariables::ts_support
bool ts_support
Definition: TcpConnection.h:206
inet::tcp::TcpSackRexmitQueue::getAmountOfSackedBytes
virtual uint32_t getAmountOfSackedBytes(uint32_t seqNum) const
Returns amount of sacked bytes above seqNum.
Definition: TcpSackRexmitQueue.cc:314
inet::tcp::TCP_S_TIME_WAIT
@ TCP_S_TIME_WAIT
Definition: TcpConnection.h:58
inet::tcp::TcpStateVariables::snd_wl1
uint32_t snd_wl1
Definition: TcpConnection.h:152
PAWS_IDLE_TIME_THRESH
#define PAWS_IDLE_TIME_THRESH
Definition: TcpConnection.h:114
inet::tcp::TcpConnection::printConnBrief
virtual void printConnBrief() const
Utility: prints local/remote addr/port and app gate index/socketId.
Definition: TcpConnectionUtil.cc:147
inet::tcp::TcpStateVariables::ecnSynSent
bool ecnSynSent
Definition: TcpConnection.h:255
inet::tcp::TcpSackRexmitQueue::getBufferEndSeq
virtual uint32_t getBufferEndSeq() const
Returns the sequence number of the last byte stored in the buffer plus one.
Definition: TcpSackRexmitQueue.h:82
kind
removed DscpReq kind
Definition: IUdp-gates.txt:12
inet::tcp::TcpConnection::unackedSignal
static simsignal_t unackedSignal
Definition: TcpConnection.h:324
TCP_MAX_WIN
#define TCP_MAX_WIN
Definition: TcpConnection.h:111
inet::tcp::TcpConnection::rcvNASegSignal
static simsignal_t rcvNASegSignal
Definition: TcpConnection.h:330
inet::tcp::TcpStateVariables::maxRcvBuffer
uint32_t maxRcvBuffer
Definition: TcpConnection.h:243
inet::tcp::TcpStateVariables::rcv_oooseg
uint32_t rcv_oooseg
Definition: TcpConnection.h:239
inet::tcp::TcpConnection::remotePort
int remotePort
Definition: TcpConnection.h:350
inet::tcp::TcpStateVariables::syn_rexmit_timeout
simtime_t syn_rexmit_timeout
Definition: TcpConnection.h:166
inet::tcp::TCP_OPTION_SACK_ENTRY_SIZE
const B TCP_OPTION_SACK_ENTRY_SIZE
Definition: TcpHeader_m.h:69
inet::tcp::TcpSackRexmitQueue::getHighestSackedSeqNum
virtual uint32_t getHighestSackedSeqNum() const
Returns the highest sequence number sacked by data receiver.
Definition: TcpSackRexmitQueue.cc:246
inet::tcp::TcpAlgorithm::sendCommandInvoked
virtual void sendCommandInvoked()=0
Called after user sent TCP_C_SEND command to us.
inet::tcp::TcpReceiveQueue::getQueueLength
virtual uint32_t getQueueLength()
Returns the number of blocks currently buffered in queue.
Definition: TcpReceiveQueue.cc:120
inet::TCP_C_CLOSE
@ TCP_C_CLOSE
Definition: TcpCommand_m.h:86
inet::tcp::TCPOPTION_MAXIMUM_SEGMENT_SIZE
@ TCPOPTION_MAXIMUM_SEGMENT_SIZE
Definition: TcpHeader_m.h:117
inet::tcp::TcpConnection::updateRcvWnd
virtual unsigned short updateRcvWnd()
Utility: update receive window (rcv_wnd), and calculate scaled value if window scaling enabled.
Definition: TcpConnectionUtil.cc:1438
inet::tcp::TcpConnection::eventName
static const char * eventName(int event)
Utility: returns name of TCP_E_xxx constants.
Definition: TcpConnectionUtil.cc:65
inet::tcp::TcpStateVariables::highRxt
uint32_t highRxt
Definition: TcpConnection.h:224
inet::tcp::TcpConnection::indicationName
static const char * indicationName(int code)
Utility: returns name of TCP_I_xxx constants.
Definition: TcpConnectionUtil.cc:96
inet::tcp::TcpConnection::nextSeg
virtual bool nextSeg(uint32_t &seqNum)
For SACK TCP.
Definition: TcpConnectionSackUtil.cc:208
inet::tcp::TcpConnection::dupAcksSignal
static simsignal_t dupAcksSignal
Definition: TcpConnection.h:325
inet::tcp::TcpReceiveQueue::getFirstSeqNo
virtual uint32_t getFirstSeqNo()
Returns the minimum of first byte seq.no.
Definition: TcpReceiveQueue.cc:154
inet::tcp::TCPOPTION_TIMESTAMP
@ TCPOPTION_TIMESTAMP
Definition: TcpHeader_m.h:121
inet::TCP_C_ABORT
@ TCP_C_ABORT
Definition: TcpCommand_m.h:87
inet::tcp::TcpAlgorithm::segmentRetransmitted
virtual void segmentRetransmitted(uint32_t fromseq, uint32_t toseq)=0
Called after we retransmitted segment.
inet::tcp::TcpSackRexmitQueue::getHighestRexmittedSeqNum
virtual uint32_t getHighestRexmittedSeqNum() const
Returns the highest sequence number rexmitted by data sender.
Definition: TcpSackRexmitQueue.cc:256
inet::tcp::TcpStateVariables::snd_mss
uint32_t snd_mss
Definition: TcpConnection.h:142
inet::TCP_C_DESTROY
@ TCP_C_DESTROY
Definition: TcpCommand_m.h:91
inet::tcp::TcpAlgorithm::receivedAckForDataNotYetSent
virtual void receivedAckForDataNotYetSent(uint32_t seq)=0
Called after we received an ACK for data not yet sent.
inet::tcp::TcpStateVariables::fork
bool fork
Definition: TcpConnection.h:140
inet::tcp::TcpSendQueue::getBufferEndSeq
virtual uint32_t getBufferEndSeq() const
Returns the sequence number of the last byte stored in the buffer plus one.
Definition: TcpSendQueue.cc:52
inet::tcp::TcpConnection::ttl
int ttl
Definition: TcpConnection.h:353
inet::tcp::TcpConnection::printSegmentBrief
static void printSegmentBrief(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
Utility: prints important header fields.
Definition: TcpConnectionUtil.cc:156
inet::tcp::TcpConnection::processSACKOption
virtual bool processSACKOption(const Ptr< const TcpHeader > &tcpHeader, const TcpOptionSack &option)
Definition: TcpConnectionSackUtil.cc:29
inet::tcp::TcpConnection::process_CLOSE
virtual void process_CLOSE(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:190
inet::tcp::TcpConnection::readHeaderOptions
virtual void readHeaderOptions(const Ptr< const TcpHeader > &tcpHeader)
Utility: readHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are impleme...
Definition: TcpConnectionUtil.cc:1062
inet::tcp::TcpConnection::processRstInSynReceived
virtual TcpEventCode processRstInSynReceived(const Ptr< const TcpHeader > &tcpHeader)
Definition: TcpConnectionRcvSegment.cc:1096
inet::tcp::TcpAlgorithm::receivedDataAck
virtual void receivedDataAck(uint32_t firstSeqAcked)=0
Called after we received an ACK which acked some data (that is, we could advance snd_una).
inet::tcp::TcpConnection::fsm
cFSM fsm
Definition: TcpConnection.h:361
inet::tcp::TcpSackRexmitQueue::init
virtual void init(uint32_t seqNum)
Initialize the object.
Definition: TcpSackRexmitQueue.cc:26
Enter_Method
#define Enter_Method(...)
Definition: SelfDoc.h:71
inet::tcp::TcpStateVariables::queueUpdate
bool queueUpdate
Definition: TcpConnection.h:233
inet::tcp::TcpAlgorithm::processEcnInEstablished
virtual void processEcnInEstablished()=0
Called before processing segment in established state.
inet::tcp::TcpStateVariables::increased_IW_enabled
bool increased_IW_enabled
Definition: TcpConnection.h:182
inet::tcp::TcpStateVariables::syn_rexmit_count
int syn_rexmit_count
Definition: TcpConnection.h:165
inet::tcp::TcpStateVariables::fin_rcvd
bool fin_rcvd
Definition: TcpConnection.h:176
inet::tcp::TcpConnection::processSynInListen
virtual TcpEventCode processSynInListen(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address srcAddr, L3Address destAddr)
Definition: TcpConnectionRcvSegment.cc:799
inet::tcp::Tcp::sendFromConn
virtual void sendFromConn(cMessage *msg, const char *gatename, int gateindex=-1)
Definition: Tcp.cc:118
inet::tcp::TcpStateVariables::rcv_wnd_scale
uint rcv_wnd_scale
Definition: TcpConnection.h:202
inet::tcp::TcpConnection::sendFin
virtual void sendFin()
Utility: sends FIN.
Definition: TcpConnectionUtil.cc:724
inet::tcp::TcpReceiveQueue::getAmountOfFreeBytes
virtual uint32_t getAmountOfFreeBytes(uint32_t maxRcvBuffer)
Returns the number of bytes currently free (=available) in queue.
Definition: TcpReceiveQueue.cc:113
inet::tcp::Tcp::tcpConnectionAddedSignal
static simsignal_t tcpConnectionAddedSignal
Definition: Tcp.h:87
inet::tcp::TcpConnection::sndSacksSignal
static simsignal_t sndSacksSignal
Definition: TcpConnection.h:327
inet::tcp::TcpConnection::synRexmitTimer
cMessage * synRexmitTimer
Definition: TcpConnection.h:385
inet::tcp::TcpConnection::processSegmentInSynSent
virtual TcpEventCode processSegmentInSynSent(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address src, L3Address dest)
Definition: TcpConnectionRcvSegment.cc:872
inet::tcp::TcpStateVariables::sndCwr
bool sndCwr
Definition: TcpConnection.h:250
inet::tcp::TCP_OPTION_TS_SIZE
const B TCP_OPTION_TS_SIZE
Definition: TcpHeader_m.h:70
inet::tcp::TcpStateVariables::sendQueueLimit
uint32_t sendQueueLimit
Definition: TcpConnection.h:232
inet::tcp::TcpEventCode
TcpEventCode
Definition: TcpConnection.h:65
inet::tcp::TcpConnection::sendAvailableIndicationToApp
virtual void sendAvailableIndicationToApp()
Utility: sends TCP_I_AVAILABLE indication with TcpAvailableInfo to application.
Definition: TcpConnectionUtil.cc:352
inet::tcp::TcpSackRexmitQueue::checkSackBlock
virtual void checkSackBlock(uint32_t seqNum, uint32_t &length, bool &sacked, bool &rexmitted) const
Definition: TcpSackRexmitQueue.cc:362
inet::tcp::TCP_E_ABORT
@ TCP_E_ABORT
Definition: TcpConnection.h:75
inet::tcp::TcpConnection::rcvOooSegSignal
static simsignal_t rcvOooSegSignal
Definition: TcpConnection.h:329
inet::tcp::TcpConnection::process_TIMEOUT_2MSL
virtual void process_TIMEOUT_2MSL()
Definition: TcpConnectionRcvSegment.cc:1295
inet::tcp::TcpConnection::process_TIMEOUT_SYN_REXMIT
virtual void process_TIMEOUT_SYN_REXMIT(TcpEventCode &event)
Definition: TcpConnectionRcvSegment.cc:1339
inet::tcp::TcpConnection::processSegmentInListen
virtual TcpEventCode processSegmentInListen(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader, L3Address src, L3Address dest)
Definition: TcpConnectionRcvSegment.cc:724
inet::tcp::TCP_E_ACCEPT
@ TCP_E_ACCEPT
Definition: TcpConnection.h:72
inet::tcp::TcpSackRexmitQueue::getTotalAmountOfSackedBytes
virtual uint32_t getTotalAmountOfSackedBytes() const
Returns total amount of sacked bytes.
Definition: TcpSackRexmitQueue.cc:302
inet::L3Address::getAddressType
IL3AddressType * getAddressType() const
Definition: L3Address.cc:59
inet::tcp::TcpConnection::sendRstAck
virtual void sendRstAck(uint32_t seq, uint32_t ack, L3Address src, L3Address dest, int srcPort, int destPort)
Utility: sends RST+ACK; does not use connection state.
Definition: TcpConnectionUtil.cc:655
inet::tcp::TCPOPTION_END_OF_OPTION_LIST
@ TCPOPTION_END_OF_OPTION_LIST
Definition: TcpHeader_m.h:115
inet::tcp::TcpStateVariables::snd_sack_perm
bool snd_sack_perm
Definition: TcpConnection.h:217
inet::tcp::TcpConnection::tcpRcvQueueBytesSignal
static simsignal_t tcpRcvQueueBytesSignal
Definition: TcpConnection.h:332
inet::tcp::TcpStateVariables::rcv_nxt
uint32_t rcv_nxt
Definition: TcpConnection.h:157
inet::tcp::TcpStateVariables::rcv_sack_perm
bool rcv_sack_perm
Definition: TcpConnection.h:218
inet::tcp::TcpStateVariables::ack_now
bool ack_now
Definition: TcpConnection.h:185
inet::tcp::TCP_E_CLOSE
@ TCP_E_CLOSE
Definition: TcpConnection.h:74
inet::tcp::TcpStateVariables::rcv_adv
uint32_t rcv_adv
Definition: TcpConnection.h:161
inet::tcp::TCP_E_RCV_FIN
@ TCP_E_RCV_FIN
Definition: TcpConnection.h:87
inet::tcp::TcpAlgorithm::receiveSeqChanged
virtual void receiveSeqChanged()=0
Called after rcv_nxt got advanced, either because we received in-sequence data ("text" in RFC 793 lin...
inet::tcp::TCP_E_READ
@ TCP_E_READ
Definition: TcpConnection.h:79
inet::tcp::TCPOPTION_SACK
@ TCPOPTION_SACK
Definition: TcpHeader_m.h:120
inet::tcp::TcpConnection::convertSimtimeToTS
static uint32_t convertSimtimeToTS(simtime_t simtime)
Utility: converts a given simtime to a timestamp (TS).
Definition: TcpConnectionUtil.cc:1589
inet::tcp::TcpStateVariables::snd_wnd_scale
uint snd_wnd_scale
Definition: TcpConnection.h:203
inet::tcp::TCP_S_LAST_ACK
@ TCP_S_LAST_ACK
Definition: TcpConnection.h:54
inet::tcp::TcpStateVariables::rcv_initial_ts
bool rcv_initial_ts
Definition: TcpConnection.h:209
inet::TCP_I_STATUS
@ TCP_I_STATUS
Definition: TcpCommand_m.h:134
inet::tcp::TcpStateVariables::ecnWillingness
bool ecnWillingness
Definition: TcpConnection.h:256
inet::tcp::TcpConnection::hasEnoughSpaceForSegmentInReceiveQueue
virtual bool hasEnoughSpaceForSegmentInReceiveQueue(Packet *tcpSegment, const Ptr< const TcpHeader > &tcpHeader)
Utility: returns true when receive queue has enough space for store the tcpHeader.
Definition: TcpConnectionRcvSegment.cc:109
inet::tcp::TcpStateVariables::gotEce
bool gotEce
Definition: TcpConnection.h:251
inet::uint
unsigned int uint
Definition: INETDefs.h:55
inet::tcp::TCP_E_RCV_DATA
@ TCP_E_RCV_DATA
Definition: TcpConnection.h:83
inet::tcp::TcpConnection::processMSSOption
virtual bool processMSSOption(const Ptr< const TcpHeader > &tcpHeader, const TcpOptionMaxSegmentSize &option)
Definition: TcpConnectionUtil.cc:1114
inet::tcp::TCP_E_TIMEOUT_FIN_WAIT_2
@ TCP_E_TIMEOUT_FIN_WAIT_2
Definition: TcpConnection.h:96
inet::TCP_I_DATA
@ TCP_I_DATA
Definition: TcpCommand_m.h:125
inet::tcp::TcpConnection::process_QUEUE_BYTES_LIMIT
virtual void process_QUEUE_BYTES_LIMIT(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:320
inet::tcp::TcpConnection::process_ACCEPT
virtual void process_ACCEPT(TcpEventCode &event, TcpCommand *tcpCommand, cMessage *msg)
Definition: TcpConnectionEventProc.cc:102
inet::tcp::TcpConnection::sndNxtSignal
static simsignal_t sndNxtSignal
Definition: TcpConnection.h:320
inet::tcp::TcpReceiveQueue::getAmountOfBufferedBytes
virtual uint32_t getAmountOfBufferedBytes()
Returns the number of bytes (out-of-order-segments) currently buffered in queue.
Definition: TcpReceiveQueue.cc:103
inet::tcp::TCP_S_CLOSING
@ TCP_S_CLOSING
Definition: TcpConnection.h:57
inet::tcp::TCP_E_QUEUE_BYTES_LIMIT
@ TCP_E_QUEUE_BYTES_LIMIT
Definition: TcpConnection.h:78
inet::tcp::TcpStateVariables::snd_una
uint32_t snd_una
Definition: TcpConnection.h:147
inet::tcp::TcpStateVariables::active
bool active
Definition: TcpConnection.h:139
inet::tcp::TcpConnection::the2MSLTimer
cMessage * the2MSLTimer
Definition: TcpConnection.h:382
inet::tcp::TCP_S_SYN_SENT
@ TCP_S_SYN_SENT
Definition: TcpConnection.h:50
inet::tcp::TcpStateVariables::snd_sack
bool snd_sack
Definition: TcpConnection.h:221
inet::tcp::TcpStateVariables::rcv_up
uint32_t rcv_up
Definition: TcpConnection.h:159
inet::tcp::TcpStateVariables::endPointIsWillingECN
bool endPointIsWillingECN
Definition: TcpConnection.h:254
inet::tcp::TcpConnection::stateName
static const char * stateName(int state)
Utility: returns name of TCP_S_xxx constants.
Definition: TcpConnectionUtil.cc:42
inet::tcp::TcpConnection::processSACKPermittedOption
virtual bool processSACKPermittedOption(const Ptr< const TcpHeader > &tcpHeader, const TcpOptionSackPermitted &option)
Definition: TcpConnectionUtil.cc:1222
inet::tcp::TcpStateVariables::usedRcvBuffer
uint32_t usedRcvBuffer
Definition: TcpConnection.h:244
inet::tcp::TcpAlgorithm::shouldMarkAck
virtual bool shouldMarkAck()=0
Called before sending ACK.
inet::tcp::TcpConnection::rexmitQueue
TcpSackRexmitQueue * rexmitQueue
Definition: TcpConnection.h:373
inet::tcp::TcpConnection::localAddr
L3Address localAddr
Definition: TcpConnection.h:345
inet::tcp::TcpStateVariables::rcv_fin_seq
uint32_t rcv_fin_seq
Definition: TcpConnection.h:177
inet::tcp::TCP_MIN_HEADER_LENGTH
const B TCP_MIN_HEADER_LENGTH
Definition: TcpHeader_m.h:63
inet::TCP_I_SEND_MSG
@ TCP_I_SEND_MSG
Definition: TcpCommand_m.h:135
inet::tcp::TcpStateVariables::pipe
uint32_t pipe
Definition: TcpConnection.h:225
inet::tcp::TcpConnection::sendAvailableDataToApp
virtual void sendAvailableDataToApp()
Utility: sends data or data notification to application.
Definition: TcpConnectionUtil.cc:387
inet::tcp::seqGreater
bool seqGreater(uint32_t a, uint32_t b)
Definition: TcpHeader.h:23
inet::tcp::TCPOPTION_NO_OPERATION
@ TCPOPTION_NO_OPERATION
Definition: TcpHeader_m.h:116
inet::tcp::TcpConnection::writeHeaderOptions
virtual TcpHeader writeHeaderOptions(const Ptr< TcpHeader > &tcpHeader)
Utility: writeHeaderOptions (Currently only EOL, NOP, MSS, WS, SACK_PERMITTED, SACK and TS are implem...
Definition: TcpConnectionUtil.cc:1240
inet::tcp::TcpStateVariables::iss
uint32_t iss
Definition: TcpConnection.h:154
inet::tcp::TcpConnection::stateEntered
virtual void stateEntered(int state, int oldState, TcpEventCode event)
Perform cleanup necessary when entering a new state, e.g.
Definition: TcpConnectionBase.cc:692
inet::tcp::TcpStateVariables::snd_up
uint32_t snd_up
Definition: TcpConnection.h:151
inet::tcp::Tcp::getEphemeralPort
virtual ushort getEphemeralPort()
To be called from TcpConnection: reserves an ephemeral port for the connection.
Definition: Tcp.cc:274
inet::tcp::TcpConnection::sendSyn
virtual void sendSyn()
Utility: send SYN.
Definition: TcpConnectionUtil.cc:538
inet::tcp::TcpAlgorithm::getStateVariables
TcpStateVariables * getStateVariables()
Creates and returns the TCP state variables.
Definition: TcpAlgorithm.h:57
inet::tcp::TCP_E_RCV_RST
@ TCP_E_RCV_RST
Definition: TcpConnection.h:89
inet::tcp::TCP_S_FIN_WAIT_2
@ TCP_S_FIN_WAIT_2
Definition: TcpConnection.h:56
inet::IP_ECN_ECT_1
@ IP_ECN_ECT_1
Definition: EcnTag_m.h:60
inet::tcp::Tcp::getMsl
int getMsl()
Definition: Tcp.h:198
inet::tcp::TcpSackRexmitQueue::getNumOfDiscontiguousSacks
virtual uint32_t getNumOfDiscontiguousSacks(uint32_t seqNum) const
Returns the number of discontiguous sacked regions (SACKed sequences) above seqNum.
Definition: TcpSackRexmitQueue.cc:335
inet::tcp::TcpConnection::updateWndInfo
virtual void updateWndInfo(const Ptr< const TcpHeader > &tcpHeader, bool doAlways=false)
Utility: update window information (snd_wnd, snd_wl1, snd_wl2)
Definition: TcpConnectionUtil.cc:1486
inet::tcp::TCP_E_OPEN_PASSIVE
@ TCP_E_OPEN_PASSIVE
Definition: TcpConnection.h:71
inet::tcp::TcpStateVariables::snd_max
uint32_t snd_max
Definition: TcpConnection.h:149
inet::tcp::TcpStateVariables::rexmit
bool rexmit
Definition: TcpConnection.h:258
inet::tcp::TCP_OPTION_SACK_MIN_SIZE
const B TCP_OPTION_SACK_MIN_SIZE
Definition: TcpHeader_m.h:68
inet::tcp::Tcp::addSockPair
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:304
inet::TCP_I_CONNECTION_REFUSED
@ TCP_I_CONNECTION_REFUSED
Definition: TcpCommand_m.h:131
inet::TCP_C_OPEN_ACTIVE
@ TCP_C_OPEN_ACTIVE
Definition: TcpCommand_m.h:82
inet::tcp::TcpStateVariables::delayed_acks_enabled
bool delayed_acks_enabled
Definition: TcpConnection.h:180