Mixed bugfixes on TCP, closes bug 1166, 1227, 1242.
1. Make connection count (m_cnCount) a separate variable from the number of
connection retries (m_cnRetries), so that the number of connection retries
can be cloned without affecting the number of connections to be made in the
cloned sockets.
2. There was a case that the m_highTxMark was mistaken as m_nextTxSequence
3. Update m_lastRtt correctly, fixes bug 1242
4. The endpoint allocation/deallocation is rewritten so that the endpoint
remembers the correct peer's address and it is deleted upon close.
RecvFrom() call now use the data in endpoint to return the peer's address,
and the socket closes nicely.
5. TcpL4Protocol::m_sockets now holds a complete list of all existing sockets
6. RST packet is sent before CloseAndNotify() is called, so that m_endPoint is
not yet destroyed, fixes bug 1166
7. Fix cwnd deflation bug in partial ACK handling in TcpNewReno
8. Created attributes for fast retransmit threshold (m_retxThresh) and max
advertised window size (m_maxWinSize)
9. Refactor SendPendingData() and DoRetransmit(), created SendDataPacket()
10. Call NotifySend() after connection established in ProcessSynSent() and
ProcessSynRcvd()
11. Defines new flags in TcpHeader: ECE and CWR (see RFC3168)
12. Prepared hooks for TCP option handling
13. Code tidy up
14. Fix the definition of out-of-order packets
15. TCP can now move from TIME_WAIT state to CLOSED state after 2*MSL
16. Implemented limited transmit (RFC3042) in TcpNewReno, c.f. bug 1227
17. Added Raj's email to the preamble, as TcpSocketBase was modified from
TcpSocketImpl.
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 Georgia Tech Research Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Raj Bhattacharjea <raj.b@gatech.edu>
*/
#include <stdint.h>
#include <iostream>
#include "tcp-header.h"
#include "ns3/buffer.h"
#include "ns3/address-utils.h"
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (TcpHeader);
TcpHeader::TcpHeader ()
: m_sourcePort (0),
m_destinationPort (0),
m_sequenceNumber (0),
m_ackNumber (0),
m_length (5),
m_flags (0),
m_windowSize (0xffff),
m_urgentPointer (0),
m_calcChecksum (false),
m_goodChecksum (true)
{
}
TcpHeader::~TcpHeader ()
{
}
void
TcpHeader::EnableChecksums (void)
{
m_calcChecksum = true;
}
void TcpHeader::SetSourcePort (uint16_t port)
{
m_sourcePort = port;
}
void TcpHeader::SetDestinationPort (uint16_t port)
{
m_destinationPort = port;
}
void TcpHeader::SetSequenceNumber (SequenceNumber32 sequenceNumber)
{
m_sequenceNumber = sequenceNumber;
}
void TcpHeader::SetAckNumber (SequenceNumber32 ackNumber)
{
m_ackNumber = ackNumber;
}
void TcpHeader::SetLength (uint8_t length)
{
m_length = length;
}
void TcpHeader::SetFlags (uint8_t flags)
{
m_flags = flags;
}
void TcpHeader::SetWindowSize (uint16_t windowSize)
{
m_windowSize = windowSize;
}
void TcpHeader::SetUrgentPointer (uint16_t urgentPointer)
{
m_urgentPointer = urgentPointer;
}
uint16_t TcpHeader::GetSourcePort () const
{
return m_sourcePort;
}
uint16_t TcpHeader::GetDestinationPort () const
{
return m_destinationPort;
}
SequenceNumber32 TcpHeader::GetSequenceNumber () const
{
return m_sequenceNumber;
}
SequenceNumber32 TcpHeader::GetAckNumber () const
{
return m_ackNumber;
}
uint8_t TcpHeader::GetLength () const
{
return m_length;
}
uint8_t TcpHeader::GetFlags () const
{
return m_flags;
}
uint16_t TcpHeader::GetWindowSize () const
{
return m_windowSize;
}
uint16_t TcpHeader::GetUrgentPointer () const
{
return m_urgentPointer;
}
void
TcpHeader::InitializeChecksum (Ipv4Address source,
Ipv4Address destination,
uint8_t protocol)
{
m_source = source;
m_destination = destination;
m_protocol = protocol;
}
uint16_t
TcpHeader::CalculateHeaderChecksum (uint16_t size) const
{
Buffer buf = Buffer (12);
buf.AddAtStart (12);
Buffer::Iterator it = buf.Begin ();
WriteTo (it, m_source);
WriteTo (it, m_destination);
it.WriteU8 (0); /* protocol */
it.WriteU8 (m_protocol); /* protocol */
it.WriteU8 (size >> 8); /* length */
it.WriteU8 (size & 0xff); /* length */
it = buf.Begin ();
/* we don't CompleteChecksum ( ~ ) now */
return ~(it.CalculateIpChecksum (12));
}
bool
TcpHeader::IsChecksumOk (void) const
{
return m_goodChecksum;
}
TypeId
TcpHeader::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpHeader")
.SetParent<Header> ()
.AddConstructor<TcpHeader> ()
;
return tid;
}
TypeId
TcpHeader::GetInstanceTypeId (void) const
{
return GetTypeId ();
}
void TcpHeader::Print (std::ostream &os) const
{
os << m_sourcePort << " > " << m_destinationPort;
if(m_flags!=0)
{
os<<" [";
if((m_flags & FIN) != 0)
{
os<<" FIN ";
}
if((m_flags & SYN) != 0)
{
os<<" SYN ";
}
if((m_flags & RST) != 0)
{
os<<" RST ";
}
if((m_flags & PSH) != 0)
{
os<<" PSH ";
}
if((m_flags & ACK) != 0)
{
os<<" ACK ";
}
if((m_flags & URG) != 0)
{
os<<" URG ";
}
if((m_flags & ECE) != 0)
{
os<<" ECE ";
}
if((m_flags & CWR) != 0)
{
os<<" CWR ";
}
os<<"]";
}
os<<" Seq="<<m_sequenceNumber<<" Ack="<<m_ackNumber<<" Win="<<m_windowSize;
}
uint32_t TcpHeader::GetSerializedSize (void) const
{
return 4*m_length;
}
void TcpHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
i.WriteHtonU16 (m_sourcePort);
i.WriteHtonU16 (m_destinationPort);
i.WriteHtonU32 (m_sequenceNumber.GetValue ());
i.WriteHtonU32 (m_ackNumber.GetValue ());
i.WriteHtonU16 (m_length << 12 | m_flags); //reserved bits are all zero
i.WriteHtonU16 (m_windowSize);
i.WriteHtonU16 (0);
i.WriteHtonU16 (m_urgentPointer);
if(m_calcChecksum)
{
uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
i = start;
uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum);
i = start;
i.Next (16);
i.WriteU16 (checksum);
}
}
uint32_t TcpHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
m_sourcePort = i.ReadNtohU16 ();
m_destinationPort = i.ReadNtohU16 ();
m_sequenceNumber = i.ReadNtohU32 ();
m_ackNumber = i.ReadNtohU32 ();
uint16_t field = i.ReadNtohU16 ();
m_flags = field & 0x3F;
m_length = field>>12;
m_windowSize = i.ReadNtohU16 ();
i.Next (2);
m_urgentPointer = i.ReadNtohU16 ();
if(m_calcChecksum)
{
uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
i = start;
uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum);
m_goodChecksum = (checksum == 0);
}
return GetSerializedSize ();
}
} // namespace ns3