diff -r 5209cecd2ade src/internet-stack/pending-data.cc --- a/src/internet-stack/pending-data.cc Thu Sep 04 13:29:13 2008 -0700 +++ b/src/internet-stack/pending-data.cc Fri Sep 05 14:13:23 2008 -0400 @@ -131,7 +131,7 @@ Ptr PendingData::CopyFromOffset uint32_t s1 = std::min (s, SizeFromOffset (o)); // Insure not beyond end of data if (s1 == 0) { - return 0; // No data requested + return Create (); // No data requested } if (data.size() != 0) { // Actual data exists, make copy and return it diff -r 5209cecd2ade src/internet-stack/tcp-socket-impl.cc --- a/src/internet-stack/tcp-socket-impl.cc Thu Sep 04 13:29:13 2008 -0700 +++ b/src/internet-stack/tcp-socket-impl.cc Fri Sep 05 14:13:23 2008 -0400 @@ -76,10 +76,13 @@ TcpSocketImpl::GetTypeId () m_highestRxAck (0), m_lastRxAck (0), m_nextRxSequence (0), + m_rxAvailable (0), + m_rxBufSize (0), m_pendingData (0), + m_rxWindowSize (0), + m_persistTime (Seconds(6)), //XXX hook this into attributes? m_rtt (0), - m_lastMeasuredRtt (Seconds(0.0)), - m_rxAvailable (0) + m_lastMeasuredRtt (Seconds(0.0)) { NS_LOG_FUNCTION (this); } @@ -112,20 +115,21 @@ TcpSocketImpl::TcpSocketImpl(const TcpSo m_highestRxAck (sock.m_highestRxAck), m_lastRxAck (sock.m_lastRxAck), m_nextRxSequence (sock.m_nextRxSequence), + m_rxAvailable (0), + m_rxBufSize (0), m_pendingData (0), m_segmentSize (sock.m_segmentSize), m_rxWindowSize (sock.m_rxWindowSize), - m_advertisedWindowSize (sock.m_advertisedWindowSize), m_cWnd (sock.m_cWnd), m_ssThresh (sock.m_ssThresh), m_initialCWnd (sock.m_initialCWnd), + m_persistTime (sock.m_persistTime), m_rtt (0), m_lastMeasuredRtt (Seconds(0.0)), m_cnTimeout (sock.m_cnTimeout), m_cnCount (sock.m_cnCount), - m_rxAvailable (0), m_sndBufSize (sock.m_sndBufSize), - m_rcvBufSize(sock.m_rcvBufSize) + m_rxBufMaxSize(sock.m_rxBufMaxSize) { NS_LOG_FUNCTION_NOARGS (); NS_LOG_LOGIC("Invoked the copy constructor"); @@ -176,7 +180,6 @@ TcpSocketImpl::SetNode (Ptr node) m_node = node; // Initialize some variables m_cWnd = m_initialCWnd * m_segmentSize; - m_rxWindowSize = m_advertisedWindowSize; } void @@ -212,6 +215,9 @@ TcpSocketImpl::Destroy (void) m_node = 0; m_endPoint = 0; m_tcp = 0; + NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " + << (Simulator::Now () + + Simulator::GetDelayLeft (m_retxEvent)).GetSeconds()); m_retxEvent.Cancel (); } int @@ -492,6 +498,7 @@ TcpSocketImpl::Recv (uint32_t maxSize, u out[i->first] = i->second; } m_rxAvailable -= i->second->GetSize (); + m_rxBufSize -= i->second->GetSize (); m_bufferedData.erase (i); // Remove from list } if (out.size() == 0) @@ -514,6 +521,7 @@ TcpSocketImpl::Recv (uint32_t maxSize, u m_bufferedData[i->first+SequenceNumber(avail)] = i->second->CreateFragment(avail,i->second->GetSize()-avail); m_rxAvailable += i->second->GetSize()-avail; + m_rxBufSize += i->second->GetSize()-avail; } } return outPacket; @@ -570,6 +578,13 @@ TcpSocketImpl::ForwardUp (Ptr pa m_lastMeasuredRtt = m; } } + + if (m_rxWindowSize == 0 && tcpHeader.GetWindowSize () != 0) + { //persist probes end + NS_LOG_LOGIC (this<<" Leaving zerowindow persist state"); + m_persistEvent.Cancel (); + } + m_rxWindowSize = tcpHeader.GetWindowSize (); //update the flow control window Events_t event = SimulationSingleton::Get ()->FlagsEvent (tcpHeader.GetFlags () ); Actions_t action = ProcessEvent (event); //updates the state @@ -632,7 +647,7 @@ Actions_t TcpSocketImpl::ProcessEvent (E void TcpSocketImpl::SendEmptyPacket (uint8_t flags) { - NS_LOG_FUNCTION (this << flags); + NS_LOG_FUNCTION (this << (uint32_t)flags); Ptr p = Create (); TcpHeader header; @@ -641,7 +656,7 @@ void TcpSocketImpl::SendEmptyPacket (uin header.SetAckNumber (m_nextRxSequence); header.SetSourcePort (m_endPoint->GetLocalPort ()); header.SetDestinationPort (m_remotePort); - header.SetWindowSize (m_advertisedWindowSize); + header.SetWindowSize (AdvertisedWindowSize()); m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), m_remoteAddress); Time rto = m_rtt->RetransmitTimeout (); @@ -651,9 +666,10 @@ void TcpSocketImpl::SendEmptyPacket (uin m_cnTimeout = m_cnTimeout + m_cnTimeout; m_cnCount--; } - if (m_retxEvent.IsExpired () ) //no outstanding timer + bool isAck = (flags == TcpHeader::ACK); + if (m_retxEvent.IsExpired () && !isAck) //no outstanding timer { - NS_LOG_LOGIC ("Schedule retransmission timeout at time " + NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this); @@ -790,7 +806,6 @@ bool TcpSocketImpl::ProcessPacketAction NS_LOG_DEBUG ("TcpSocketImpl " << this << " ACK_TX_1" << " nextRxSeq " << m_nextRxSequence); SendEmptyPacket (TcpHeader::ACK); - m_rxWindowSize = tcpHeader.GetWindowSize (); if (tcpHeader.GetAckNumber () > m_highestRxAck) { m_highestRxAck = tcpHeader.GetAckNumber (); @@ -808,13 +823,17 @@ bool TcpSocketImpl::ProcessPacketAction { break; } - if (tcpHeader.GetAckNumber () == m_highestRxAck && - tcpHeader.GetAckNumber () < m_nextTxSequence) + if (tcpHeader.GetAckNumber () == m_highestRxAck) { - DupAck (tcpHeader, ++m_dupAckCount); + if (tcpHeader.GetAckNumber () < m_nextTxSequence) + { + DupAck (tcpHeader, ++m_dupAckCount); + } + NS_ASSERT(tcpHeader.GetAckNumber () <= m_nextTxSequence); + //if the ack is precisely equal to the nextTxSequence break; } - if (tcpHeader.GetAckNumber () > m_highestRxAck) + if (tcpHeader.GetAckNumber () > m_highestRxAck) { m_dupAckCount = 0; } @@ -928,7 +947,7 @@ bool TcpSocketImpl::SendPendingData (boo << " highestRxAck " << m_highestRxAck << " pd->Size " << m_pendingData->Size () << " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence)); - +//XXX pd->Size is probably a bug, should be SizeFromSeq(...) if (w < m_segmentSize && m_pendingData->Size () > w) { break; // No more @@ -961,6 +980,7 @@ bool TcpSocketImpl::SendPendingData (boo header.SetAckNumber (m_nextRxSequence); header.SetSourcePort (m_endPoint->GetLocalPort()); header.SetDestinationPort (m_remotePort); + header.SetWindowSize (AdvertisedWindowSize()); if (m_shutdownSend) { m_errno = ERROR_SHUTDOWN; @@ -971,7 +991,7 @@ bool TcpSocketImpl::SendPendingData (boo if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit { Time rto = m_rtt->RetransmitTimeout (); - NS_LOG_LOGIC ("SendPendingData Schedule retransmission timeout at time " << + NS_LOG_LOGIC (this<<" SendPendingData Schedule ReTxTimeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds () ); m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this); @@ -1024,6 +1044,17 @@ uint32_t TcpSocketImpl::AvailableWindow return (win - unack); // Amount of window space available } +uint32_t TcpSocketImpl::RxBufferFreeSpace() +{ + return m_rxBufMaxSize - m_rxBufSize; +} + +uint16_t TcpSocketImpl::AdvertisedWindowSize() +{ + uint32_t max = 0xffff; + return std::min(RxBufferFreeSpace(), max); +} + void TcpSocketImpl::NewRx (Ptr p, const TcpHeader& tcpHeader, const Address& fromAddress) @@ -1039,9 +1070,20 @@ void TcpSocketImpl::NewRx (Ptr p " ack " << tcpHeader.GetAckNumber() << " p.size is " << p->GetSize()); States_t origState = m_state; + if (RxBufferFreeSpace() < p->GetSize()) + { //if not enough room, fragment + p = p->CreateFragment(0, RxBufferFreeSpace()); + } + //XXX + //fragmenting here MIGHT not be the right thing to do, since possibly we trim + //the front and back off the packet below if it isn't all new data, so the + //check against RxBufferFreeSpace and fragmentation should ideally occur + //just before insertion into m_bufferedData, but this strategy is more + //agressive in rejecting oversized packets and still gives acceptable TCP uint32_t s = p->GetSize (); // Size of associated data if (s == 0) - {// Nothing to do if no associated data + {//if there is no data or no rx buffer space, just ack anyway + SendEmptyPacket (TcpHeader::ACK); return; } // Log sequence received if enabled @@ -1074,14 +1116,12 @@ void TcpSocketImpl::NewRx (Ptr p //buffer this, it'll be read by call to Recv UnAckData_t::iterator i = m_bufferedData.find (tcpHeader.GetSequenceNumber () ); - if (i != m_bufferedData.end () ) //we found it already in the buffer - { - i->second = 0; // relase reference to already buffered - } - // Save for later delivery - m_bufferedData[tcpHeader.GetSequenceNumber () ] = p; + NS_ASSERT(i == m_bufferedData.end ()); //no way it should have been found + // Save for later delivery if there is room + m_bufferedData[tcpHeader.GetSequenceNumber () ] = p; m_rxAvailable += p->GetSize (); RxBufFinishInsert (tcpHeader.GetSequenceNumber ()); + m_rxBufSize += p->GetSize (); NotifyDataRecv (); if (m_closeNotified) { @@ -1181,6 +1221,7 @@ void TcpSocketImpl::NewRx (Ptr p // Save for later delivery m_bufferedData[start] = p; m_rxAvailable += p->GetSize (); + m_rxBufSize += p->GetSize(); RxBufFinishInsert(start); NotifyDataRecv (); } @@ -1248,13 +1289,31 @@ void TcpSocketImpl::CommonNewAck (Sequen //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl)); if (!skipTimer) { - m_retxEvent.Cancel (); + NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " + << (Simulator::Now () + + Simulator::GetDelayLeft (m_retxEvent)).GetSeconds()); + m_retxEvent.Cancel (); //On recieving a "New" ack we restart retransmission timer .. RFC 2988 Time rto = m_rtt->RetransmitTimeout (); - NS_LOG_LOGIC ("Schedule retransmission timeout at time " + NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); - m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this); + m_retxEvent = + Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this); + } + if (m_rxWindowSize == 0 && m_persistEvent.IsExpired ()) //zerowindow + { + NS_LOG_LOGIC (this<<"Enter zerowindow persist state"); + NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " + << (Simulator::Now () + + Simulator::GetDelayLeft (m_retxEvent)).GetSeconds()); + m_retxEvent.Cancel (); + NS_LOG_LOGIC ("Schedule persist timeout at time " + < p = + m_pendingData->CopyFromSeq(1,m_firstPendingSequence,m_nextTxSequence); + TcpHeader tcpHeader; + tcpHeader.SetSequenceNumber (m_nextTxSequence); + tcpHeader.SetAckNumber (m_nextRxSequence); + tcpHeader.SetSourcePort (m_endPoint->GetLocalPort()); + tcpHeader.SetDestinationPort (m_remotePort); + tcpHeader.SetWindowSize (AdvertisedWindowSize()); + + m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (), + m_remoteAddress); + NS_LOG_LOGIC ("Schedule persist timeout at time " + < p = m_pendingData->CopyFromSeq (m_segmentSize, m_firstPendingSequence, - m_highestRxAck); + m_nextTxSequence); // Calculate remaining data for COE check uint32_t remainingData = m_pendingData->SizeFromSeq ( m_firstPendingSequence, @@ -1406,7 +1495,7 @@ void TcpSocketImpl::Retransmit () if (m_retxEvent.IsExpired () ) { Time rto = m_rtt->RetransmitTimeout (); - NS_LOG_LOGIC ("Schedule retransmission timeout at time " + NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this); @@ -1419,7 +1508,7 @@ void TcpSocketImpl::Retransmit () tcpHeader.SetSourcePort (m_endPoint->GetLocalPort()); tcpHeader.SetDestinationPort (m_remotePort); tcpHeader.SetFlags (flags); - tcpHeader.SetWindowSize (m_advertisedWindowSize); + tcpHeader.SetWindowSize (AdvertisedWindowSize()); m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (), m_remoteAddress); @@ -1440,13 +1529,13 @@ void void TcpSocketImpl::SetRcvBufSize (uint32_t size) { - m_rcvBufSize = size; + m_rxBufMaxSize = size; } uint32_t TcpSocketImpl::GetRcvBufSize (void) const { - return m_rcvBufSize; + return m_rxBufMaxSize; } void @@ -1459,18 +1548,6 @@ TcpSocketImpl::GetSegSize (void) const TcpSocketImpl::GetSegSize (void) const { return m_segmentSize; -} - -void -TcpSocketImpl::SetAdvWin (uint32_t window) -{ - m_advertisedWindowSize = window; -} - -uint32_t -TcpSocketImpl::GetAdvWin (void) const -{ - return m_advertisedWindowSize; } void diff -r 5209cecd2ade src/internet-stack/tcp-socket-impl.h --- a/src/internet-stack/tcp-socket-impl.h Thu Sep 04 13:29:13 2008 -0700 +++ b/src/internet-stack/tcp-socket-impl.h Fri Sep 05 14:13:23 2008 -0400 @@ -121,6 +121,10 @@ private: virtual uint32_t Window(); // Return window size (integer) virtual uint32_t AvailableWindow();// Return unfilled portion of window + //methods for Rx buffer management + uint32_t RxBufferFreeSpace(); + uint16_t AdvertisedWindowSize(); + // Manage data tx/rx void NewRx (Ptr, const TcpHeader&, const Address&); void RxBufFinishInsert (SequenceNumber); @@ -132,6 +136,7 @@ private: void ReTxTimeout (); void DelAckTimeout (); void LastAckTimeout (); + void PersistTimeout (); void Retransmit (); void CommonNewAck (SequenceNumber seq, bool skipTimer = false); @@ -142,8 +147,6 @@ private: virtual uint32_t GetRcvBufSize (void) const; virtual void SetSegSize (uint32_t size); virtual uint32_t GetSegSize (void) const; - virtual void SetAdvWin (uint32_t window); - virtual uint32_t GetAdvWin (void) const; virtual void SetSSThresh (uint32_t threshold); virtual uint32_t GetSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); @@ -195,22 +198,32 @@ private: SequenceNumber m_lastRxAck; //sequence info, reciever side - SequenceNumber m_nextRxSequence; + SequenceNumber m_nextRxSequence; //next expected sequence - //history data - //this is the incoming data buffer which sorts out of sequence data - UnAckData_t m_bufferedData; + //Rx buffer + UnAckData_t m_bufferedData; //buffer which sorts out of sequence data + //Rx buffer state + uint32_t m_rxAvailable; // amount of data available for reading through Recv + uint32_t m_rxBufSize; //size in bytes of the data in the rx buf + //note that these two are not the same: rxAvailbale is the number of + //contiguous sequenced bytes that can be read, rxBufSize is the TOTAL size + //including out of sequence data, such that m_rxAvailable <= m_rxBufSize + //this is kind of the tx buffer PendingData* m_pendingData; SequenceNumber m_firstPendingSequence; // Window management uint32_t m_segmentSize; //SegmentSize - uint32_t m_rxWindowSize; - uint32_t m_advertisedWindowSize; //Window to advertise + uint32_t m_rxWindowSize; //Flow control window TracedValue m_cWnd; //Congestion window uint32_t m_ssThresh; //Slow Start Threshold uint32_t m_initialCWnd; //Initial cWnd value + + //persist timer management + Time m_persistTime; + EventId m_persistEvent; + // Round trip time estimation Ptr m_rtt; @@ -220,12 +233,9 @@ private: Time m_cnTimeout; uint32_t m_cnCount; - // Temporary queue for delivering data to application - uint32_t m_rxAvailable; - // Attributes uint32_t m_sndBufSize; // buffer limit for the outgoing queue - uint32_t m_rcvBufSize; // maximum receive socket buffer size + uint32_t m_rxBufMaxSize; // maximum receive socket buffer size }; }//namespace ns3 diff -r 5209cecd2ade src/node/tcp-socket.cc --- a/src/node/tcp-socket.cc Thu Sep 04 13:29:13 2008 -0700 +++ b/src/node/tcp-socket.cc Fri Sep 05 14:13:23 2008 -0400 @@ -55,12 +55,6 @@ TcpSocket::GetTypeId (void) MakeUintegerAccessor (&TcpSocket::GetSegSize, &TcpSocket::SetSegSize), MakeUintegerChecker ()) - .AddAttribute ("AdvertisedWindowSize", - "TCP advertised window size (bytes)", - UintegerValue (0xffff), - MakeUintegerAccessor (&TcpSocket::GetAdvWin, - &TcpSocket::SetAdvWin), - MakeUintegerChecker ()) .AddAttribute ("SlowStartThreshold", "TCP slow start threshold (bytes)", UintegerValue (0xffff), diff -r 5209cecd2ade src/node/tcp-socket.h --- a/src/node/tcp-socket.h Thu Sep 04 13:29:13 2008 -0700 +++ b/src/node/tcp-socket.h Fri Sep 05 14:13:23 2008 -0400 @@ -59,8 +59,6 @@ private: virtual uint32_t GetRcvBufSize (void) const = 0; virtual void SetSegSize (uint32_t size) = 0; virtual uint32_t GetSegSize (void) const = 0; - virtual void SetAdvWin (uint32_t window) = 0; - virtual uint32_t GetAdvWin (void) const = 0; virtual void SetSSThresh (uint32_t threshold) = 0; virtual uint32_t GetSSThresh (void) const = 0; virtual void SetInitialCwnd (uint32_t count) = 0;