--- a/src/internet/model/tcp-rx-buffer.cc +++ a/src/internet/model/tcp-rx-buffer.cc @@ -102,7 +102,7 @@ TcpRxBuffer::IncNextRxSequence () NS_LOG_FUNCTION (this); // Increment nextRxSeq is valid only if we don't have any data buffered, // this is supposed to be called only during the three-way handshake - NS_ASSERT (m_size == 0); + NS_ASSERT (m_size == (uint32_t)0); m_nextRxSeq++; } @@ -138,12 +138,12 @@ TcpRxBuffer::Finished (void) } bool -TcpRxBuffer::Add (Ptr p, TcpHeader const& tcph) +TcpRxBuffer::Add (Ptr p, SequenceNumber32 const& _headSeq) { - NS_LOG_FUNCTION (this << p << tcph); + NS_LOG_FUNCTION (this << p << _headSeq); uint32_t pktSize = p->GetSize (); - SequenceNumber32 headSeq = tcph.GetSequenceNumber (); + SequenceNumber32 headSeq = _headSeq; SequenceNumber32 tailSeq = headSeq + SequenceNumber32 (pktSize); NS_LOG_LOGIC ("Add pkt " << p << " len=" << pktSize << " seq=" << headSeq << ", when NextRxSeq=" << m_nextRxSeq << ", buffsize=" << m_size); @@ -188,7 +188,7 @@ TcpRxBuffer::Add (Ptr p, TcpHeader const& tcph) } else { - uint32_t start = headSeq - tcph.GetSequenceNumber (); + uint32_t start = headSeq - _headSeq; uint32_t length = tailSeq - headSeq; p = p->CreateFragment (start, length); NS_ASSERT (length == p->GetSize ()); --- a/src/internet/model/tcp-rx-buffer.h +++ a/src/internet/model/tcp-rx-buffer.h @@ -54,7 +54,7 @@ public: // Accessors /** - * \brief Get Next Rx Sequence number + * \brief Get Next in-order Rx Sequence number (RCV.NXT) * \returns Next Rx Sequence number */ SequenceNumber32 NextRxSequence (void) const; @@ -78,12 +78,12 @@ public: */ void SetFinSequence (const SequenceNumber32& s); /** - * \brief Get the Maximum buffer size + * \brief Get the Maximum buffer size (in bytes) * \returns the Maximum buffer size */ uint32_t MaxBufferSize (void) const; /** - * \brief Set the Maximum buffer size + * \brief Set the Maximum buffer size (in bytes) * \param s the Maximum buffer size */ void SetMaxBufferSize (uint32_t s); @@ -114,7 +114,7 @@ public: * \param tcph packet's TCP header * \return True when success, false otherwise. */ - bool Add (Ptr p, TcpHeader const& tcph); + bool Add (Ptr p, SequenceNumber32 const& headSeq); /** * Extract data from the head of the buffer as indicated by nextRxSeq. --- a/src/internet/model/tcp-socket-base.cc +++ a/src/internet/model/tcp-socket-base.cc @@ -180,11 +180,22 @@ TcpSocketBase::GetTypeId (void) "Receive tcp packet from IP protocol", MakeTraceSourceAccessor (&TcpSocketBase::m_rxTrace), "ns3::TcpSocketBase::TcpTxRxTracedCallback") + .AddTraceSource("UnackSequence", + "First unacknowledged sequence number (SND.UNA)", + MakeTraceSourceAccessor(&TcpSocketBase::m_firstTxUnack), + "ns3::SequenceNumber32TracedValueCallback") + ; return tid; } -// TcpSocketState +TypeId +TcpSocketBase::GetInstanceTypeId () const +{ + return TcpSocketBase::GetTypeId(); +} + + TypeId TcpSocketState::GetTypeId (void) { @@ -332,6 +343,8 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock) m_endPoint6 (0), m_node (sock.m_node), m_tcp (sock.m_tcp), + m_rtt (0), + m_firstTxUnack (sock.m_firstTxUnack), m_nextTxSequence (sock.m_nextTxSequence), m_highTxMark (sock.m_highTxMark), m_state (sock.m_state), @@ -469,6 +482,12 @@ TcpSocketBase::GetNode (void) const return m_node; } +SequenceNumber32 +TcpSocketBase::FirstUnackedSeq () const +{ + return m_firstTxUnack.Get(); +} + /* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */ int TcpSocketBase::Bind (void) @@ -577,14 +596,14 @@ TcpSocketBase::Bind (const Address &address) void TcpSocketBase::InitializeCwnd (void) { - m_tcb->m_cWnd = m_tcb->m_initialCWnd * m_tcb->m_segmentSize; - m_tcb->m_ssThresh = m_tcb->m_initialSsThresh; + m_tcb->m_cWnd = GetInitialCwnd() * GetSegSize(); + m_tcb->m_ssThresh = GetInitialSSThresh(); } void TcpSocketBase::SetInitialSSThresh (uint32_t threshold) { - NS_ABORT_MSG_UNLESS (m_state == CLOSED, + NS_ABORT_MSG_UNLESS ( (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh, "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started."); m_tcb->m_initialSsThresh = threshold; @@ -599,7 +618,7 @@ TcpSocketBase::GetInitialSSThresh (void) const void TcpSocketBase::SetInitialCwnd (uint32_t cwnd) { - NS_ABORT_MSG_UNLESS (m_state == CLOSED, + NS_ABORT_MSG_UNLESS ( (m_state == CLOSED) || cwnd == m_tcb->m_initialCWnd, "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started."); m_tcb->m_initialCWnd = cwnd; @@ -643,7 +662,8 @@ TcpSocketBase::Connect (const Address & address) // Get the appropriate local address and port number from the routing protocol and set up endpoint if (SetupEndpoint () != 0) - { // Route to destination does not exist + { + NS_LOG_ERROR("Route to destination does not exist ?!"); return -1; } } @@ -1289,12 +1309,12 @@ TcpSocketBase::ProcessEstablished (Ptr packet, const TcpHeader& tcpHeade // Different flags are different events if (tcpflags == TcpHeader::ACK) { - if (tcpHeader.GetAckNumber () < m_txBuffer->HeadSequence ()) + if (tcpHeader.GetAckNumber () < FirstUnackedSeq ()) { // Case 1: If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. // Pag. 72 RFC 793 NS_LOG_LOGIC ("Ignored ack of " << tcpHeader.GetAckNumber () << - " SND.UNA = " << m_txBuffer->HeadSequence ()); + " SND.UNA = " << FirstUnackedSeq ()); // TODO: RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] } @@ -1346,16 +1366,30 @@ TcpSocketBase::ProcessEstablished (Ptr packet, const TcpHeader& tcpHeade } } +void +TcpSocketBase::ReceivedAck (Ptr packet, + const TcpHeader& tcpHeader + ) +{ + // If there is any data piggybacked, store it into m_rxBuffer + NS_LOG_FUNCTION(this << packet << tcpHeader); + NS_ASSERT (0 != (tcpHeader.GetFlags () & TcpHeader::ACK)); + ReceivedAck(packet, tcpHeader.GetAckNumber()); + if (packet->GetSize () > 0) + { + ReceivedData (packet, tcpHeader); + } +} + /* Process the newly received ACK */ void -TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) +TcpSocketBase::ReceivedAck (Ptr packet, SequenceNumber32 ack) { - NS_LOG_FUNCTION (this << tcpHeader); + NS_LOG_FUNCTION (this << ack); - NS_ASSERT (0 != (tcpHeader.GetFlags () & TcpHeader::ACK)); NS_ASSERT (m_tcb->m_segmentSize > 0); - uint32_t bytesAcked = tcpHeader.GetAckNumber () - m_txBuffer->HeadSequence (); + uint32_t bytesAcked = ack - FirstUnackedSeq (); uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize; m_bytesAckedNotProcessed += bytesAcked % m_tcb->m_segmentSize; @@ -1369,12 +1403,12 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) " Segments acked: " << segsAcked << " bytes left: " << m_bytesAckedNotProcessed); - NS_LOG_DEBUG ("ACK of " << tcpHeader.GetAckNumber () << - " SND.UNA=" << m_txBuffer->HeadSequence () << + NS_LOG_DEBUG ("ACK of " << ack << + " SND.UNA=" << FirstUnackedSeq() << " SND.NXT=" << m_nextTxSequence); - if (tcpHeader.GetAckNumber () == m_txBuffer->HeadSequence () && - tcpHeader.GetAckNumber () < m_nextTxSequence && + if (ack == FirstUnackedSeq() && + ack < m_nextTxSequence && packet->GetSize () == 0) { // There is a DupAck @@ -1432,12 +1466,12 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) // Artificially call PktsAcked. After all, one segment has been ACKed. m_congestionControl->PktsAcked (m_tcb, 1, m_lastRtt); } - else if (tcpHeader.GetAckNumber () == m_txBuffer->HeadSequence () && - tcpHeader.GetAckNumber () == m_nextTxSequence) + else if (ack == FirstUnackedSeq () && + ack == m_nextTxSequence) { // Dupack, but the ACK is precisely equal to the nextTxSequence } - else if (tcpHeader.GetAckNumber () > m_txBuffer->HeadSequence ()) + else if (ack > FirstUnackedSeq ()) { // Case 3: New ACK, reset m_dupAckCount and update m_txBuffer bool callCongestionControl = true; bool resetRTO = true; @@ -1475,7 +1509,7 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) } else if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY) { - if (tcpHeader.GetAckNumber () < m_recover) + if (ack < m_recover) { /* Partial ACK. * In case of partial ACK, retransmit the first unacknowledged @@ -1503,7 +1537,8 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) callCongestionControl = false; // No congestion control on cWnd show be invoked m_dupAckCount -= segsAcked; // Update the dupAckCount - m_txBuffer->DiscardUpTo (tcpHeader.GetAckNumber ()); //Bug 1850: retransmit before newack + m_firstTxUnack = ack; + UpdateTxBuffer (); //Bug 1850: retransmit before newack DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet if (m_isFirstPartialAck) @@ -1521,12 +1556,12 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) */ m_congestionControl->PktsAcked (m_tcb, 1, m_lastRtt); - NS_LOG_INFO ("Partial ACK for seq " << tcpHeader.GetAckNumber () << + NS_LOG_INFO ("Partial ACK for seq " << ack << " in fast recovery: cwnd set to " << m_tcb->m_cWnd << " recover seq: " << m_recover << " dupAck count: " << m_dupAckCount); } - else if (tcpHeader.GetAckNumber () >= m_recover) + else if (ack >= m_recover) {// Full ACK (RFC2582 sec.3 bullet #5 paragraph 2, option 1) m_tcb->m_cWnd = std::min (m_tcb->m_ssThresh.Get (), BytesInFlight () + m_tcb->m_segmentSize); @@ -1539,10 +1574,10 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) * except the (maybe) new ACKs which come from a new window */ m_congestionControl->PktsAcked (m_tcb, segsAcked, m_lastRtt); - newSegsAcked = (tcpHeader.GetAckNumber () - m_recover) / m_tcb->m_segmentSize; + newSegsAcked = (ack - m_recover) / m_tcb->m_segmentSize; m_tcb->m_congState = TcpSocketState::CA_OPEN; - NS_LOG_INFO ("Received full ACK for seq " << tcpHeader.GetAckNumber () << + NS_LOG_INFO ("Received full ACK for seq " << ack << ". Leaving fast recovery with cwnd set to " << m_tcb->m_cWnd); NS_LOG_DEBUG ("RECOVERY -> OPEN"); } @@ -1574,7 +1609,7 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) NS_ASSERT (m_tcb->m_congState == TcpSocketState::CA_RECOVERY); } - NewAck (tcpHeader.GetAckNumber (), resetRTO); + NewAck (ack, resetRTO); // Try to send more data if (!m_sendPendingDataEvent.IsRunning ()) @@ -1584,12 +1619,6 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) this, m_connected); } } - - // If there is any data piggybacked, store it into m_rxBuffer - if (packet->GetSize () > 0) - { - ReceivedData (packet, tcpHeader); - } } /* Received a packet upon LISTEN state. */ @@ -1662,6 +1691,7 @@ TcpSocketBase::ProcessSynSent (Ptr packet, const TcpHeader& tcpHeader) m_rxBuffer->SetNextRxSequence (tcpHeader.GetSequenceNumber () + SequenceNumber32 (1)); m_highTxMark = ++m_nextTxSequence; m_txBuffer->SetHeadSequence (m_nextTxSequence); + m_firstTxUnack = m_nextTxSequence; SendEmptyPacket (TcpHeader::ACK); SendPendingData (m_connected); Simulator::ScheduleNow (&TcpSocketBase::ConnectionSucceeded, this); @@ -1703,6 +1733,9 @@ TcpSocketBase::ProcessSynRcvd (Ptr packet, const TcpHeader& tcpHeader, m_retxEvent.Cancel (); m_highTxMark = ++m_nextTxSequence; m_txBuffer->SetHeadSequence (m_nextTxSequence); + m_firstTxUnack = m_nextTxSequence; + + if (m_endPoint) { m_endPoint->SetPeer (InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 (), @@ -1737,6 +1770,7 @@ TcpSocketBase::ProcessSynRcvd (Ptr packet, const TcpHeader& tcpHeader, m_retxEvent.Cancel (); m_highTxMark = ++m_nextTxSequence; m_txBuffer->SetHeadSequence (m_nextTxSequence); + m_firstTxUnack = m_nextTxSequence; if (m_endPoint) { m_endPoint->SetPeer (InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 (), @@ -2294,7 +2328,7 @@ TcpSocketBase::SendDataPacket (SequenceNumber32 seq, uint32_t maxSize, bool with NS_LOG_FUNCTION (this << seq << maxSize << withAck); bool isRetransmission = false; - if ( seq == m_txBuffer->HeadSequence () ) + if ( seq == FirstUnackedSeq() ) { isRetransmission = true; } @@ -2478,14 +2512,10 @@ TcpSocketBase::SendPendingData (bool withAck) " rxwin " << m_rWnd << " segsize " << m_tcb->m_segmentSize << " nextTxSeq " << m_nextTxSequence << - " highestRxAck " << m_txBuffer->HeadSequence () << - " pd->Size " << m_txBuffer->Size () << - " pd->SFS " << m_txBuffer->SizeFromSequence (m_nextTxSequence)); - - NS_LOG_DEBUG ("Window: " << w << - " cWnd: " << m_tcb->m_cWnd << - " unAck: " << UnAckDataCount ()); - + " highestRxAck " << FirstUnackedSeq() << + " TxBufferSize=" << m_txBuffer->Size () << + " pd->SizeFromSequence( " << m_nextTxSequence << ")=" + << m_txBuffer->SizeFromSequence (m_nextTxSequence)); uint32_t s = std::min (w, m_tcb->m_segmentSize); // Send no more than window uint32_t sz = SendDataPacket (m_nextTxSequence, s, withAck); nPacketsSent++; // Count sent this loop @@ -2502,14 +2532,14 @@ uint32_t TcpSocketBase::UnAckDataCount () const { NS_LOG_FUNCTION (this); - return m_nextTxSequence.Get () - m_txBuffer->HeadSequence (); + return m_nextTxSequence.Get () - FirstUnackedSeq(); } uint32_t TcpSocketBase::BytesInFlight () const { NS_LOG_FUNCTION (this); - return m_highTxMark.Get () - m_txBuffer->HeadSequence (); + return m_highTxMark.Get () - FirstUnackedSeq(); } uint32_t @@ -2556,7 +2586,7 @@ TcpSocketBase::ReceivedData (Ptr p, const TcpHeader& tcpHeader) // Put into Rx buffer SequenceNumber32 expectedSeq = m_rxBuffer->NextRxSequence (); - if (!m_rxBuffer->Add (p, tcpHeader)) + if (!m_rxBuffer->Add (p, tcpHeader.GetSequenceNumber ())) { // Insert failed: No data or RX buffer full SendEmptyPacket (TcpHeader::ACK); return; @@ -2680,15 +2710,18 @@ TcpSocketBase::NewAck (SequenceNumber32 const& ack, bool resetRTO) // Note the highest ACK and tell app to send more NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack << - " numberAck " << (ack - m_txBuffer->HeadSequence ())); // Number bytes ack'ed - m_txBuffer->DiscardUpTo (ack); + " numberAck " << (ack - FirstUnackedSeq())); // Number bytes ack'ed + + m_firstTxUnack = ack; + UpdateTxBuffer(); + if (GetTxAvailable () > 0) { NotifySend (GetTxAvailable ()); } if (ack > m_nextTxSequence) { - m_nextTxSequence = ack; // If advanced + m_nextTxSequence = m_firstTxUnack; // If advanced } if (m_txBuffer->Size () == 0 && m_state != FIN_WAIT_1 && m_state != CLOSING) { // No retransmit timer if no data to retransmit @@ -2698,6 +2731,13 @@ TcpSocketBase::NewAck (SequenceNumber32 const& ack, bool resetRTO) } } +void +TcpSocketBase::UpdateTxBuffer() +{ + NS_LOG_FUNCTION(this); + m_txBuffer->DiscardUpTo (m_firstTxUnack); +} + // Retransmit timeout void TcpSocketBase::ReTxTimeout () @@ -2710,7 +2750,7 @@ TcpSocketBase::ReTxTimeout () return; } // If all data are received (non-closing socket and nothing to send), just return - if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence () >= m_highTxMark) + if (m_state <= ESTABLISHED && FirstUnackedSeq() >= m_highTxMark) { return; } @@ -2791,7 +2831,7 @@ TcpSocketBase::Retransmit () // If erroneous timeout in closed/timed-wait state, just return if (m_state == CLOSED || m_state == TIME_WAIT) return; // If all data are received (non-closing socket and nothing to send), just return - if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence () >= m_highTxMark) return; + if (m_state <= ESTABLISHED && FirstUnackedSeq() >= m_highTxMark) return; /* * When a TCP sender detects segment loss using the retransmission timer @@ -2824,7 +2864,7 @@ TcpSocketBase::Retransmit () * are not able to retransmit anything because of local congestion. */ - m_nextTxSequence = m_txBuffer->HeadSequence (); // Restart from highest Ack + m_nextTxSequence = FirstUnackedSeq (); // Restart from highest Ack m_dupAckCount = 0; if (m_tcb->m_congState != TcpSocketState::CA_LOSS) @@ -2880,11 +2920,13 @@ TcpSocketBase::DoRetransmit () } // Retransmit a data packet: Call SendDataPacket - uint32_t sz = SendDataPacket (m_txBuffer->HeadSequence (), m_tcb->m_segmentSize, true); + NS_LOG_LOGIC ("TcpSocketBase " << this << " retxing seq " << FirstUnackedSeq ()); + uint32_t sz = SendDataPacket (FirstUnackedSeq(), GetSegSize(), true); // In case of RTO, advance m_nextTxSequence - m_nextTxSequence = std::max (m_nextTxSequence.Get (), m_txBuffer->HeadSequence () + sz); - - NS_LOG_DEBUG ("retxing seq " << m_txBuffer->HeadSequence ()); + m_nextTxSequence = std::max (FirstUnackedSeq (), FirstUnackedSeq () + sz); +// m_firstTxUnack = m_nextTxSequence; + + NS_LOG_DEBUG ("retxing seq " << FirstUnackedSeq ()); } void @@ -2952,10 +2994,9 @@ TcpSocketBase::GetRcvBufSize (void) const void TcpSocketBase::SetSegSize (uint32_t size) { - NS_LOG_FUNCTION (this << size); + NS_ABORT_MSG_UNLESS ( (m_state == CLOSED) || (m_tcb->m_segmentSize == size), "Cannot change segment size dynamically."); m_tcb->m_segmentSize = size; - - NS_ABORT_MSG_UNLESS (m_state == CLOSED, "Cannot change segment size dynamically."); + } uint32_t @@ -3208,7 +3249,8 @@ TcpSocketBase::AddOptionTimestamp (TcpHeader& header) option->GetTimestamp () << " echo=" << m_timestampToEcho); } -void TcpSocketBase::UpdateWindowSize (const TcpHeader &header) +bool +TcpSocketBase::UpdateWindowSize (const TcpHeader &header) { NS_LOG_FUNCTION (this << header); // If the connection is not established, the window size is always @@ -3220,7 +3262,7 @@ void TcpSocketBase::UpdateWindowSize (const TcpHeader &header) { m_rWnd = receivedWindow; NS_LOG_LOGIC ("State less than ESTABLISHED; updating rWnd to " << m_rWnd); - return; + return true; } // Test for conditions that allow updating of the window @@ -3250,6 +3292,7 @@ void TcpSocketBase::UpdateWindowSize (const TcpHeader &header) m_rWnd = receivedWindow; NS_LOG_LOGIC ("updating rWnd to " << m_rWnd); } + return update; } void --- a/src/internet/model/tcp-socket-base.h +++ a/src/internet/model/tcp-socket-base.h @@ -246,6 +246,7 @@ public: static TypeId GetTypeId (void); friend class TcpGeneralTest; + virtual TypeId GetInstanceTypeId () const; /** * Create an unbound TCP socket @@ -280,6 +281,8 @@ public: */ virtual void SetRtt (Ptr rtt); + virtual SequenceNumber32 FirstUnackedSeq () const; + /** * \brief Sets the Minimum RTO. * \param minRto The minimum RTO. @@ -391,37 +394,41 @@ public: typedef void (* TcpTxRxTracedCallback) (const Ptr packet, const TcpHeader& header, const Ptr socket); + + // Implementing ns3::TcpSocket -- Attribute get/set + // inherited, no need to doc + virtual uint32_t GetSndBufSize (void) const; + virtual uint32_t GetRcvBufSize (void) const; + virtual uint32_t GetSegSize (void) const; + virtual uint32_t GetInitialSSThresh (void) const; + virtual uint32_t GetInitialCwnd (void) const; + virtual Time GetConnTimeout (void) const; +// virtual uint32_t GetConnCount (void) const; + virtual Time GetDelAckTimeout (void) const; + virtual uint32_t GetDelAckMaxCount (void) const; + virtual bool GetTcpNoDelay (void) const; + virtual Time GetPersistTimeout (void) const; + virtual bool GetAllowBroadcast (void) const; + virtual uint32_t GetSynRetries (void) const; + virtual uint32_t GetDataRetries (void) const; protected: // Implementing ns3::TcpSocket -- Attribute get/set // inherited, no need to doc virtual void SetSndBufSize (uint32_t size); - virtual uint32_t GetSndBufSize (void) const; virtual void SetRcvBufSize (uint32_t size); - virtual uint32_t GetRcvBufSize (void) const; virtual void SetSegSize (uint32_t size); - virtual uint32_t GetSegSize (void) const; virtual void SetInitialSSThresh (uint32_t threshold); - virtual uint32_t GetInitialSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); - virtual uint32_t GetInitialCwnd (void) const; virtual void SetConnTimeout (Time timeout); - virtual Time GetConnTimeout (void) const; virtual void SetSynRetries (uint32_t count); - virtual uint32_t GetSynRetries (void) const; virtual void SetDataRetries (uint32_t retries); - virtual uint32_t GetDataRetries (void) const; virtual void SetDelAckTimeout (Time timeout); - virtual Time GetDelAckTimeout (void) const; virtual void SetDelAckMaxCount (uint32_t count); - virtual uint32_t GetDelAckMaxCount (void) const; virtual void SetTcpNoDelay (bool noDelay); - virtual bool GetTcpNoDelay (void) const; virtual void SetPersistTimeout (Time timeout); - virtual Time GetPersistTimeout (void) const; virtual bool SetAllowBroadcast (bool allowBroadcast); - virtual bool GetAllowBroadcast (void) const; @@ -567,7 +574,7 @@ protected: /** * \brief Send reset and tear down this socket */ - void SendRST (void); + virtual void SendRST (void); /** * \brief Check if a sequence number range is within the rx window @@ -576,7 +583,7 @@ protected: * \param tail end of the Sequence window * \returns true if it is in range */ - bool OutOfRange (SequenceNumber32 head, SequenceNumber32 tail) const; + virtual bool OutOfRange (SequenceNumber32 head, SequenceNumber32 tail) const; // Helper functions: Connection close @@ -586,12 +593,12 @@ protected: * * \returns 0 on success */ - int DoClose (void); + virtual int DoClose (void); /** * \brief Peacefully close the socket by notifying the upper layer and deallocate end point */ - void CloseAndNotify (void); + virtual void CloseAndNotify (void); /** * \brief Kill this socket by zeroing its attributes (IPv4) @@ -599,7 +606,7 @@ protected: * This is a callback function configured to m_endpoint in * SetupCallback(), invoked when the endpoint is destroyed. */ - void Destroy (void); + virtual void Destroy (void); /** * \brief Kill this socket by zeroing its attributes (IPv6) @@ -607,12 +614,12 @@ protected: * This is a callback function configured to m_endpoint in * SetupCallback(), invoked when the endpoint is destroyed. */ - void Destroy6 (void); + virtual void Destroy6 (void); /** * \brief Deallocate m_endPoint and m_endPoint6 */ - void DeallocateEndPoint (void); + virtual void DeallocateEndPoint (void); /** * \brief Received a FIN from peer, notify rx buffer @@ -620,22 +627,22 @@ protected: * \param p the packet * \param tcpHeader the packet's TCP header */ - void PeerClose (Ptr p, const TcpHeader& tcpHeader); + virtual void PeerClose (Ptr p, const TcpHeader& tcpHeader); /** * \brief FIN is in sequence, notify app and respond with a FIN */ - void DoPeerClose (void); + virtual void DoPeerClose (void); /** * \brief Cancel all timer when endpoint is deleted */ - void CancelAllTimers (void); + virtual void CancelAllTimers (void); /** * \brief Move from CLOSING or FIN_WAIT_2 to TIME_WAIT state */ - void TimeWait (void); + virtual void TimeWait (void); // State transition functions @@ -647,7 +654,7 @@ protected: * \param packet the packet * \param tcpHeader the packet's TCP header */ - void ProcessEstablished (Ptr packet, const TcpHeader& tcpHeader); // Received a packet upon ESTABLISHED state + virtual void ProcessEstablished (Ptr packet, const TcpHeader& tcpHeader); // Received a packet upon ESTABLISHED state /** * \brief Received a packet upon LISTEN state. @@ -657,7 +664,7 @@ protected: * \param fromAddress the source address * \param toAddress the destination address */ - void ProcessListen (Ptr packet, const TcpHeader& tcpHeader, + virtual void ProcessListen (Ptr packet, const TcpHeader& tcpHeader, const Address& fromAddress, const Address& toAddress); /** @@ -666,7 +673,7 @@ protected: * \param packet the packet * \param tcpHeader the packet's TCP header */ - void ProcessSynSent (Ptr packet, const TcpHeader& tcpHeader); + virtual void ProcessSynSent (Ptr packet, const TcpHeader& tcpHeader); /** * \brief Received a packet upon SYN_RCVD. @@ -676,7 +683,7 @@ protected: * \param fromAddress the source address * \param toAddress the destination address */ - void ProcessSynRcvd (Ptr packet, const TcpHeader& tcpHeader, + virtual void ProcessSynRcvd (Ptr packet, const TcpHeader& tcpHeader, const Address& fromAddress, const Address& toAddress); /** @@ -685,7 +692,7 @@ protected: * \param packet the packet * \param tcpHeader the packet's TCP header */ - void ProcessWait (Ptr packet, const TcpHeader& tcpHeader); + virtual void ProcessWait (Ptr packet, const TcpHeader& tcpHeader); /** * \brief Received a packet upon CLOSING @@ -693,7 +700,7 @@ protected: * \param packet the packet * \param tcpHeader the packet's TCP header */ - void ProcessClosing (Ptr packet, const TcpHeader& tcpHeader); + virtual void ProcessClosing (Ptr packet, const TcpHeader& tcpHeader); /** * \brief Received a packet upon LAST_ACK @@ -701,7 +708,7 @@ protected: * \param packet the packet * \param tcpHeader the packet's TCP header */ - void ProcessLastAck (Ptr packet, const TcpHeader& tcpHeader); + virtual void ProcessLastAck (Ptr packet, const TcpHeader& tcpHeader); // Window management @@ -746,8 +753,9 @@ protected: * or 3) the advertised window is larger than the current send window * * \param header TcpHeader from which to extract the new window value + * \return true if receiver window got updated */ - void UpdateWindowSize (const TcpHeader& header); + virtual bool UpdateWindowSize (const TcpHeader& header); // Manage data tx/rx @@ -764,6 +772,7 @@ protected: * \param tcpHeader the packet's TCP header */ virtual void ReceivedAck (Ptr packet, const TcpHeader& tcpHeader); + virtual void ReceivedAck (Ptr packet, SequenceNumber32 ack); /** * \brief Recv of a data, put into buffer, call L7 to get it if necessary @@ -796,6 +805,11 @@ protected: virtual void Retransmit (void); /** + * \brief Called when a new ack arrives + */ + virtual void UpdateTxBuffer (void); + + /** * \brief Action upon delay ACK timeout, i.e. send an ACK */ virtual void DelAckTimeout (void); @@ -940,6 +954,7 @@ protected: Ptr m_rtt; //!< Round trip time estimator // Rx and Tx buffer management + TracedValue m_firstTxUnack; //!< First unacknowledged seq nb (SND.UNA) TracedValue m_nextTxSequence; //!< Next seqnum to be sent (SND.NXT), ReTx pushes it back TracedValue m_highTxMark; //!< Highest seqno ever sent, regardless of ReTx Ptr m_rxBuffer; //!< Rx buffer (reordering buffer) --- a/src/internet/model/tcp-tx-buffer.cc +++ a/src/internet/model/tcp-tx-buffer.cc @@ -197,6 +197,7 @@ TcpTxBuffer::CopyFromSequence (uint32_t numBytes, const SequenceNumber32& seq) } count += pktSize; } + NS_ASSERT (outPacket); NS_ASSERT (outPacket->GetSize () == s); return outPacket; } --- a/src/network/utils/pcap-file.cc +++ a/src/network/utils/pcap-file.cc @@ -448,7 +448,7 @@ PcapFile::Read ( uint32_t &readLen) { NS_LOG_FUNCTION (this << &data <