--- a/src/internet-node/tcp-header.cc Tue May 20 10:30:40 2008 -0700
+++ b/src/internet-node/tcp-header.cc Tue May 20 11:52:25 2008 -0700
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <iostream>
-#include "tcp-socket.h"
+#include "tcp-socket-impl.h"
#include "tcp-header.h"
#include "ns3/buffer.h"
--- a/src/internet-node/tcp-impl.h Tue May 20 10:30:40 2008 -0700
+++ b/src/internet-node/tcp-impl.h Tue May 20 11:52:25 2008 -0700
@@ -37,7 +37,7 @@
* <a href="http://www.ece.gatech.edu/research/labs/MANIACS/GTNetS/">
* Georgia Tech Network Simulator (GTNetS)</a>.
*
- * Most of the logic is in class ns3::TcpSocket.
+ * Most of the logic is in class ns3::TcpSocketImpl.
*/
class TcpImpl : public Tcp
{
--- a/src/internet-node/tcp-l4-protocol.cc Tue May 20 10:30:40 2008 -0700
+++ b/src/internet-node/tcp-l4-protocol.cc Tue May 20 11:52:25 2008 -0700
@@ -30,7 +30,7 @@
#include "ipv4-end-point-demux.h"
#include "ipv4-end-point.h"
#include "ipv4-l3-protocol.h"
-#include "tcp-socket.h"
+#include "tcp-socket-impl.h"
#include "tcp-typedefs.h"
@@ -379,7 +379,7 @@
{
NS_LOG_FUNCTION_NOARGS ();
Ptr<RttEstimator> rtt = m_rttFactory.Create<RttEstimator> ();
- Ptr<TcpSocket> socket = CreateObject<TcpSocket> ();
+ Ptr<TcpSocketImpl> socket = CreateObject<TcpSocketImpl> ();
socket->SetNode (m_node);
socket->SetTcp (this);
socket->SetRtt (rtt);
--- a/src/internet-node/tcp-l4-protocol.h Tue May 20 10:30:40 2008 -0700
+++ b/src/internet-node/tcp-l4-protocol.h Tue May 20 11:52:25 2008 -0700
@@ -59,7 +59,7 @@
virtual int GetVersion (void) const;
/**
- * \return A smart Socket pointer to a TcpSocket, allocated by this instance
+ * \return A smart Socket pointer to a TcpSocketImpl, allocated by this instance
* of the TCP protocol
*/
Ptr<Socket> CreateSocket (void);
@@ -73,7 +73,7 @@
void DeAllocate (Ipv4EndPoint *endPoint);
-// // called by TcpSocket.
+// // called by TcpSocketImpl.
// bool Connect (const Ipv4Address& saddr, const Ipv4Address& daddr,
// uint16_t sport, uint16_t dport);
@@ -107,7 +107,7 @@
Ipv4EndPointDemux *m_endPoints;
ObjectFactory m_rttFactory;
private:
- friend class TcpSocket;
+ friend class TcpSocketImpl;
void SendPacket (Ptr<Packet>, TcpHeader,
Ipv4Address, Ipv4Address);
static ObjectFactory GetDefaultRttEstimatorFactory (void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/tcp-socket-impl.cc Tue May 20 11:52:25 2008 -0700
@@ -0,0 +1,1354 @@
+/* -*- 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 "ns3/node.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/log.h"
+#include "ns3/ipv4.h"
+#include "tcp-socket-impl.h"
+#include "tcp-l4-protocol.h"
+#include "ipv4-end-point.h"
+#include "ipv4-l4-demux.h"
+#include "ns3/simulation-singleton.h"
+#include "tcp-typedefs.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
+#include "ns3/uinteger.h"
+#include "ns3/trace-source-accessor.h"
+
+#include <algorithm>
+
+NS_LOG_COMPONENT_DEFINE ("TcpSocketImpl");
+
+using namespace std;
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (TcpSocketImpl);
+
+TypeId
+TcpSocketImpl::GetTypeId ()
+{
+ static TypeId tid = TypeId("ns3::TcpSocketImpl")
+ .SetParent<Socket> ()
+ .AddTraceSource ("CongestionWindow",
+ "The TCP connection's congestion window",
+ MakeTraceSourceAccessor (&TcpSocketImpl::m_cWnd))
+ ;
+ return tid;
+}
+
+ TcpSocketImpl::TcpSocketImpl ()
+ : m_skipRetxResched (false),
+ m_dupAckCount (0),
+ m_delAckCount (0),
+ m_endPoint (0),
+ m_node (0),
+ m_tcp (0),
+ m_errno (ERROR_NOTERROR),
+ m_shutdownSend (false),
+ m_shutdownRecv (false),
+ m_connected (false),
+ m_state (CLOSED),
+ m_closeNotified (false),
+ m_closeRequestNotified (false),
+ m_closeOnEmpty (false),
+ m_pendingClose (false),
+ m_nextTxSequence (0),
+ m_highTxMark (0),
+ m_highestRxAck (0),
+ m_lastRxAck (0),
+ m_nextRxSequence (0),
+ m_pendingData (0),
+ m_rtt (0),
+ m_lastMeasuredRtt (Seconds(0.0)),
+ m_rxAvailable (0),
+ m_sndBufLimit (0xffffffff),
+ m_rcvBufLimit (0xffffffff),
+ m_wouldBlock (false)
+{
+ NS_LOG_FUNCTION (this);
+
+}
+
+TcpSocketImpl::TcpSocketImpl(const TcpSocketImpl& sock)
+ : Socket(sock), //copy the base class callbacks
+ m_skipRetxResched (sock.m_skipRetxResched),
+ m_dupAckCount (sock.m_dupAckCount),
+ m_delAckCount (0),
+ m_delAckMaxCount (sock.m_delAckMaxCount),
+ m_delAckTimout (sock.m_delAckTimout),
+ m_endPoint (0),
+ m_node (sock.m_node),
+ m_tcp (sock.m_tcp),
+ m_remoteAddress (sock.m_remoteAddress),
+ m_remotePort (sock.m_remotePort),
+ m_localAddress (sock.m_localAddress),
+ m_localPort (sock.m_localPort),
+ m_errno (sock.m_errno),
+ m_shutdownSend (sock.m_shutdownSend),
+ m_shutdownRecv (sock.m_shutdownRecv),
+ m_connected (sock.m_connected),
+ m_state (sock.m_state),
+ m_closeNotified (sock.m_closeNotified),
+ m_closeRequestNotified (sock.m_closeRequestNotified),
+ m_closeOnEmpty (sock.m_closeOnEmpty),
+ m_pendingClose (sock.m_pendingClose),
+ m_nextTxSequence (sock.m_nextTxSequence),
+ m_highTxMark (sock.m_highTxMark),
+ m_highestRxAck (sock.m_highestRxAck),
+ m_lastRxAck (sock.m_lastRxAck),
+ m_nextRxSequence (sock.m_nextRxSequence),
+ 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_rtt (0),
+ m_lastMeasuredRtt (Seconds(0.0)),
+ m_cnTimeout (sock.m_cnTimeout),
+ m_cnCount (sock.m_cnCount),
+ m_rxAvailable (0),
+ m_sndBufLimit (0xffffffff),
+ m_rcvBufLimit (0xffffffff)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_LOGIC("Invoked the copy constructor");
+ //copy the pending data if necessary
+ if(sock.m_pendingData)
+ {
+ m_pendingData = sock.m_pendingData->Copy();
+ }
+ //copy the rtt if necessary
+ if (sock.m_rtt)
+ {
+ m_rtt = sock.m_rtt->Copy();
+ }
+ //can't "copy" the endpoint just yes, must do this when we know the peer info
+ //too; this is in SYN_ACK_TX
+}
+
+TcpSocketImpl::~TcpSocketImpl ()
+{
+ NS_LOG_FUNCTION(this);
+ m_node = 0;
+ if (m_endPoint != 0)
+ {
+ NS_ASSERT (m_tcp != 0);
+ /**
+ * Note that this piece of code is a bit tricky:
+ * when DeAllocate is called, it will call into
+ * Ipv4EndPointDemux::Deallocate which triggers
+ * a delete of the associated endPoint which triggers
+ * in turn a call to the method ::Destroy below
+ * will will zero the m_endPoint field.
+ */
+ NS_ASSERT (m_endPoint != 0);
+ m_tcp->DeAllocate (m_endPoint);
+ NS_ASSERT (m_endPoint == 0);
+ }
+ m_tcp = 0;
+ delete m_pendingData; //prevents leak
+ m_pendingData = 0;
+}
+
+void
+TcpSocketImpl::SetNode (Ptr<Node> node)
+{
+ m_node = node;
+ Ptr<Tcp> t = node->GetObject<Tcp> ();
+ m_segmentSize = t->GetDefaultSegSize ();
+ m_rxWindowSize = t->GetDefaultAdvWin ();
+ m_advertisedWindowSize = t->GetDefaultAdvWin ();
+ m_cWnd = t->GetDefaultInitialCwnd () * m_segmentSize;
+ m_ssThresh = t->GetDefaultSsThresh ();
+ m_initialCWnd = t->GetDefaultInitialCwnd ();
+ m_cnTimeout = Seconds (t->GetDefaultConnTimeout ());
+ m_cnCount = t->GetDefaultConnCount ();
+ m_delAckTimout = Seconds(t->GetDefaultDelAckTimeout ());
+ m_delAckMaxCount = t->GetDefaultDelAckCount ();
+}
+
+void
+TcpSocketImpl::SetTcp (Ptr<TcpL4Protocol> tcp)
+{
+ m_tcp = tcp;
+}
+void
+TcpSocketImpl::SetRtt (Ptr<RttEstimator> rtt)
+{
+ m_rtt = rtt;
+}
+
+
+enum Socket::SocketErrno
+TcpSocketImpl::GetErrno (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_errno;
+}
+
+Ptr<Node>
+TcpSocketImpl::GetNode (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_node;
+}
+
+void
+TcpSocketImpl::Destroy (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_node = 0;
+ m_endPoint = 0;
+ m_tcp = 0;
+ m_retxEvent.Cancel ();
+}
+int
+TcpSocketImpl::FinishBind (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ if (m_endPoint == 0)
+ {
+ return -1;
+ }
+ m_endPoint->SetRxCallback (MakeCallback (&TcpSocketImpl::ForwardUp, Ptr<TcpSocketImpl>(this)));
+ m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocketImpl::Destroy, Ptr<TcpSocketImpl>(this)));
+ m_localAddress = m_endPoint->GetLocalAddress ();
+ m_localPort = m_endPoint->GetLocalPort ();
+ return 0;
+}
+
+int
+TcpSocketImpl::Bind (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_endPoint = m_tcp->Allocate ();
+ return FinishBind ();
+}
+int
+TcpSocketImpl::Bind (const Address &address)
+{
+ NS_LOG_FUNCTION (this<<address);
+ if (!InetSocketAddress::IsMatchingType (address))
+ {
+ return ERROR_INVAL;
+ }
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ if (ipv4 == Ipv4Address::GetAny () && port == 0)
+ {
+ m_endPoint = m_tcp->Allocate ();
+ NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
+ }
+ else if (ipv4 == Ipv4Address::GetAny () && port != 0)
+ {
+ m_endPoint = m_tcp->Allocate (port);
+ NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
+ }
+ else if (ipv4 != Ipv4Address::GetAny () && port == 0)
+ {
+ m_endPoint = m_tcp->Allocate (ipv4);
+ NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
+ }
+ else if (ipv4 != Ipv4Address::GetAny () && port != 0)
+ {
+ m_endPoint = m_tcp->Allocate (ipv4, port);
+ NS_LOG_LOGIC ("TcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
+ }
+
+ return FinishBind ();
+}
+
+int
+TcpSocketImpl::ShutdownSend (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_shutdownSend = true;
+ return 0;
+}
+int
+TcpSocketImpl::ShutdownRecv (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_shutdownRecv = false;
+ return 0;
+}
+
+int
+TcpSocketImpl::Close (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ if (m_state == CLOSED)
+ {
+ return -1;
+ }
+ if (m_pendingData && m_pendingData->Size() != 0)
+ { // App close with pending data must wait until all data transmitted
+ m_closeOnEmpty = true;
+ NS_LOG_LOGIC("Socket " << this <<
+ " deferring close, state " << m_state);
+ return 0;
+ }
+
+ Actions_t action = ProcessEvent (APP_CLOSE);
+ ProcessAction (action);
+ ShutdownSend ();
+ return 0;
+}
+
+int
+TcpSocketImpl::Connect (const Address & address)
+{
+ NS_LOG_FUNCTION (this << address);
+ if (m_endPoint == 0)
+ {
+ if (Bind () == -1)
+ {
+ NS_ASSERT (m_endPoint == 0);
+ return -1;
+ }
+ NS_ASSERT (m_endPoint != 0);
+ }
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ m_remoteAddress = transport.GetIpv4 ();
+ m_remotePort = transport.GetPort ();
+
+ uint32_t localIfIndex;
+ Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
+
+ if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
+ {
+ m_endPoint->SetLocalAddress (ipv4->GetAddress (localIfIndex));
+ }
+ else
+ {
+ m_errno = ERROR_NOROUTETOHOST;
+ return -1;
+ }
+
+ Actions_t action = ProcessEvent (APP_CONNECT);
+ bool success = ProcessAction (action);
+ if (success)
+ {
+ return 0;
+ }
+ return -1;
+}
+int
+TcpSocketImpl::Send (const Ptr<Packet> p) //p here is just data, no headers
+{ // TCP Does not deal with packets from app, just data
+ return Send(p->PeekData(), p->GetSize());
+}
+
+int TcpSocketImpl::Send (const uint8_t* buf, uint32_t size)
+{
+ NS_LOG_FUNCTION (this << buf << size);
+ if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT)
+ {
+ if (size > GetTxAvailable ())
+ {
+ m_wouldBlock = true;
+ m_errno = ERROR_MSGSIZE;
+ return -1;
+ }
+ if (!m_pendingData)
+ {
+ m_pendingData = new PendingData (); // Create if non-existent
+ m_firstPendingSequence = m_nextTxSequence; // Note seq of first
+ }
+ //PendingData::Add always copies the data buffer, never modifies
+ m_pendingData->Add (size,buf);
+ NS_LOG_DEBUG("TcpSock::Send, pdsize " << m_pendingData->Size() <<
+ " state " << m_state);
+ Actions_t action = ProcessEvent (APP_SEND);
+ NS_LOG_DEBUG(" action " << action);
+ if (!ProcessAction (action))
+ {
+ return -1; // Failed, return zero
+ }
+ return size;
+ }
+ else
+ {
+ m_errno = ERROR_NOTCONN;
+ return -1;
+ }
+}
+
+int TcpSocketImpl::DoSendTo (Ptr<Packet> p, const Address &address)
+{
+ NS_LOG_FUNCTION (this << p << address);
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ return DoSendTo (p, ipv4, port);
+}
+
+int TcpSocketImpl::DoSendTo (Ptr<Packet> p, Ipv4Address ipv4, uint16_t port)
+{
+ NS_LOG_FUNCTION (this << p << ipv4 << port);
+ if (m_endPoint == 0)
+ {
+ if (Bind () == -1)
+ {
+ NS_ASSERT (m_endPoint == 0);
+ return -1;
+ }
+ NS_ASSERT (m_endPoint != 0);
+ }
+ if (m_shutdownSend)
+ {
+ m_errno = ERROR_SHUTDOWN;
+ return -1;
+ }
+ m_tcp->Send (p, m_endPoint->GetLocalAddress (), ipv4,
+ m_endPoint->GetLocalPort (), port);
+ NotifyDataSent (p->GetSize ());
+ return 0;
+}
+
+int
+TcpSocketImpl::SendTo (Ptr<Packet> p, const Address &address)
+{
+ NS_LOG_FUNCTION (this << address << p);
+ if (!m_connected)
+ {
+ m_errno = ERROR_NOTCONN;
+ return -1;
+ }
+ else
+ {
+ return Send (p); //drop the address according to BSD manpages
+ }
+}
+
+uint32_t
+TcpSocketImpl::GetTxAvailable (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ if (m_pendingData != 0)
+ {
+ uint32_t unAckedDataSize =
+ m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck);
+ NS_ASSERT (m_sndBufLimit >= unAckedDataSize); //else a logical error
+ return m_sndBufLimit-unAckedDataSize;
+ }
+ else
+ {
+ return m_sndBufLimit;
+ }
+}
+
+int
+TcpSocketImpl::Listen (uint32_t q)
+{
+ NS_LOG_FUNCTION (this << q);
+ Actions_t action = ProcessEvent (APP_LISTEN);
+ ProcessAction (action);
+ return 0;
+}
+
+Ptr<Packet>
+TcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ if (m_deliveryQueue.empty() )
+ {
+ return 0;
+ }
+ Ptr<Packet> p = m_deliveryQueue.front ();
+ if (p->GetSize () <= maxSize)
+ {
+ m_deliveryQueue.pop ();
+ m_rxAvailable -= p->GetSize ();
+ }
+ else
+ {
+ p = 0;
+ }
+ return p;
+}
+
+uint32_t
+TcpSocketImpl::GetRxAvailable (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ // We separately maintain this state to avoid walking the queue
+ // every time this might be called
+ return m_rxAvailable;
+}
+
+void
+TcpSocketImpl::SetSndBuf (uint32_t size)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_sndBufLimit = size;
+}
+
+uint32_t
+TcpSocketImpl::GetSndBuf (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_sndBufLimit;
+}
+
+void
+TcpSocketImpl::SetRcvBuf (uint32_t size)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_rcvBufLimit = size;
+}
+
+uint32_t
+TcpSocketImpl::GetRcvBuf (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_rcvBufLimit;
+}
+
+void
+TcpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
+{
+ NS_LOG_DEBUG("Socket " << this << " got forward up" <<
+ " dport " << m_endPoint->GetLocalPort() <<
+ " daddr " << m_endPoint->GetLocalAddress() <<
+ " sport " << m_endPoint->GetPeerPort() <<
+ " saddr " << m_endPoint->GetPeerAddress());
+
+ NS_LOG_FUNCTION (this << packet << ipv4 << port);
+ if (m_shutdownRecv)
+ {
+ return;
+ }
+ TcpHeader tcpHeader;
+ packet->RemoveHeader (tcpHeader);
+
+ if (tcpHeader.GetFlags () & TcpHeader::ACK)
+ {
+ Time m = m_rtt->AckSeq (tcpHeader.GetAckNumber () );
+ if (m != Seconds (0.0))
+ {
+ m_lastMeasuredRtt = m;
+ }
+ }
+
+ Events_t event = SimulationSingleton<TcpStateMachine>::Get ()->FlagsEvent (tcpHeader.GetFlags () );
+ Actions_t action = ProcessEvent (event); //updates the state
+ Address address = InetSocketAddress (ipv4, port);
+ NS_LOG_DEBUG("Socket " << this <<
+ " processing pkt action, " << action <<
+ " current state " << m_state);
+ ProcessPacketAction (action, packet, tcpHeader, address);
+}
+
+Actions_t TcpSocketImpl::ProcessEvent (Events_t e)
+{
+ NS_LOG_FUNCTION (this << e);
+ States_t saveState = m_state;
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " processing event " << e);
+ // simulation singleton is a way to get a single global static instance of a
+ // class intended to be a singleton; see simulation-singleton.h
+ SA stateAction = SimulationSingleton<TcpStateMachine>::Get ()->Lookup (m_state,e);
+ // debug
+ if (stateAction.action == RST_TX)
+ {
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " sending RST from state "
+ << saveState << " event " << e);
+ }
+ bool needCloseNotify = (stateAction.state == CLOSED && m_state != CLOSED
+ && e != TIMEOUT);
+ m_state = stateAction.state;
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " moved from state " << saveState
+ << " to state " <<m_state);
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " pendingData " << m_pendingData);
+
+ //extra event logic is here for RX events
+ //e = SYN_ACK_RX
+ if (saveState == SYN_SENT && m_state == ESTABLISHED)
+ // this means the application side has completed its portion of
+ // the handshaking
+ {
+ Simulator::ScheduleNow(&TcpSocketImpl::ConnectionSucceeded, this);
+ //NotifyConnectionSucceeded ();
+ m_connected = true;
+ m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!");
+ }
+
+ if (needCloseNotify && !m_closeNotified)
+ {
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from "
+ << m_state << " event " << e << " closeNot " << m_closeNotified
+ << " action " << stateAction.action);
+ NotifyCloseCompleted ();
+ m_closeNotified = true;
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " calling Closed from PE"
+ << " origState " << saveState
+ << " event " << e);
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from "
+ << m_state << " event " << e
+ << " set CloseNotif ");
+ }
+ return stateAction.action;
+}
+
+void TcpSocketImpl::SendEmptyPacket (uint8_t flags)
+{
+ NS_LOG_FUNCTION (this << flags);
+ Ptr<Packet> p = Create<Packet> ();
+ TcpHeader header;
+
+ header.SetFlags (flags);
+ header.SetSequenceNumber (m_nextTxSequence);
+ header.SetAckNumber (m_nextRxSequence);
+ header.SetSourcePort (m_endPoint->GetLocalPort ());
+ header.SetDestinationPort (m_remotePort);
+ header.SetWindowSize (m_advertisedWindowSize);
+ m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (),
+ m_remoteAddress);
+ Time rto = m_rtt->RetransmitTimeout ();
+ if (flags & TcpHeader::SYN)
+ {
+ rto = m_cnTimeout;
+ m_cnTimeout = m_cnTimeout + m_cnTimeout;
+ m_cnCount--;
+ }
+ if (m_retxEvent.IsExpired () ) //no outstanding timer
+ {
+ NS_LOG_LOGIC ("Schedule retransmission timeout at time "
+ << Simulator::Now ().GetSeconds () << " to expire at time "
+ << (Simulator::Now () + rto).GetSeconds ());
+ m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this);
+ }
+}
+
+bool TcpSocketImpl::ProcessAction (Actions_t a)
+{ // These actions do not require a packet or any TCP Headers
+ NS_LOG_FUNCTION (this << a);
+ switch (a)
+ {
+ case NO_ACT:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action: NO_ACT");
+ break;
+ case ACK_TX:
+ SendEmptyPacket (TcpHeader::ACK);
+ break;
+ case ACK_TX_1:
+ NS_ASSERT (false); // This should be processed in ProcessPacketAction
+ break;
+ case RST_TX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action RST_TX");
+ SendEmptyPacket (TcpHeader::RST);
+ break;
+ case SYN_TX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_TX");
+ // TCP SYN Flag consumes one byte
+ // is the above correct? we're SENDING a syn, not acking back -- Raj
+ // commented out for now
+ // m_nextTxSequence+= 1;
+ SendEmptyPacket (TcpHeader::SYN);
+ break;
+ case SYN_ACK_TX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_ACK_TX");
+ // TCP SYN Flag consumes one byte
+ ++m_nextRxSequence;
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+ break;
+ case FIN_TX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action FIN_TX");
+ SendEmptyPacket (TcpHeader::FIN);
+ break;
+ case FIN_ACK_TX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action FIN_ACK_TX");
+ SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK);
+ break;
+ case NEW_ACK:
+ NS_ASSERT (false); // This should be processed in ProcessPacketAction
+ break;
+ case NEW_SEQ_RX:
+ NS_ASSERT (false); // This should be processed in ProcessPacketAction
+ break;
+ case RETX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action RETX");
+ break;
+ case TX_DATA:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action TX_DATA");
+ SendPendingData ();
+ break;
+ case PEER_CLOSE:
+ NS_ASSERT (false); // This should be processed in ProcessPacketAction
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action PEER_CLOSE");
+ break;
+ case APP_CLOSED:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action APP_CLOSED");
+ break;
+ case CANCEL_TM:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action CANCEL_TM");
+ break;
+ case APP_NOTIFY:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action APP_NOTIFY");
+ break;
+ case SERV_NOTIFY:
+ NS_ASSERT (false); // This should be processed in ProcessPacketAction
+ break;
+ case LAST_ACTION:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action LAST_ACTION");
+ break;
+ }
+ return true;
+}
+
+bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
+ const TcpHeader& tcpHeader,
+ const Address& fromAddress)
+{
+ NS_LOG_FUNCTION (this << a << p << fromAddress);
+ uint32_t localIfIndex;
+ Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
+ switch (a)
+ {
+ case SYN_ACK_TX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_ACK_TX");
+// m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
+// m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
+// if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
+// {
+// m_localAddress = ipv4->GetAddress (localIfIndex);
+// }
+ if (m_state == LISTEN) //this means we should fork a new TcpSocketImpl
+ {
+ NS_LOG_DEBUG("In SYN_ACK_TX, m_state is LISTEN, this " << this);
+ //notify the server that we got a SYN
+ // If server refuses connection do nothing
+ if (!NotifyConnectionRequest(fromAddress)) return true;
+ // Clone the socket
+ Ptr<TcpSocketImpl> newSock = Copy ();
+ NS_LOG_LOGIC ("Cloned a TcpSocketImpl " << newSock);
+ //this listening socket should do nothing more
+ Simulator::ScheduleNow (&TcpSocketImpl::CompleteFork, newSock,
+ p, tcpHeader,fromAddress);
+ return true;
+ }
+ // This is the cloned endpoint
+ m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
+ if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
+ {
+ m_localAddress = ipv4->GetAddress (localIfIndex);
+ m_endPoint->SetLocalAddress (m_localAddress);
+ // Leave local addr in the portmap to any, as the path from
+ // remote can change and packets can arrive on different interfaces
+ //m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
+ }
+ // TCP SYN consumes one byte
+ m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
+ SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
+ break;
+ case ACK_TX_1:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action ACK_TX_1");
+ // TCP SYN consumes one byte
+ m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
+ m_nextTxSequence = tcpHeader.GetAckNumber ();
+ m_firstPendingSequence = m_nextTxSequence; //bug 166
+ 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 ();
+ // Data freed from the send buffer; notify any blocked sender
+ if (m_wouldBlock)
+ {
+ NotifySend (GetTxAvailable ());
+ m_wouldBlock = false;
+ }
+ }
+ SendPendingData ();
+ break;
+ case NEW_ACK:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action NEW_ACK_TX");
+ if (tcpHeader.GetAckNumber () < m_highestRxAck) //old ack, do nothing
+ {
+ break;
+ }
+ if (tcpHeader.GetAckNumber () == m_highestRxAck &&
+ tcpHeader.GetAckNumber () < m_nextTxSequence)
+ {
+ DupAck (tcpHeader, ++m_dupAckCount);
+ break;
+ }
+ if (tcpHeader.GetAckNumber () > m_highestRxAck)
+ {
+ m_dupAckCount = 0;
+ }
+ NewAck (tcpHeader.GetAckNumber ());
+ break;
+ case NEW_SEQ_RX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action NEW_SEQ_RX");
+ NewRx (p, tcpHeader, fromAddress); // Process new data received
+ break;
+ case PEER_CLOSE:
+ {
+ // First we have to be sure the FIN packet was not received
+ // out of sequence. If so, note pending close and process
+ // new sequence rx
+ if (tcpHeader.GetSequenceNumber () != m_nextRxSequence)
+ { // process close later
+ m_pendingClose = true;
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " setting pendingClose"
+ << " rxseq " << tcpHeader.GetSequenceNumber ()
+ << " nextRxSeq " << m_nextRxSequence);
+ NewRx (p, tcpHeader, fromAddress);
+ return true;
+ }
+ // Now we need to see if any data came with the FIN
+ // if so, call NewRx
+ if (p->GetSize () != 0)
+ {
+ NewRx (p, tcpHeader, fromAddress);
+ }
+ States_t saveState = m_state; // Used to see if app responds
+ NS_LOG_LOGIC ("TcpSocketImpl " << this
+ << " peer close, state " << m_state);
+ if (!m_closeRequestNotified)
+ {
+ NS_LOG_LOGIC ("TCP " << this
+ << " calling AppCloseRequest");
+ NotifyCloseRequested();
+ m_closeRequestNotified = true;
+ }
+ NS_LOG_LOGIC ("TcpSocketImpl " << this
+ << " peer close, state after " << m_state);
+ if (m_state == saveState)
+ { // Need to ack, the application will close later
+ SendEmptyPacket (TcpHeader::ACK);
+// // Also need to re-tx the ack if we
+ }
+ if (m_state == LAST_ACK)
+ {
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " scheduling LATO1");
+ m_lastAckEvent = Simulator::Schedule (m_rtt->RetransmitTimeout (),
+ &TcpSocketImpl::LastAckTimeout,this);
+ }
+ break;
+ }
+ case SERV_NOTIFY:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SERV_NOTIFY");
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!");
+ NotifyNewConnectionCreated (this, fromAddress);
+ m_connected = true; // ! This is bogus; fix when we clone the tcp
+ m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
+ //treat the connection orientation final ack as a newack
+ CommonNewAck (tcpHeader.GetAckNumber (), true);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+void TcpSocketImpl::CompleteFork(Ptr<Packet> p, const TcpHeader& h, const Address& fromAddress)
+{
+ // Get port and address from peer (connecting host)
+ m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
+ m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
+ m_endPoint = m_tcp->Allocate (m_localAddress,
+ m_localPort,
+ m_remoteAddress,
+ m_remotePort);
+ //the cloned socket with be in listen state, so manually change state
+ m_state = SYN_RCVD;
+ //equivalent to FinishBind
+ m_endPoint->SetRxCallback (MakeCallback (&TcpSocketImpl::ForwardUp, Ptr<TcpSocketImpl>(this)));
+ m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocketImpl::Destroy, Ptr<TcpSocketImpl>(this)));
+ ProcessPacketAction(SYN_ACK_TX, p, h, fromAddress);
+ }
+
+void TcpSocketImpl::ConnectionSucceeded()
+{ // We would preferred to have scheduled an event directly to
+ // NotifyConnectionSucceeded, but (sigh) these are protected
+ // and we can get the address of it :(
+ NotifyConnectionSucceeded();
+}
+
+bool TcpSocketImpl::SendPendingData (bool withAck)
+{
+ NS_LOG_FUNCTION (this << withAck);
+ NS_LOG_LOGIC ("ENTERING SendPendingData");
+ if (!m_pendingData)
+ {
+ return false; // No data exists
+ }
+ uint32_t nPacketsSent = 0;
+ while (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence))
+ {
+ uint32_t w = AvailableWindow ();// Get available window size
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " SendPendingData"
+ << " w " << w
+ << " rxwin " << m_rxWindowSize
+ << " cWnd " << m_cWnd
+ << " segsize " << m_segmentSize
+ << " nextTxSeq " << m_nextTxSequence
+ << " highestRxAck " << m_highestRxAck
+ << " pd->Size " << m_pendingData->Size ()
+ << " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence));
+
+ if (w < m_segmentSize && m_pendingData->Size () > w)
+ {
+ break; // No more
+ }
+ uint32_t s = std::min (w, m_segmentSize); // Send no more than window
+ Ptr<Packet> p = m_pendingData->CopyFromSeq (s, m_firstPendingSequence,
+ m_nextTxSequence);
+ NS_LOG_LOGIC("TcpSocketImpl " << this << " sendPendingData"
+ << " txseq " << m_nextTxSequence
+ << " s " << s
+ << " datasize " << p->GetSize() );
+ uint8_t flags = 0;
+ if (withAck)
+ {
+ flags |= TcpHeader::ACK;
+ }
+ uint32_t sz = p->GetSize (); // Size of packet
+ uint32_t remainingData = m_pendingData->SizeFromSeq(
+ m_firstPendingSequence,
+ m_nextTxSequence + SequenceNumber (sz));
+ if (m_closeOnEmpty && (remainingData == 0))
+ {
+ flags = TcpHeader::FIN;
+ m_state = FIN_WAIT_1;
+ }
+
+ TcpHeader header;
+ header.SetFlags (flags);
+ header.SetSequenceNumber (m_nextTxSequence);
+ header.SetAckNumber (m_nextRxSequence);
+ header.SetSourcePort (m_endPoint->GetLocalPort());
+ header.SetDestinationPort (m_remotePort);
+ if (m_shutdownSend)
+ {
+ m_errno = ERROR_SHUTDOWN;
+ return -1;
+ }
+
+
+ if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit
+ {
+ Time rto = m_rtt->RetransmitTimeout ();
+ NS_LOG_LOGIC ("Schedule retransmission timeout at time " <<
+ Simulator::Now ().GetSeconds () << " to expire at time " <<
+ (Simulator::Now () + rto).GetSeconds () );
+ m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this);
+ }
+ NS_LOG_LOGIC ("About to send a packet with flags: " << flags);
+ m_tcp->SendPacket (p, header,
+ m_endPoint->GetLocalAddress (),
+ m_remoteAddress);
+ m_rtt->SentSeq(m_nextTxSequence, sz); // notify the RTT
+ // Notify the application
+ Simulator::ScheduleNow(&TcpSocketImpl::NotifyDataSent, this, p->GetSize ());
+ nPacketsSent++; // Count sent this loop
+ m_nextTxSequence += sz; // Advance next tx sequence
+ // Note the high water mark
+ m_highTxMark = std::max (m_nextTxSequence, m_highTxMark);
+ }
+ NS_LOG_LOGIC ("Sent "<<nPacketsSent<<" packets");
+ NS_LOG_LOGIC("RETURN SendPendingData");
+ return (nPacketsSent>0);
+}
+
+uint32_t TcpSocketImpl::UnAckDataCount ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_nextTxSequence - m_highestRxAck;
+}
+
+uint32_t TcpSocketImpl::BytesInFlight ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_highTxMark - m_highestRxAck;
+}
+
+uint32_t TcpSocketImpl::Window ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_LOGIC ("TcpSocketImpl::Window() "<<this);
+ return std::min (m_rxWindowSize, m_cWnd.Get());
+}
+
+uint32_t TcpSocketImpl::AvailableWindow ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ uint32_t unack = UnAckDataCount (); // Number of outstanding bytes
+ uint32_t win = Window ();
+ if (win < unack)
+ {
+ return 0; // No space available
+ }
+ return (win - unack); // Amount of window space available
+}
+
+void TcpSocketImpl::NewRx (Ptr<Packet> p,
+ const TcpHeader& tcpHeader,
+ const Address& fromAddress)
+{
+ NS_LOG_FUNCTION (this << p << "tcpHeader " << fromAddress);
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewRx,"
+ << " seq " << tcpHeader.GetSequenceNumber()
+ << " ack " << tcpHeader.GetAckNumber()
+ << " p.size is " << p->GetSize () );
+ NS_LOG_DEBUG ("TcpSocketImpl " << this <<
+ " NewRx," <<
+ " seq " << tcpHeader.GetSequenceNumber() <<
+ " ack " << tcpHeader.GetAckNumber() <<
+ " p.size is " << p->GetSize());
+ States_t origState = m_state;
+ uint32_t s = p->GetSize (); // Size of associated data
+ if (s == 0)
+ {// Nothing to do if no associated data
+ return;
+ }
+ // Log sequence received if enabled
+ // NoteTimeSeq(LOG_SEQ_RX, h->sequenceNumber);
+ // Three possibilities
+ // 1) Received seq is expected, deliver this and any buffered data
+ // 2) Received seq is < expected, just re-ack previous
+ // 3) Received seq is > expected, just re-ack previous and buffer data
+ if (tcpHeader.GetSequenceNumber () == m_nextRxSequence)
+ { // If seq is expected seq
+ // 1) Update nextRxSeq
+ // 2) Deliver to application this packet
+ // 3) See if any buffered can be delivered
+ // 4) Send the ack
+ m_nextRxSequence += s; // Advance next expected sequence
+ //bytesReceived += s; // Statistics
+ NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence );
+ SocketRxAddressTag tag;
+ tag.SetAddress (fromAddress);
+ p->AddTag (tag);
+ m_deliveryQueue.push (p);
+ m_rxAvailable += p->GetSize ();
+ NotifyDataRecv ();
+ if (m_closeNotified)
+ {
+ NS_LOG_LOGIC ("Tcp " << this << " HuH? Got data after closeNotif");
+ }
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " adv rxseq by " << s);
+ // Look for buffered data
+ UnAckData_t::iterator i;
+ // Note that the bufferedData list DOES contain the tcp header
+ while (!m_bufferedData.empty ())
+ { // Check the buffered data for delivery
+ NS_LOG_LOGIC("TCP " << this << " bufferedData.size() "
+ << m_bufferedData.size ()
+ << " time " << Simulator::Now ());
+ i = m_bufferedData.begin ();
+ Ptr<Packet> p1 = i->second;
+ SequenceNumber s1 = 0;
+ if (i->first > m_nextRxSequence)
+ {
+ break; // Not next expected
+ }
+ // already have the header as a param
+ //TCPHeader* h = dynamic_cast<TCPHeader*>(p1->PopPDU());
+ // Check non-null here...
+ uint8_t flags = tcpHeader.GetFlags (); // Flags (used below)
+ if (i->first < m_nextRxSequence)
+ { // remove already delivered data
+ // Two cases here.
+ // 1) seq + length <= nextRxSeq, just discard
+ // 2) seq + length > nextRxSeq, can deliver partial
+ s1 = p->GetSize ();
+ if (i->first + s1 < m_nextRxSequence)
+ { // Just remove from list
+ //bufferedData.erase(i);
+ p1 = 0; // Nothing to deliver
+ }
+ else
+ { // Remove partial data to prepare for delivery
+ uint32_t dup = m_nextRxSequence - i->first;
+ i->second = p1->CreateFragment (0, p1->GetSize () - dup);
+ p1 = i->second;
+ }
+ }
+ else
+ { // At this point i->first must equal nextRxSeq
+ if (i->first != m_nextRxSequence)
+ {
+ NS_FATAL_ERROR ("HuH? NexRx failure, first "
+ << i->first << " nextRxSeq " << m_nextRxSequence);
+ }
+ s1 = p1->GetSize ();
+ }
+ SocketRxAddressTag tag;
+ tag.SetAddress (fromAddress);
+ p1->AddTag (tag);
+ m_deliveryQueue.push (p1);
+ m_rxAvailable += p->GetSize ();
+ NotifyDataRecv ();
+
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " adv rxseq1 by " << s1 );
+ m_nextRxSequence += s1; // Note data received
+ m_bufferedData.erase (i); // Remove from list
+ if (flags & TcpHeader::FIN)
+ NS_LOG_LOGIC("TcpSocketImpl " << this
+ << " found FIN in buffered");
+ }
+
+ if (m_pendingClose || (origState > ESTABLISHED))
+ { // See if we can close now
+ if (m_bufferedData.empty())
+ {
+ ProcessPacketAction (PEER_CLOSE, p, tcpHeader, fromAddress);
+ }
+ }
+ }
+ else if (SequenceNumber (tcpHeader.GetSequenceNumber ()) >= m_nextRxSequence)
+ { // Need to buffer this one
+ NS_LOG_LOGIC ("Case 2, buffering " << tcpHeader.GetSequenceNumber () );
+ UnAckData_t::iterator i =
+ m_bufferedData.find (tcpHeader.GetSequenceNumber () );
+ if (i != m_bufferedData.end () )
+ {
+ i->second = 0; // relase reference to already buffered
+ }
+ // Save for later delivery
+ m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;
+ }
+ else
+ { // debug
+ NS_LOG_LOGIC("TCP " << this
+ << " got seq " << tcpHeader.GetSequenceNumber ()
+ << " expected " << m_nextRxSequence
+ << " flags " << tcpHeader.GetFlags ());
+ }
+ // Now send a new ack packet acknowledging all received and delivered data
+ if(++m_delAckCount >= m_delAckMaxCount)
+ {
+ m_delAckEvent.Cancel();
+ m_delAckCount = 0;
+ SendEmptyPacket (TcpHeader::ACK);
+ }
+ else
+ {
+ m_delAckEvent = Simulator::Schedule (m_delAckTimout, &TcpSocketImpl::DelAckTimeout, this);
+ }
+}
+
+void TcpSocketImpl::DelAckTimeout ()
+{
+ m_delAckCount = 0;
+ SendEmptyPacket (TcpHeader::ACK);
+}
+
+void TcpSocketImpl::CommonNewAck (SequenceNumber ack, bool skipTimer)
+{ // CommonNewAck is called only for "New" (non-duplicate) acks
+ // and MUST be called by any subclass, from the NewAck function
+ // Always cancel any pending re-tx timer on new acknowledgement
+ NS_LOG_FUNCTION (this << ack << skipTimer);
+ //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl));
+ if (!skipTimer)
+ {
+ 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 "
+ << Simulator::Now ().GetSeconds () << " to expire at time "
+ << (Simulator::Now () + rto).GetSeconds ());
+ m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this);
+ }
+ NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack
+ << " numberAck " << (ack - m_highestRxAck)); // Number bytes ack'ed
+ m_highestRxAck = ack; // Note the highest recieved Ack
+ if (m_wouldBlock)
+ {
+ // m_highestRxAck advancing means some data was acked, and the size
+ // of free space in the buffer has increased
+ NotifySend (GetTxAvailable ());
+ m_wouldBlock = false;
+ }
+ if (ack > m_nextTxSequence)
+ {
+ m_nextTxSequence = ack; // If advanced
+ }
+ // See if all pending ack'ed; if so we can delete the data
+ if (m_pendingData)
+ { // Data exists, see if can be deleted
+ if (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck) == 0)
+ { // All pending acked, can be deleted
+ m_pendingData->Clear ();
+ delete m_pendingData;
+ m_pendingData = 0;
+ // Insure no re-tx timer
+ m_retxEvent.Cancel ();
+ }
+ }
+ // Try to send more data
+ SendPendingData();
+}
+
+Ptr<TcpSocketImpl> TcpSocketImpl::Copy ()
+{
+ return CopyObject<TcpSocketImpl> (this);
+}
+
+void TcpSocketImpl::NewAck (SequenceNumber seq)
+{ // New acknowledgement up to sequence number "seq"
+ // Adjust congestion window in response to new ack's received
+ NS_LOG_FUNCTION (this << seq);
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewAck "
+ << " seq " << seq
+ << " cWnd " << m_cWnd
+ << " ssThresh " << m_ssThresh);
+ if (m_cWnd < m_ssThresh)
+ { // Slow start mode, add one segSize to cWnd
+ m_cWnd += m_segmentSize;
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " NewCWnd SlowStart, cWnd " << m_cWnd
+ << " sst " << m_ssThresh);
+ }
+ else
+ { // Congestion avoidance mode, adjust by (ackBytes*segSize) / cWnd
+ double adder = ((double) m_segmentSize * m_segmentSize) / m_cWnd.Get();
+ if (adder < 1.0)
+ {
+ adder = 1.0;
+ }
+ m_cWnd += (uint32_t) adder;
+ NS_LOG_LOGIC ("NewCWnd CongAvoid, cWnd " << m_cWnd
+ << " sst " << m_ssThresh);
+ }
+ CommonNewAck (seq, false); // Complete newAck processing
+}
+
+void TcpSocketImpl::DupAck (const TcpHeader& t, uint32_t count)
+{
+ NS_LOG_FUNCTION (this << "t " << count);
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " DupAck " << t.GetAckNumber ()
+ << ", count " << count
+ << ", time " << Simulator::Now ());
+ if (count == 3)
+ { // Count of three indicates triple duplicate ack
+ m_ssThresh = Window () / 2; // Per RFC2581
+ m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
+ NS_LOG_LOGIC("TcpSocketImpl " << this << "Tahoe TDA, time " << Simulator::Now ()
+ << " seq " << t.GetAckNumber ()
+ << " in flight " << BytesInFlight ()
+ << " new ssthresh " << m_ssThresh);
+
+ m_cWnd = m_segmentSize; // Collapse cwnd (re-enter slowstart)
+ // For Tahoe, we also reset nextTxSeq
+ m_nextTxSequence = m_highestRxAck;
+ SendPendingData ();
+ }
+}
+
+void TcpSocketImpl::ReTxTimeout ()
+{ // Retransmit timeout
+ NS_LOG_FUNCTION (this);
+ m_ssThresh = Window () / 2; // Per RFC2581
+ m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
+ // Set cWnd to segSize on timeout, per rfc2581
+ // Collapse congestion window (re-enter slowstart)
+ m_cWnd = m_segmentSize;
+ m_nextTxSequence = m_highestRxAck; // Start from highest Ack
+ m_rtt->IncreaseMultiplier (); // DoubleValue timeout value for next retx timer
+ Retransmit (); // Retransmit the packet
+}
+
+void TcpSocketImpl::LastAckTimeout ()
+{
+ m_lastAckEvent.Cancel ();
+ if (m_state == LAST_ACK)
+ {
+ Actions_t action = ProcessEvent (TIMEOUT);
+ ProcessAction (action);
+ }
+ if (!m_closeNotified)
+ {
+ m_closeNotified = true;
+ }
+}
+
+void TcpSocketImpl::Retransmit ()
+{
+ NS_LOG_FUNCTION (this);
+ uint8_t flags = TcpHeader::NONE;
+ if (m_state == SYN_SENT)
+ {
+ if (m_cnCount > 0)
+ {
+ SendEmptyPacket (TcpHeader::SYN);
+ return;
+ }
+ else
+ {
+ NotifyConnectionFailed ();
+ return;
+ }
+ }
+ if (!m_pendingData)
+ {
+ if (m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2)
+ { // Must have lost FIN, re-send
+ SendEmptyPacket (TcpHeader::FIN);
+ }
+ return;
+ }
+ Ptr<Packet> p = m_pendingData->CopyFromSeq (m_segmentSize,
+ m_firstPendingSequence,
+ m_highestRxAck);
+ // Calculate remaining data for COE check
+ uint32_t remainingData = m_pendingData->SizeFromSeq (
+ m_firstPendingSequence,
+ m_nextTxSequence + SequenceNumber(p->GetSize ()));
+ if (m_closeOnEmpty && remainingData == 0)
+ { // Add the FIN flag
+ flags = flags | TcpHeader::FIN;
+ }
+
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " retxing seq " << m_highestRxAck);
+ if (m_retxEvent.IsExpired () )
+ {
+ Time rto = m_rtt->RetransmitTimeout ();
+ NS_LOG_LOGIC ("Schedule retransmission timeout at time "
+ << Simulator::Now ().GetSeconds () << " to expire at time "
+ << (Simulator::Now () + rto).GetSeconds ());
+ m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this);
+ }
+ m_rtt->SentSeq (m_highestRxAck,p->GetSize ());
+ // And send the packet
+ TcpHeader tcpHeader;
+ tcpHeader.SetSequenceNumber (m_nextTxSequence);
+ tcpHeader.SetAckNumber (m_nextRxSequence);
+ tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
+ tcpHeader.SetDestinationPort (m_remotePort);
+ tcpHeader.SetFlags (flags);
+ tcpHeader.SetWindowSize (m_advertisedWindowSize);
+
+ m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
+ m_remoteAddress);
+}
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet-node/tcp-socket-impl.h Tue May 20 11:52:25 2008 -0700
@@ -0,0 +1,197 @@
+/* -*- 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>
+ */
+#ifndef TCP_SOCKET_IMPL_H
+#define TCP_SOCKET_IMPL_H
+
+#include <stdint.h>
+#include <queue>
+#include "ns3/callback.h"
+#include "ns3/traced-value.h"
+#include "ns3/socket.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/event-id.h"
+#include "tcp-typedefs.h"
+#include "pending-data.h"
+#include "sequence-number.h"
+#include "rtt-estimator.h"
+
+
+namespace ns3 {
+
+class Ipv4EndPoint;
+class Node;
+class Packet;
+class TcpL4Protocol;
+class TcpHeader;
+
+class TcpSocketImpl : public Socket
+{
+public:
+ static TypeId GetTypeId (void);
+ /**
+ * Create an unbound tcp socket.
+ */
+ TcpSocketImpl ();
+ TcpSocketImpl (const TcpSocketImpl& sock);
+ virtual ~TcpSocketImpl ();
+
+ void SetNode (Ptr<Node> node);
+ void SetTcp (Ptr<TcpL4Protocol> tcp);
+ void SetRtt (Ptr<RttEstimator> rtt);
+
+ virtual enum SocketErrno GetErrno (void) const;
+ virtual Ptr<Node> GetNode (void) const;
+ virtual int Bind (void);
+ virtual int Bind (const Address &address);
+ virtual int Close (void);
+ virtual int ShutdownSend (void);
+ virtual int ShutdownRecv (void);
+ virtual int Connect(const Address &address);
+ virtual int Send (Ptr<Packet> p);
+ virtual int Send (const uint8_t* buf, uint32_t size);
+ virtual int SendTo(Ptr<Packet> p, const Address &address);
+ virtual uint32_t GetTxAvailable (void) const;
+ virtual int Listen(uint32_t queueLimit);
+
+ virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags);
+ virtual uint32_t GetRxAvailable (void) const;
+
+protected:
+ virtual void SetSndBuf (uint32_t size);
+ virtual uint32_t GetSndBuf (void) const;
+ virtual void SetRcvBuf (uint32_t size);
+ virtual uint32_t GetRcvBuf (void) const;
+
+private:
+ friend class Tcp;
+ // invoked by Tcp class
+ int FinishBind (void);
+ void ForwardUp (Ptr<Packet> p, Ipv4Address ipv4, uint16_t port);
+ void Destroy (void);
+ int DoSendTo (Ptr<Packet> p, const Address &daddr);
+ int DoSendTo (Ptr<Packet> p, Ipv4Address daddr, uint16_t dport);
+ void SendEmptyPacket(uint8_t flags);
+ //methods for state
+ bool ProcessAction (Actions_t a);
+ bool ProcessAction (Actions_t a, const TcpHeader& tcpHeader,
+ Ipv4Address saddr, Ipv4Address daddr);
+ bool ProcessPacketAction (Actions_t a, Ptr<Packet> p,
+ const TcpHeader& tcpHeader,
+ const Address& fromAddress);
+ Actions_t ProcessEvent (Events_t e);
+ bool SendPendingData(bool withAck = false);
+ void CompleteFork(Ptr<Packet>, const TcpHeader&, const Address& fromAddress);
+ void ConnectionSucceeded();
+
+ //methods for window management
+ virtual uint32_t UnAckDataCount(); // Return count of number of unacked bytes
+ virtual uint32_t BytesInFlight(); // Return total bytes in flight
+ virtual uint32_t Window(); // Return window size (integer)
+ virtual uint32_t AvailableWindow();// Return unfilled portion of window
+
+ // Manage data tx/rx
+ void NewRx (Ptr<Packet>, const TcpHeader&, const Address&);
+ // XXX This should be virtual and overridden
+ Ptr<TcpSocketImpl> Copy ();
+ void NewAck (SequenceNumber seq);
+ // XXX This should be virtual and overridden
+ void DupAck (const TcpHeader& t, uint32_t count);
+ void ReTxTimeout ();
+ void DelAckTimeout ();
+ void LastAckTimeout ();
+ void Retransmit ();
+ void CommonNewAck (SequenceNumber seq, bool skipTimer = false);
+
+ bool m_skipRetxResched;
+ uint32_t m_dupAckCount;
+ EventId m_retxEvent;
+ EventId m_lastAckEvent;
+
+ EventId m_delAckEvent;
+ uint32_t m_delAckCount;
+ uint32_t m_delAckMaxCount;
+ Time m_delAckTimout;
+
+ Ipv4EndPoint *m_endPoint;
+ Ptr<Node> m_node;
+ Ptr<TcpL4Protocol> m_tcp;
+ Ipv4Address m_remoteAddress;
+ uint16_t m_remotePort;
+ //these two are so that the socket/endpoint cloning works
+ Ipv4Address m_localAddress;
+ uint16_t m_localPort;
+ enum SocketErrno m_errno;
+ bool m_shutdownSend;
+ bool m_shutdownRecv;
+ bool m_connected;
+
+ //manage the state infomation
+ States_t m_state;
+ bool m_closeNotified;
+ bool m_closeRequestNotified;
+ bool m_closeOnEmpty;
+ bool m_pendingClose;
+
+
+ //sequence info, sender side
+ SequenceNumber m_nextTxSequence;
+ SequenceNumber m_highTxMark;
+ SequenceNumber m_highestRxAck;
+ SequenceNumber m_lastRxAck;
+
+ //sequence info, reciever side
+ SequenceNumber m_nextRxSequence;
+
+ //history data
+ //this is the incoming data buffer which sorts out of sequence data
+ UnAckData_t m_bufferedData;
+ //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
+ TracedValue<uint32_t> m_cWnd; //Congestion window
+ uint32_t m_ssThresh; //Slow Start Threshold
+ uint32_t m_initialCWnd; //Initial cWnd value
+
+ // Round trip time estimation
+ Ptr<RttEstimator> m_rtt;
+ Time m_lastMeasuredRtt;
+
+ // Timer-related members
+ Time m_cnTimeout;
+ uint32_t m_cnCount;
+
+ // Temporary queue for delivering data to application
+ std::queue<Ptr<Packet> > m_deliveryQueue;
+ uint32_t m_rxAvailable;
+
+ uint32_t m_sndBufLimit; // buffer limit for the outgoing queue
+ uint32_t m_rcvBufLimit; // maximum receive socket buffer size
+ bool m_wouldBlock; // set to true whenever socket would block on send()
+};
+
+}//namespace ns3
+
+#endif /* TCP_SOCKET_IMPL_H */
--- a/src/internet-node/tcp-socket.cc Tue May 20 10:30:40 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1354 +0,0 @@
-/* -*- 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 "ns3/node.h"
-#include "ns3/inet-socket-address.h"
-#include "ns3/log.h"
-#include "ns3/ipv4.h"
-#include "tcp-socket.h"
-#include "tcp-l4-protocol.h"
-#include "ipv4-end-point.h"
-#include "ipv4-l4-demux.h"
-#include "ns3/simulation-singleton.h"
-#include "tcp-typedefs.h"
-#include "ns3/simulator.h"
-#include "ns3/packet.h"
-#include "ns3/uinteger.h"
-#include "ns3/trace-source-accessor.h"
-
-#include <algorithm>
-
-NS_LOG_COMPONENT_DEFINE ("TcpSocket");
-
-using namespace std;
-
-namespace ns3 {
-
-NS_OBJECT_ENSURE_REGISTERED (TcpSocket);
-
-TypeId
-TcpSocket::GetTypeId ()
-{
- static TypeId tid = TypeId("ns3::TcpSocket")
- .SetParent<Socket> ()
- .AddTraceSource ("CongestionWindow",
- "The TCP connection's congestion window",
- MakeTraceSourceAccessor (&TcpSocket::m_cWnd))
- ;
- return tid;
-}
-
- TcpSocket::TcpSocket ()
- : m_skipRetxResched (false),
- m_dupAckCount (0),
- m_delAckCount (0),
- m_endPoint (0),
- m_node (0),
- m_tcp (0),
- m_errno (ERROR_NOTERROR),
- m_shutdownSend (false),
- m_shutdownRecv (false),
- m_connected (false),
- m_state (CLOSED),
- m_closeNotified (false),
- m_closeRequestNotified (false),
- m_closeOnEmpty (false),
- m_pendingClose (false),
- m_nextTxSequence (0),
- m_highTxMark (0),
- m_highestRxAck (0),
- m_lastRxAck (0),
- m_nextRxSequence (0),
- m_pendingData (0),
- m_rtt (0),
- m_lastMeasuredRtt (Seconds(0.0)),
- m_rxAvailable (0),
- m_sndBufLimit (0xffffffff),
- m_rcvBufLimit (0xffffffff),
- m_wouldBlock (false)
-{
- NS_LOG_FUNCTION (this);
-
-}
-
-TcpSocket::TcpSocket(const TcpSocket& sock)
- : Socket(sock), //copy the base class callbacks
- m_skipRetxResched (sock.m_skipRetxResched),
- m_dupAckCount (sock.m_dupAckCount),
- m_delAckCount (0),
- m_delAckMaxCount (sock.m_delAckMaxCount),
- m_delAckTimout (sock.m_delAckTimout),
- m_endPoint (0),
- m_node (sock.m_node),
- m_tcp (sock.m_tcp),
- m_remoteAddress (sock.m_remoteAddress),
- m_remotePort (sock.m_remotePort),
- m_localAddress (sock.m_localAddress),
- m_localPort (sock.m_localPort),
- m_errno (sock.m_errno),
- m_shutdownSend (sock.m_shutdownSend),
- m_shutdownRecv (sock.m_shutdownRecv),
- m_connected (sock.m_connected),
- m_state (sock.m_state),
- m_closeNotified (sock.m_closeNotified),
- m_closeRequestNotified (sock.m_closeRequestNotified),
- m_closeOnEmpty (sock.m_closeOnEmpty),
- m_pendingClose (sock.m_pendingClose),
- m_nextTxSequence (sock.m_nextTxSequence),
- m_highTxMark (sock.m_highTxMark),
- m_highestRxAck (sock.m_highestRxAck),
- m_lastRxAck (sock.m_lastRxAck),
- m_nextRxSequence (sock.m_nextRxSequence),
- 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_rtt (0),
- m_lastMeasuredRtt (Seconds(0.0)),
- m_cnTimeout (sock.m_cnTimeout),
- m_cnCount (sock.m_cnCount),
- m_rxAvailable (0),
- m_sndBufLimit (0xffffffff),
- m_rcvBufLimit (0xffffffff)
-{
- NS_LOG_FUNCTION_NOARGS ();
- NS_LOG_LOGIC("Invoked the copy constructor");
- //copy the pending data if necessary
- if(sock.m_pendingData)
- {
- m_pendingData = sock.m_pendingData->Copy();
- }
- //copy the rtt if necessary
- if (sock.m_rtt)
- {
- m_rtt = sock.m_rtt->Copy();
- }
- //can't "copy" the endpoint just yes, must do this when we know the peer info
- //too; this is in SYN_ACK_TX
-}
-
-TcpSocket::~TcpSocket ()
-{
- NS_LOG_FUNCTION(this);
- m_node = 0;
- if (m_endPoint != 0)
- {
- NS_ASSERT (m_tcp != 0);
- /**
- * Note that this piece of code is a bit tricky:
- * when DeAllocate is called, it will call into
- * Ipv4EndPointDemux::Deallocate which triggers
- * a delete of the associated endPoint which triggers
- * in turn a call to the method ::Destroy below
- * will will zero the m_endPoint field.
- */
- NS_ASSERT (m_endPoint != 0);
- m_tcp->DeAllocate (m_endPoint);
- NS_ASSERT (m_endPoint == 0);
- }
- m_tcp = 0;
- delete m_pendingData; //prevents leak
- m_pendingData = 0;
-}
-
-void
-TcpSocket::SetNode (Ptr<Node> node)
-{
- m_node = node;
- Ptr<Tcp> t = node->GetObject<Tcp> ();
- m_segmentSize = t->GetDefaultSegSize ();
- m_rxWindowSize = t->GetDefaultAdvWin ();
- m_advertisedWindowSize = t->GetDefaultAdvWin ();
- m_cWnd = t->GetDefaultInitialCwnd () * m_segmentSize;
- m_ssThresh = t->GetDefaultSsThresh ();
- m_initialCWnd = t->GetDefaultInitialCwnd ();
- m_cnTimeout = Seconds (t->GetDefaultConnTimeout ());
- m_cnCount = t->GetDefaultConnCount ();
- m_delAckTimout = Seconds(t->GetDefaultDelAckTimeout ());
- m_delAckMaxCount = t->GetDefaultDelAckCount ();
-}
-
-void
-TcpSocket::SetTcp (Ptr<TcpL4Protocol> tcp)
-{
- m_tcp = tcp;
-}
-void
-TcpSocket::SetRtt (Ptr<RttEstimator> rtt)
-{
- m_rtt = rtt;
-}
-
-
-enum Socket::SocketErrno
-TcpSocket::GetErrno (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_errno;
-}
-
-Ptr<Node>
-TcpSocket::GetNode (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_node;
-}
-
-void
-TcpSocket::Destroy (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- m_node = 0;
- m_endPoint = 0;
- m_tcp = 0;
- m_retxEvent.Cancel ();
-}
-int
-TcpSocket::FinishBind (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- if (m_endPoint == 0)
- {
- return -1;
- }
- m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr<TcpSocket>(this)));
- m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr<TcpSocket>(this)));
- m_localAddress = m_endPoint->GetLocalAddress ();
- m_localPort = m_endPoint->GetLocalPort ();
- return 0;
-}
-
-int
-TcpSocket::Bind (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- m_endPoint = m_tcp->Allocate ();
- return FinishBind ();
-}
-int
-TcpSocket::Bind (const Address &address)
-{
- NS_LOG_FUNCTION (this<<address);
- if (!InetSocketAddress::IsMatchingType (address))
- {
- return ERROR_INVAL;
- }
- InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
- Ipv4Address ipv4 = transport.GetIpv4 ();
- uint16_t port = transport.GetPort ();
- if (ipv4 == Ipv4Address::GetAny () && port == 0)
- {
- m_endPoint = m_tcp->Allocate ();
- NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
- }
- else if (ipv4 == Ipv4Address::GetAny () && port != 0)
- {
- m_endPoint = m_tcp->Allocate (port);
- NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
- }
- else if (ipv4 != Ipv4Address::GetAny () && port == 0)
- {
- m_endPoint = m_tcp->Allocate (ipv4);
- NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
- }
- else if (ipv4 != Ipv4Address::GetAny () && port != 0)
- {
- m_endPoint = m_tcp->Allocate (ipv4, port);
- NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
- }
-
- return FinishBind ();
-}
-
-int
-TcpSocket::ShutdownSend (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- m_shutdownSend = true;
- return 0;
-}
-int
-TcpSocket::ShutdownRecv (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- m_shutdownRecv = false;
- return 0;
-}
-
-int
-TcpSocket::Close (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
- if (m_state == CLOSED)
- {
- return -1;
- }
- if (m_pendingData && m_pendingData->Size() != 0)
- { // App close with pending data must wait until all data transmitted
- m_closeOnEmpty = true;
- NS_LOG_LOGIC("Socket " << this <<
- " deferring close, state " << m_state);
- return 0;
- }
-
- Actions_t action = ProcessEvent (APP_CLOSE);
- ProcessAction (action);
- ShutdownSend ();
- return 0;
-}
-
-int
-TcpSocket::Connect (const Address & address)
-{
- NS_LOG_FUNCTION (this << address);
- if (m_endPoint == 0)
- {
- if (Bind () == -1)
- {
- NS_ASSERT (m_endPoint == 0);
- return -1;
- }
- NS_ASSERT (m_endPoint != 0);
- }
- InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
- m_remoteAddress = transport.GetIpv4 ();
- m_remotePort = transport.GetPort ();
-
- uint32_t localIfIndex;
- Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
-
- if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
- {
- m_endPoint->SetLocalAddress (ipv4->GetAddress (localIfIndex));
- }
- else
- {
- m_errno = ERROR_NOROUTETOHOST;
- return -1;
- }
-
- Actions_t action = ProcessEvent (APP_CONNECT);
- bool success = ProcessAction (action);
- if (success)
- {
- return 0;
- }
- return -1;
-}
-int
-TcpSocket::Send (const Ptr<Packet> p) //p here is just data, no headers
-{ // TCP Does not deal with packets from app, just data
- return Send(p->PeekData(), p->GetSize());
-}
-
-int TcpSocket::Send (const uint8_t* buf, uint32_t size)
-{
- NS_LOG_FUNCTION (this << buf << size);
- if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT)
- {
- if (size > GetTxAvailable ())
- {
- m_wouldBlock = true;
- m_errno = ERROR_MSGSIZE;
- return -1;
- }
- if (!m_pendingData)
- {
- m_pendingData = new PendingData (); // Create if non-existent
- m_firstPendingSequence = m_nextTxSequence; // Note seq of first
- }
- //PendingData::Add always copies the data buffer, never modifies
- m_pendingData->Add (size,buf);
- NS_LOG_DEBUG("TcpSock::Send, pdsize " << m_pendingData->Size() <<
- " state " << m_state);
- Actions_t action = ProcessEvent (APP_SEND);
- NS_LOG_DEBUG(" action " << action);
- if (!ProcessAction (action))
- {
- return -1; // Failed, return zero
- }
- return size;
- }
- else
- {
- m_errno = ERROR_NOTCONN;
- return -1;
- }
-}
-
-int TcpSocket::DoSendTo (Ptr<Packet> p, const Address &address)
-{
- NS_LOG_FUNCTION (this << p << address);
- InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
- Ipv4Address ipv4 = transport.GetIpv4 ();
- uint16_t port = transport.GetPort ();
- return DoSendTo (p, ipv4, port);
-}
-
-int TcpSocket::DoSendTo (Ptr<Packet> p, Ipv4Address ipv4, uint16_t port)
-{
- NS_LOG_FUNCTION (this << p << ipv4 << port);
- if (m_endPoint == 0)
- {
- if (Bind () == -1)
- {
- NS_ASSERT (m_endPoint == 0);
- return -1;
- }
- NS_ASSERT (m_endPoint != 0);
- }
- if (m_shutdownSend)
- {
- m_errno = ERROR_SHUTDOWN;
- return -1;
- }
- m_tcp->Send (p, m_endPoint->GetLocalAddress (), ipv4,
- m_endPoint->GetLocalPort (), port);
- NotifyDataSent (p->GetSize ());
- return 0;
-}
-
-int
-TcpSocket::SendTo (Ptr<Packet> p, const Address &address)
-{
- NS_LOG_FUNCTION (this << address << p);
- if (!m_connected)
- {
- m_errno = ERROR_NOTCONN;
- return -1;
- }
- else
- {
- return Send (p); //drop the address according to BSD manpages
- }
-}
-
-uint32_t
-TcpSocket::GetTxAvailable (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- if (m_pendingData != 0)
- {
- uint32_t unAckedDataSize =
- m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck);
- NS_ASSERT (m_sndBufLimit >= unAckedDataSize); //else a logical error
- return m_sndBufLimit-unAckedDataSize;
- }
- else
- {
- return m_sndBufLimit;
- }
-}
-
-int
-TcpSocket::Listen (uint32_t q)
-{
- NS_LOG_FUNCTION (this << q);
- Actions_t action = ProcessEvent (APP_LISTEN);
- ProcessAction (action);
- return 0;
-}
-
-Ptr<Packet>
-TcpSocket::Recv (uint32_t maxSize, uint32_t flags)
-{
- NS_LOG_FUNCTION_NOARGS ();
- if (m_deliveryQueue.empty() )
- {
- return 0;
- }
- Ptr<Packet> p = m_deliveryQueue.front ();
- if (p->GetSize () <= maxSize)
- {
- m_deliveryQueue.pop ();
- m_rxAvailable -= p->GetSize ();
- }
- else
- {
- p = 0;
- }
- return p;
-}
-
-uint32_t
-TcpSocket::GetRxAvailable (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- // We separately maintain this state to avoid walking the queue
- // every time this might be called
- return m_rxAvailable;
-}
-
-void
-TcpSocket::SetSndBuf (uint32_t size)
-{
- NS_LOG_FUNCTION_NOARGS ();
- m_sndBufLimit = size;
-}
-
-uint32_t
-TcpSocket::GetSndBuf (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_sndBufLimit;
-}
-
-void
-TcpSocket::SetRcvBuf (uint32_t size)
-{
- NS_LOG_FUNCTION_NOARGS ();
- m_rcvBufLimit = size;
-}
-
-uint32_t
-TcpSocket::GetRcvBuf (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_rcvBufLimit;
-}
-
-void
-TcpSocket::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
-{
- NS_LOG_DEBUG("Socket " << this << " got forward up" <<
- " dport " << m_endPoint->GetLocalPort() <<
- " daddr " << m_endPoint->GetLocalAddress() <<
- " sport " << m_endPoint->GetPeerPort() <<
- " saddr " << m_endPoint->GetPeerAddress());
-
- NS_LOG_FUNCTION (this << packet << ipv4 << port);
- if (m_shutdownRecv)
- {
- return;
- }
- TcpHeader tcpHeader;
- packet->RemoveHeader (tcpHeader);
-
- if (tcpHeader.GetFlags () & TcpHeader::ACK)
- {
- Time m = m_rtt->AckSeq (tcpHeader.GetAckNumber () );
- if (m != Seconds (0.0))
- {
- m_lastMeasuredRtt = m;
- }
- }
-
- Events_t event = SimulationSingleton<TcpStateMachine>::Get ()->FlagsEvent (tcpHeader.GetFlags () );
- Actions_t action = ProcessEvent (event); //updates the state
- Address address = InetSocketAddress (ipv4, port);
- NS_LOG_DEBUG("Socket " << this <<
- " processing pkt action, " << action <<
- " current state " << m_state);
- ProcessPacketAction (action, packet, tcpHeader, address);
-}
-
-Actions_t TcpSocket::ProcessEvent (Events_t e)
-{
- NS_LOG_FUNCTION (this << e);
- States_t saveState = m_state;
- NS_LOG_LOGIC ("TcpSocket " << this << " processing event " << e);
- // simulation singleton is a way to get a single global static instance of a
- // class intended to be a singleton; see simulation-singleton.h
- SA stateAction = SimulationSingleton<TcpStateMachine>::Get ()->Lookup (m_state,e);
- // debug
- if (stateAction.action == RST_TX)
- {
- NS_LOG_LOGIC ("TcpSocket " << this << " sending RST from state "
- << saveState << " event " << e);
- }
- bool needCloseNotify = (stateAction.state == CLOSED && m_state != CLOSED
- && e != TIMEOUT);
- m_state = stateAction.state;
- NS_LOG_LOGIC ("TcpSocket " << this << " moved from state " << saveState
- << " to state " <<m_state);
- NS_LOG_LOGIC ("TcpSocket " << this << " pendingData " << m_pendingData);
-
- //extra event logic is here for RX events
- //e = SYN_ACK_RX
- if (saveState == SYN_SENT && m_state == ESTABLISHED)
- // this means the application side has completed its portion of
- // the handshaking
- {
- Simulator::ScheduleNow(&TcpSocket::ConnectionSucceeded, this);
- //NotifyConnectionSucceeded ();
- m_connected = true;
- m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
- NS_LOG_LOGIC ("TcpSocket " << this << " Connected!");
- }
-
- if (needCloseNotify && !m_closeNotified)
- {
- NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from "
- << m_state << " event " << e << " closeNot " << m_closeNotified
- << " action " << stateAction.action);
- NotifyCloseCompleted ();
- m_closeNotified = true;
- NS_LOG_LOGIC ("TcpSocket " << this << " calling Closed from PE"
- << " origState " << saveState
- << " event " << e);
- NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from "
- << m_state << " event " << e
- << " set CloseNotif ");
- }
- return stateAction.action;
-}
-
-void TcpSocket::SendEmptyPacket (uint8_t flags)
-{
- NS_LOG_FUNCTION (this << flags);
- Ptr<Packet> p = Create<Packet> ();
- TcpHeader header;
-
- header.SetFlags (flags);
- header.SetSequenceNumber (m_nextTxSequence);
- header.SetAckNumber (m_nextRxSequence);
- header.SetSourcePort (m_endPoint->GetLocalPort ());
- header.SetDestinationPort (m_remotePort);
- header.SetWindowSize (m_advertisedWindowSize);
- m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (),
- m_remoteAddress);
- Time rto = m_rtt->RetransmitTimeout ();
- if (flags & TcpHeader::SYN)
- {
- rto = m_cnTimeout;
- m_cnTimeout = m_cnTimeout + m_cnTimeout;
- m_cnCount--;
- }
- if (m_retxEvent.IsExpired () ) //no outstanding timer
- {
- NS_LOG_LOGIC ("Schedule retransmission timeout at time "
- << Simulator::Now ().GetSeconds () << " to expire at time "
- << (Simulator::Now () + rto).GetSeconds ());
- m_retxEvent = Simulator::Schedule (rto, &TcpSocket::ReTxTimeout, this);
- }
-}
-
-bool TcpSocket::ProcessAction (Actions_t a)
-{ // These actions do not require a packet or any TCP Headers
- NS_LOG_FUNCTION (this << a);
- switch (a)
- {
- case NO_ACT:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action: NO_ACT");
- break;
- case ACK_TX:
- SendEmptyPacket (TcpHeader::ACK);
- break;
- case ACK_TX_1:
- NS_ASSERT (false); // This should be processed in ProcessPacketAction
- break;
- case RST_TX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action RST_TX");
- SendEmptyPacket (TcpHeader::RST);
- break;
- case SYN_TX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_TX");
- // TCP SYN Flag consumes one byte
- // is the above correct? we're SENDING a syn, not acking back -- Raj
- // commented out for now
- // m_nextTxSequence+= 1;
- SendEmptyPacket (TcpHeader::SYN);
- break;
- case SYN_ACK_TX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX");
- // TCP SYN Flag consumes one byte
- ++m_nextRxSequence;
- SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
- break;
- case FIN_TX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_TX");
- SendEmptyPacket (TcpHeader::FIN);
- break;
- case FIN_ACK_TX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_ACK_TX");
- SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK);
- break;
- case NEW_ACK:
- NS_ASSERT (false); // This should be processed in ProcessPacketAction
- break;
- case NEW_SEQ_RX:
- NS_ASSERT (false); // This should be processed in ProcessPacketAction
- break;
- case RETX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action RETX");
- break;
- case TX_DATA:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action TX_DATA");
- SendPendingData ();
- break;
- case PEER_CLOSE:
- NS_ASSERT (false); // This should be processed in ProcessPacketAction
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action PEER_CLOSE");
- break;
- case APP_CLOSED:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_CLOSED");
- break;
- case CANCEL_TM:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action CANCEL_TM");
- break;
- case APP_NOTIFY:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_NOTIFY");
- break;
- case SERV_NOTIFY:
- NS_ASSERT (false); // This should be processed in ProcessPacketAction
- break;
- case LAST_ACTION:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action LAST_ACTION");
- break;
- }
- return true;
-}
-
-bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
- const TcpHeader& tcpHeader,
- const Address& fromAddress)
-{
- NS_LOG_FUNCTION (this << a << p << fromAddress);
- uint32_t localIfIndex;
- Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
- switch (a)
- {
- case SYN_ACK_TX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX");
-// m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
-// m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
-// if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
-// {
-// m_localAddress = ipv4->GetAddress (localIfIndex);
-// }
- if (m_state == LISTEN) //this means we should fork a new TcpSocket
- {
- NS_LOG_DEBUG("In SYN_ACK_TX, m_state is LISTEN, this " << this);
- //notify the server that we got a SYN
- // If server refuses connection do nothing
- if (!NotifyConnectionRequest(fromAddress)) return true;
- // Clone the socket
- Ptr<TcpSocket> newSock = Copy ();
- NS_LOG_LOGIC ("Cloned a TcpSocket " << newSock);
- //this listening socket should do nothing more
- Simulator::ScheduleNow (&TcpSocket::CompleteFork, newSock,
- p, tcpHeader,fromAddress);
- return true;
- }
- // This is the cloned endpoint
- m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
- if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
- {
- m_localAddress = ipv4->GetAddress (localIfIndex);
- m_endPoint->SetLocalAddress (m_localAddress);
- // Leave local addr in the portmap to any, as the path from
- // remote can change and packets can arrive on different interfaces
- //m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
- }
- // TCP SYN consumes one byte
- m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
- SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
- break;
- case ACK_TX_1:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action ACK_TX_1");
- // TCP SYN consumes one byte
- m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
- m_nextTxSequence = tcpHeader.GetAckNumber ();
- m_firstPendingSequence = m_nextTxSequence; //bug 166
- NS_LOG_DEBUG ("TcpSocket " << this << " ACK_TX_1" <<
- " nextRxSeq " << m_nextRxSequence);
- SendEmptyPacket (TcpHeader::ACK);
- m_rxWindowSize = tcpHeader.GetWindowSize ();
- if (tcpHeader.GetAckNumber () > m_highestRxAck)
- {
- m_highestRxAck = tcpHeader.GetAckNumber ();
- // Data freed from the send buffer; notify any blocked sender
- if (m_wouldBlock)
- {
- NotifySend (GetTxAvailable ());
- m_wouldBlock = false;
- }
- }
- SendPendingData ();
- break;
- case NEW_ACK:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_ACK_TX");
- if (tcpHeader.GetAckNumber () < m_highestRxAck) //old ack, do nothing
- {
- break;
- }
- if (tcpHeader.GetAckNumber () == m_highestRxAck &&
- tcpHeader.GetAckNumber () < m_nextTxSequence)
- {
- DupAck (tcpHeader, ++m_dupAckCount);
- break;
- }
- if (tcpHeader.GetAckNumber () > m_highestRxAck)
- {
- m_dupAckCount = 0;
- }
- NewAck (tcpHeader.GetAckNumber ());
- break;
- case NEW_SEQ_RX:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_SEQ_RX");
- NewRx (p, tcpHeader, fromAddress); // Process new data received
- break;
- case PEER_CLOSE:
- {
- // First we have to be sure the FIN packet was not received
- // out of sequence. If so, note pending close and process
- // new sequence rx
- if (tcpHeader.GetSequenceNumber () != m_nextRxSequence)
- { // process close later
- m_pendingClose = true;
- NS_LOG_LOGIC ("TcpSocket " << this << " setting pendingClose"
- << " rxseq " << tcpHeader.GetSequenceNumber ()
- << " nextRxSeq " << m_nextRxSequence);
- NewRx (p, tcpHeader, fromAddress);
- return true;
- }
- // Now we need to see if any data came with the FIN
- // if so, call NewRx
- if (p->GetSize () != 0)
- {
- NewRx (p, tcpHeader, fromAddress);
- }
- States_t saveState = m_state; // Used to see if app responds
- NS_LOG_LOGIC ("TcpSocket " << this
- << " peer close, state " << m_state);
- if (!m_closeRequestNotified)
- {
- NS_LOG_LOGIC ("TCP " << this
- << " calling AppCloseRequest");
- NotifyCloseRequested();
- m_closeRequestNotified = true;
- }
- NS_LOG_LOGIC ("TcpSocket " << this
- << " peer close, state after " << m_state);
- if (m_state == saveState)
- { // Need to ack, the application will close later
- SendEmptyPacket (TcpHeader::ACK);
-// // Also need to re-tx the ack if we
- }
- if (m_state == LAST_ACK)
- {
- NS_LOG_LOGIC ("TcpSocket " << this << " scheduling LATO1");
- m_lastAckEvent = Simulator::Schedule (m_rtt->RetransmitTimeout (),
- &TcpSocket::LastAckTimeout,this);
- }
- break;
- }
- case SERV_NOTIFY:
- NS_LOG_LOGIC ("TcpSocket " << this <<" Action SERV_NOTIFY");
- NS_LOG_LOGIC ("TcpSocket " << this << " Connected!");
- NotifyNewConnectionCreated (this, fromAddress);
- m_connected = true; // ! This is bogus; fix when we clone the tcp
- m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
- //treat the connection orientation final ack as a newack
- CommonNewAck (tcpHeader.GetAckNumber (), true);
- break;
- default:
- break;
- }
- return true;
-}
-
-void TcpSocket::CompleteFork(Ptr<Packet> p, const TcpHeader& h, const Address& fromAddress)
-{
- // Get port and address from peer (connecting host)
- m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
- m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
- m_endPoint = m_tcp->Allocate (m_localAddress,
- m_localPort,
- m_remoteAddress,
- m_remotePort);
- //the cloned socket with be in listen state, so manually change state
- m_state = SYN_RCVD;
- //equivalent to FinishBind
- m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr<TcpSocket>(this)));
- m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr<TcpSocket>(this)));
- ProcessPacketAction(SYN_ACK_TX, p, h, fromAddress);
- }
-
-void TcpSocket::ConnectionSucceeded()
-{ // We would preferred to have scheduled an event directly to
- // NotifyConnectionSucceeded, but (sigh) these are protected
- // and we can get the address of it :(
- NotifyConnectionSucceeded();
-}
-
-bool TcpSocket::SendPendingData (bool withAck)
-{
- NS_LOG_FUNCTION (this << withAck);
- NS_LOG_LOGIC ("ENTERING SendPendingData");
- if (!m_pendingData)
- {
- return false; // No data exists
- }
- uint32_t nPacketsSent = 0;
- while (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence))
- {
- uint32_t w = AvailableWindow ();// Get available window size
- NS_LOG_LOGIC ("TcpSocket " << this << " SendPendingData"
- << " w " << w
- << " rxwin " << m_rxWindowSize
- << " cWnd " << m_cWnd
- << " segsize " << m_segmentSize
- << " nextTxSeq " << m_nextTxSequence
- << " highestRxAck " << m_highestRxAck
- << " pd->Size " << m_pendingData->Size ()
- << " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence));
-
- if (w < m_segmentSize && m_pendingData->Size () > w)
- {
- break; // No more
- }
- uint32_t s = std::min (w, m_segmentSize); // Send no more than window
- Ptr<Packet> p = m_pendingData->CopyFromSeq (s, m_firstPendingSequence,
- m_nextTxSequence);
- NS_LOG_LOGIC("TcpSocket " << this << " sendPendingData"
- << " txseq " << m_nextTxSequence
- << " s " << s
- << " datasize " << p->GetSize() );
- uint8_t flags = 0;
- if (withAck)
- {
- flags |= TcpHeader::ACK;
- }
- uint32_t sz = p->GetSize (); // Size of packet
- uint32_t remainingData = m_pendingData->SizeFromSeq(
- m_firstPendingSequence,
- m_nextTxSequence + SequenceNumber (sz));
- if (m_closeOnEmpty && (remainingData == 0))
- {
- flags = TcpHeader::FIN;
- m_state = FIN_WAIT_1;
- }
-
- TcpHeader header;
- header.SetFlags (flags);
- header.SetSequenceNumber (m_nextTxSequence);
- header.SetAckNumber (m_nextRxSequence);
- header.SetSourcePort (m_endPoint->GetLocalPort());
- header.SetDestinationPort (m_remotePort);
- if (m_shutdownSend)
- {
- m_errno = ERROR_SHUTDOWN;
- return -1;
- }
-
-
- if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit
- {
- Time rto = m_rtt->RetransmitTimeout ();
- NS_LOG_LOGIC ("Schedule retransmission timeout at time " <<
- Simulator::Now ().GetSeconds () << " to expire at time " <<
- (Simulator::Now () + rto).GetSeconds () );
- m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this);
- }
- NS_LOG_LOGIC ("About to send a packet with flags: " << flags);
- m_tcp->SendPacket (p, header,
- m_endPoint->GetLocalAddress (),
- m_remoteAddress);
- m_rtt->SentSeq(m_nextTxSequence, sz); // notify the RTT
- // Notify the application
- Simulator::ScheduleNow(&TcpSocket::NotifyDataSent, this, p->GetSize ());
- nPacketsSent++; // Count sent this loop
- m_nextTxSequence += sz; // Advance next tx sequence
- // Note the high water mark
- m_highTxMark = std::max (m_nextTxSequence, m_highTxMark);
- }
- NS_LOG_LOGIC ("Sent "<<nPacketsSent<<" packets");
- NS_LOG_LOGIC("RETURN SendPendingData");
- return (nPacketsSent>0);
-}
-
-uint32_t TcpSocket::UnAckDataCount ()
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_nextTxSequence - m_highestRxAck;
-}
-
-uint32_t TcpSocket::BytesInFlight ()
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_highTxMark - m_highestRxAck;
-}
-
-uint32_t TcpSocket::Window ()
-{
- NS_LOG_FUNCTION_NOARGS ();
- NS_LOG_LOGIC ("TcpSocket::Window() "<<this);
- return std::min (m_rxWindowSize, m_cWnd.Get());
-}
-
-uint32_t TcpSocket::AvailableWindow ()
-{
- NS_LOG_FUNCTION_NOARGS ();
- uint32_t unack = UnAckDataCount (); // Number of outstanding bytes
- uint32_t win = Window ();
- if (win < unack)
- {
- return 0; // No space available
- }
- return (win - unack); // Amount of window space available
-}
-
-void TcpSocket::NewRx (Ptr<Packet> p,
- const TcpHeader& tcpHeader,
- const Address& fromAddress)
-{
- NS_LOG_FUNCTION (this << p << "tcpHeader " << fromAddress);
- NS_LOG_LOGIC ("TcpSocket " << this << " NewRx,"
- << " seq " << tcpHeader.GetSequenceNumber()
- << " ack " << tcpHeader.GetAckNumber()
- << " p.size is " << p->GetSize () );
- NS_LOG_DEBUG ("TcpSocket " << this <<
- " NewRx," <<
- " seq " << tcpHeader.GetSequenceNumber() <<
- " ack " << tcpHeader.GetAckNumber() <<
- " p.size is " << p->GetSize());
- States_t origState = m_state;
- uint32_t s = p->GetSize (); // Size of associated data
- if (s == 0)
- {// Nothing to do if no associated data
- return;
- }
- // Log sequence received if enabled
- // NoteTimeSeq(LOG_SEQ_RX, h->sequenceNumber);
- // Three possibilities
- // 1) Received seq is expected, deliver this and any buffered data
- // 2) Received seq is < expected, just re-ack previous
- // 3) Received seq is > expected, just re-ack previous and buffer data
- if (tcpHeader.GetSequenceNumber () == m_nextRxSequence)
- { // If seq is expected seq
- // 1) Update nextRxSeq
- // 2) Deliver to application this packet
- // 3) See if any buffered can be delivered
- // 4) Send the ack
- m_nextRxSequence += s; // Advance next expected sequence
- //bytesReceived += s; // Statistics
- NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence );
- SocketRxAddressTag tag;
- tag.SetAddress (fromAddress);
- p->AddTag (tag);
- m_deliveryQueue.push (p);
- m_rxAvailable += p->GetSize ();
- NotifyDataRecv ();
- if (m_closeNotified)
- {
- NS_LOG_LOGIC ("Tcp " << this << " HuH? Got data after closeNotif");
- }
- NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq by " << s);
- // Look for buffered data
- UnAckData_t::iterator i;
- // Note that the bufferedData list DOES contain the tcp header
- while (!m_bufferedData.empty ())
- { // Check the buffered data for delivery
- NS_LOG_LOGIC("TCP " << this << " bufferedData.size() "
- << m_bufferedData.size ()
- << " time " << Simulator::Now ());
- i = m_bufferedData.begin ();
- Ptr<Packet> p1 = i->second;
- SequenceNumber s1 = 0;
- if (i->first > m_nextRxSequence)
- {
- break; // Not next expected
- }
- // already have the header as a param
- //TCPHeader* h = dynamic_cast<TCPHeader*>(p1->PopPDU());
- // Check non-null here...
- uint8_t flags = tcpHeader.GetFlags (); // Flags (used below)
- if (i->first < m_nextRxSequence)
- { // remove already delivered data
- // Two cases here.
- // 1) seq + length <= nextRxSeq, just discard
- // 2) seq + length > nextRxSeq, can deliver partial
- s1 = p->GetSize ();
- if (i->first + s1 < m_nextRxSequence)
- { // Just remove from list
- //bufferedData.erase(i);
- p1 = 0; // Nothing to deliver
- }
- else
- { // Remove partial data to prepare for delivery
- uint32_t dup = m_nextRxSequence - i->first;
- i->second = p1->CreateFragment (0, p1->GetSize () - dup);
- p1 = i->second;
- }
- }
- else
- { // At this point i->first must equal nextRxSeq
- if (i->first != m_nextRxSequence)
- {
- NS_FATAL_ERROR ("HuH? NexRx failure, first "
- << i->first << " nextRxSeq " << m_nextRxSequence);
- }
- s1 = p1->GetSize ();
- }
- SocketRxAddressTag tag;
- tag.SetAddress (fromAddress);
- p1->AddTag (tag);
- m_deliveryQueue.push (p1);
- m_rxAvailable += p->GetSize ();
- NotifyDataRecv ();
-
- NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq1 by " << s1 );
- m_nextRxSequence += s1; // Note data received
- m_bufferedData.erase (i); // Remove from list
- if (flags & TcpHeader::FIN)
- NS_LOG_LOGIC("TcpSocket " << this
- << " found FIN in buffered");
- }
-
- if (m_pendingClose || (origState > ESTABLISHED))
- { // See if we can close now
- if (m_bufferedData.empty())
- {
- ProcessPacketAction (PEER_CLOSE, p, tcpHeader, fromAddress);
- }
- }
- }
- else if (SequenceNumber (tcpHeader.GetSequenceNumber ()) >= m_nextRxSequence)
- { // Need to buffer this one
- NS_LOG_LOGIC ("Case 2, buffering " << tcpHeader.GetSequenceNumber () );
- UnAckData_t::iterator i =
- m_bufferedData.find (tcpHeader.GetSequenceNumber () );
- if (i != m_bufferedData.end () )
- {
- i->second = 0; // relase reference to already buffered
- }
- // Save for later delivery
- m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;
- }
- else
- { // debug
- NS_LOG_LOGIC("TCP " << this
- << " got seq " << tcpHeader.GetSequenceNumber ()
- << " expected " << m_nextRxSequence
- << " flags " << tcpHeader.GetFlags ());
- }
- // Now send a new ack packet acknowledging all received and delivered data
- if(++m_delAckCount >= m_delAckMaxCount)
- {
- m_delAckEvent.Cancel();
- m_delAckCount = 0;
- SendEmptyPacket (TcpHeader::ACK);
- }
- else
- {
- m_delAckEvent = Simulator::Schedule (m_delAckTimout, &TcpSocket::DelAckTimeout, this);
- }
-}
-
-void TcpSocket::DelAckTimeout ()
-{
- m_delAckCount = 0;
- SendEmptyPacket (TcpHeader::ACK);
-}
-
-void TcpSocket::CommonNewAck (SequenceNumber ack, bool skipTimer)
-{ // CommonNewAck is called only for "New" (non-duplicate) acks
- // and MUST be called by any subclass, from the NewAck function
- // Always cancel any pending re-tx timer on new acknowledgement
- NS_LOG_FUNCTION (this << ack << skipTimer);
- //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl));
- if (!skipTimer)
- {
- 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 "
- << Simulator::Now ().GetSeconds () << " to expire at time "
- << (Simulator::Now () + rto).GetSeconds ());
- m_retxEvent = Simulator::Schedule (rto, &TcpSocket::ReTxTimeout, this);
- }
- NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack
- << " numberAck " << (ack - m_highestRxAck)); // Number bytes ack'ed
- m_highestRxAck = ack; // Note the highest recieved Ack
- if (m_wouldBlock)
- {
- // m_highestRxAck advancing means some data was acked, and the size
- // of free space in the buffer has increased
- NotifySend (GetTxAvailable ());
- m_wouldBlock = false;
- }
- if (ack > m_nextTxSequence)
- {
- m_nextTxSequence = ack; // If advanced
- }
- // See if all pending ack'ed; if so we can delete the data
- if (m_pendingData)
- { // Data exists, see if can be deleted
- if (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck) == 0)
- { // All pending acked, can be deleted
- m_pendingData->Clear ();
- delete m_pendingData;
- m_pendingData = 0;
- // Insure no re-tx timer
- m_retxEvent.Cancel ();
- }
- }
- // Try to send more data
- SendPendingData();
-}
-
-Ptr<TcpSocket> TcpSocket::Copy ()
-{
- return CopyObject<TcpSocket> (this);
-}
-
-void TcpSocket::NewAck (SequenceNumber seq)
-{ // New acknowledgement up to sequence number "seq"
- // Adjust congestion window in response to new ack's received
- NS_LOG_FUNCTION (this << seq);
- NS_LOG_LOGIC ("TcpSocket " << this << " NewAck "
- << " seq " << seq
- << " cWnd " << m_cWnd
- << " ssThresh " << m_ssThresh);
- if (m_cWnd < m_ssThresh)
- { // Slow start mode, add one segSize to cWnd
- m_cWnd += m_segmentSize;
- NS_LOG_LOGIC ("TcpSocket " << this << " NewCWnd SlowStart, cWnd " << m_cWnd
- << " sst " << m_ssThresh);
- }
- else
- { // Congestion avoidance mode, adjust by (ackBytes*segSize) / cWnd
- double adder = ((double) m_segmentSize * m_segmentSize) / m_cWnd.Get();
- if (adder < 1.0)
- {
- adder = 1.0;
- }
- m_cWnd += (uint32_t) adder;
- NS_LOG_LOGIC ("NewCWnd CongAvoid, cWnd " << m_cWnd
- << " sst " << m_ssThresh);
- }
- CommonNewAck (seq, false); // Complete newAck processing
-}
-
-void TcpSocket::DupAck (const TcpHeader& t, uint32_t count)
-{
- NS_LOG_FUNCTION (this << "t " << count);
- NS_LOG_LOGIC ("TcpSocket " << this << " DupAck " << t.GetAckNumber ()
- << ", count " << count
- << ", time " << Simulator::Now ());
- if (count == 3)
- { // Count of three indicates triple duplicate ack
- m_ssThresh = Window () / 2; // Per RFC2581
- m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
- NS_LOG_LOGIC("TcpSocket " << this << "Tahoe TDA, time " << Simulator::Now ()
- << " seq " << t.GetAckNumber ()
- << " in flight " << BytesInFlight ()
- << " new ssthresh " << m_ssThresh);
-
- m_cWnd = m_segmentSize; // Collapse cwnd (re-enter slowstart)
- // For Tahoe, we also reset nextTxSeq
- m_nextTxSequence = m_highestRxAck;
- SendPendingData ();
- }
-}
-
-void TcpSocket::ReTxTimeout ()
-{ // Retransmit timeout
- NS_LOG_FUNCTION (this);
- m_ssThresh = Window () / 2; // Per RFC2581
- m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
- // Set cWnd to segSize on timeout, per rfc2581
- // Collapse congestion window (re-enter slowstart)
- m_cWnd = m_segmentSize;
- m_nextTxSequence = m_highestRxAck; // Start from highest Ack
- m_rtt->IncreaseMultiplier (); // DoubleValue timeout value for next retx timer
- Retransmit (); // Retransmit the packet
-}
-
-void TcpSocket::LastAckTimeout ()
-{
- m_lastAckEvent.Cancel ();
- if (m_state == LAST_ACK)
- {
- Actions_t action = ProcessEvent (TIMEOUT);
- ProcessAction (action);
- }
- if (!m_closeNotified)
- {
- m_closeNotified = true;
- }
-}
-
-void TcpSocket::Retransmit ()
-{
- NS_LOG_FUNCTION (this);
- uint8_t flags = TcpHeader::NONE;
- if (m_state == SYN_SENT)
- {
- if (m_cnCount > 0)
- {
- SendEmptyPacket (TcpHeader::SYN);
- return;
- }
- else
- {
- NotifyConnectionFailed ();
- return;
- }
- }
- if (!m_pendingData)
- {
- if (m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2)
- { // Must have lost FIN, re-send
- SendEmptyPacket (TcpHeader::FIN);
- }
- return;
- }
- Ptr<Packet> p = m_pendingData->CopyFromSeq (m_segmentSize,
- m_firstPendingSequence,
- m_highestRxAck);
- // Calculate remaining data for COE check
- uint32_t remainingData = m_pendingData->SizeFromSeq (
- m_firstPendingSequence,
- m_nextTxSequence + SequenceNumber(p->GetSize ()));
- if (m_closeOnEmpty && remainingData == 0)
- { // Add the FIN flag
- flags = flags | TcpHeader::FIN;
- }
-
- NS_LOG_LOGIC ("TcpSocket " << this << " retxing seq " << m_highestRxAck);
- if (m_retxEvent.IsExpired () )
- {
- Time rto = m_rtt->RetransmitTimeout ();
- NS_LOG_LOGIC ("Schedule retransmission timeout at time "
- << Simulator::Now ().GetSeconds () << " to expire at time "
- << (Simulator::Now () + rto).GetSeconds ());
- m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this);
- }
- m_rtt->SentSeq (m_highestRxAck,p->GetSize ());
- // And send the packet
- TcpHeader tcpHeader;
- tcpHeader.SetSequenceNumber (m_nextTxSequence);
- tcpHeader.SetAckNumber (m_nextRxSequence);
- tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
- tcpHeader.SetDestinationPort (m_remotePort);
- tcpHeader.SetFlags (flags);
- tcpHeader.SetWindowSize (m_advertisedWindowSize);
-
- m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
- m_remoteAddress);
-}
-
-}//namespace ns3
--- a/src/internet-node/tcp-socket.h Tue May 20 10:30:40 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-/* -*- 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>
- */
-#ifndef TCP_SOCKET_H
-#define TCP_SOCKET_H
-
-#include <stdint.h>
-#include <queue>
-#include "ns3/callback.h"
-#include "ns3/traced-value.h"
-#include "ns3/socket.h"
-#include "ns3/ptr.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/event-id.h"
-#include "tcp-typedefs.h"
-#include "pending-data.h"
-#include "sequence-number.h"
-#include "rtt-estimator.h"
-
-
-namespace ns3 {
-
-class Ipv4EndPoint;
-class Node;
-class Packet;
-class TcpL4Protocol;
-class TcpHeader;
-
-class TcpSocket : public Socket
-{
-public:
- static TypeId GetTypeId (void);
- /**
- * Create an unbound tcp socket.
- */
- TcpSocket ();
- TcpSocket (const TcpSocket& sock);
- virtual ~TcpSocket ();
-
- void SetNode (Ptr<Node> node);
- void SetTcp (Ptr<TcpL4Protocol> tcp);
- void SetRtt (Ptr<RttEstimator> rtt);
-
- virtual enum SocketErrno GetErrno (void) const;
- virtual Ptr<Node> GetNode (void) const;
- virtual int Bind (void);
- virtual int Bind (const Address &address);
- virtual int Close (void);
- virtual int ShutdownSend (void);
- virtual int ShutdownRecv (void);
- virtual int Connect(const Address &address);
- virtual int Send (Ptr<Packet> p);
- virtual int Send (const uint8_t* buf, uint32_t size);
- virtual int SendTo(Ptr<Packet> p, const Address &address);
- virtual uint32_t GetTxAvailable (void) const;
- virtual int Listen(uint32_t queueLimit);
-
- virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags);
- virtual uint32_t GetRxAvailable (void) const;
-
-protected:
- virtual void SetSndBuf (uint32_t size);
- virtual uint32_t GetSndBuf (void) const;
- virtual void SetRcvBuf (uint32_t size);
- virtual uint32_t GetRcvBuf (void) const;
-
-private:
- friend class Tcp;
- // invoked by Tcp class
- int FinishBind (void);
- void ForwardUp (Ptr<Packet> p, Ipv4Address ipv4, uint16_t port);
- void Destroy (void);
- int DoSendTo (Ptr<Packet> p, const Address &daddr);
- int DoSendTo (Ptr<Packet> p, Ipv4Address daddr, uint16_t dport);
- void SendEmptyPacket(uint8_t flags);
- //methods for state
- bool ProcessAction (Actions_t a);
- bool ProcessAction (Actions_t a, const TcpHeader& tcpHeader,
- Ipv4Address saddr, Ipv4Address daddr);
- bool ProcessPacketAction (Actions_t a, Ptr<Packet> p,
- const TcpHeader& tcpHeader,
- const Address& fromAddress);
- Actions_t ProcessEvent (Events_t e);
- bool SendPendingData(bool withAck = false);
- void CompleteFork(Ptr<Packet>, const TcpHeader&, const Address& fromAddress);
- void ConnectionSucceeded();
-
- //methods for window management
- virtual uint32_t UnAckDataCount(); // Return count of number of unacked bytes
- virtual uint32_t BytesInFlight(); // Return total bytes in flight
- virtual uint32_t Window(); // Return window size (integer)
- virtual uint32_t AvailableWindow();// Return unfilled portion of window
-
- // Manage data tx/rx
- void NewRx (Ptr<Packet>, const TcpHeader&, const Address&);
- // XXX This should be virtual and overridden
- Ptr<TcpSocket> Copy ();
- void NewAck (SequenceNumber seq);
- // XXX This should be virtual and overridden
- void DupAck (const TcpHeader& t, uint32_t count);
- void ReTxTimeout ();
- void DelAckTimeout ();
- void LastAckTimeout ();
- void Retransmit ();
- void CommonNewAck (SequenceNumber seq, bool skipTimer = false);
-
- bool m_skipRetxResched;
- uint32_t m_dupAckCount;
- EventId m_retxEvent;
- EventId m_lastAckEvent;
-
- EventId m_delAckEvent;
- uint32_t m_delAckCount;
- uint32_t m_delAckMaxCount;
- Time m_delAckTimout;
-
- Ipv4EndPoint *m_endPoint;
- Ptr<Node> m_node;
- Ptr<TcpL4Protocol> m_tcp;
- Ipv4Address m_remoteAddress;
- uint16_t m_remotePort;
- //these two are so that the socket/endpoint cloning works
- Ipv4Address m_localAddress;
- uint16_t m_localPort;
- enum SocketErrno m_errno;
- bool m_shutdownSend;
- bool m_shutdownRecv;
- bool m_connected;
-
- //manage the state infomation
- States_t m_state;
- bool m_closeNotified;
- bool m_closeRequestNotified;
- bool m_closeOnEmpty;
- bool m_pendingClose;
-
-
- //sequence info, sender side
- SequenceNumber m_nextTxSequence;
- SequenceNumber m_highTxMark;
- SequenceNumber m_highestRxAck;
- SequenceNumber m_lastRxAck;
-
- //sequence info, reciever side
- SequenceNumber m_nextRxSequence;
-
- //history data
- //this is the incoming data buffer which sorts out of sequence data
- UnAckData_t m_bufferedData;
- //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
- TracedValue<uint32_t> m_cWnd; //Congestion window
- uint32_t m_ssThresh; //Slow Start Threshold
- uint32_t m_initialCWnd; //Initial cWnd value
-
- // Round trip time estimation
- Ptr<RttEstimator> m_rtt;
- Time m_lastMeasuredRtt;
-
- // Timer-related members
- Time m_cnTimeout;
- uint32_t m_cnCount;
-
- // Temporary queue for delivering data to application
- std::queue<Ptr<Packet> > m_deliveryQueue;
- uint32_t m_rxAvailable;
-
- uint32_t m_sndBufLimit; // buffer limit for the outgoing queue
- uint32_t m_rcvBufLimit; // maximum receive socket buffer size
- bool m_wouldBlock; // set to true whenever socket would block on send()
-};
-
-}//namespace ns3
-
-#endif /* TCP_SOCKET_H */
--- a/src/internet-node/wscript Tue May 20 10:30:40 2008 -0700
+++ b/src/internet-node/wscript Tue May 20 11:52:25 2008 -0700
@@ -23,7 +23,7 @@
'arp-l3-protocol.cc',
'ipv4-loopback-interface.cc',
'udp-socket-impl.cc',
- 'tcp-socket.cc',
+ 'tcp-socket-impl.cc',
'ipv4-end-point-demux.cc',
'ipv4-impl.cc',
'ascii-trace.cc',