src/internet-node/tcp-socket.cc
author Raj Bhattacharjea <raj.b@gatech.edu>
Thu Mar 20 14:04:24 2008 -0400 (2008-03-20)
changeset 2668 4956586bd798
parent 2608 408589d1dfff
child 2669 43ec4c995363
permissions -rw-r--r--
Pass TcpSockets as smart pointers into demux callbacks
fixes TcpSocket memory leaks
raj@2224
     1
/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
raj@2224
     2
/*
raj@2224
     3
 * Copyright (c) 2007 Georgia Tech Research Corporation
raj@2224
     4
 *
raj@2224
     5
 * This program is free software; you can redistribute it and/or modify
raj@2224
     6
 * it under the terms of the GNU General Public License version 2 as
raj@2224
     7
 * published by the Free Software Foundation;
raj@2224
     8
 *
raj@2224
     9
 * This program is distributed in the hope that it will be useful,
raj@2224
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
raj@2224
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
raj@2224
    12
 * GNU General Public License for more details.
raj@2224
    13
 *
raj@2224
    14
 * You should have received a copy of the GNU General Public License
raj@2224
    15
 * along with this program; if not, write to the Free Software
raj@2224
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
raj@2224
    17
 *
raj@2224
    18
 * Author: Raj Bhattacharjea <raj.b@gatech.edu>
raj@2224
    19
 */
raj@2224
    20
raj@2224
    21
raj@2224
    22
#include "ns3/node.h"
raj@2224
    23
#include "ns3/inet-socket-address.h"
raj@2224
    24
#include "ns3/log.h"
raj@2224
    25
#include "ns3/ipv4.h"
raj@2224
    26
#include "tcp-socket.h"
raj@2224
    27
#include "tcp-l4-protocol.h"
raj@2224
    28
#include "ipv4-end-point.h"
raj@2224
    29
#include "ipv4-l4-demux.h"
raj@2224
    30
#include "ns3/simulation-singleton.h"
raj@2224
    31
#include "tcp-typedefs.h"
raj@2224
    32
#include "ns3/simulator.h"
raj@2224
    33
#include "ns3/packet.h"
raj@2224
    34
raj@2224
    35
#include <algorithm>
raj@2224
    36
raj@2224
    37
NS_LOG_COMPONENT_DEFINE ("TcpSocket");
raj@2224
    38
raj@2224
    39
using namespace std;
raj@2224
    40
raj@2224
    41
namespace ns3 {
raj@2224
    42
mathieu@2592
    43
  TcpSocket::TcpSocket ()
raj@2224
    44
  : m_skipRetxResched (false),
raj@2224
    45
    m_dupAckCount (0),
raj@2224
    46
    m_endPoint (0),
mathieu@2592
    47
    m_node (0),
mathieu@2592
    48
    m_tcp (0),
raj@2224
    49
    m_errno (ERROR_NOTERROR),
raj@2224
    50
    m_shutdownSend (false),
raj@2224
    51
    m_shutdownRecv (false),
raj@2224
    52
    m_connected (false),
raj@2224
    53
    m_state (CLOSED),
raj@2224
    54
    m_closeNotified (false),
raj@2224
    55
    m_closeRequestNotified (false),
raj@2224
    56
    m_closeOnEmpty (false),
tomh@2226
    57
    m_pendingClose (false),
raj@2224
    58
    m_nextTxSequence (0),
raj@2224
    59
    m_highTxMark (0),
raj@2224
    60
    m_highestRxAck (0),
raj@2224
    61
    m_lastRxAck (0),
raj@2224
    62
    m_nextRxSequence (0),
raj@2224
    63
    m_pendingData (0),
mathieu@2592
    64
    m_rtt (0),
mathieu@2556
    65
    m_lastMeasuredRtt (Seconds(0.0))
raj@2224
    66
{
raj@2224
    67
  NS_LOG_FUNCTION;
mathieu@2592
    68
  NS_LOG_PARAMS (this);
mathieu@2556
    69
  
raj@2224
    70
}
raj@2224
    71
mathieu@2608
    72
TcpSocket::TcpSocket(const TcpSocket& sock)
mathieu@2608
    73
  : Socket(sock), //copy the base class callbacks
mathieu@2608
    74
    m_skipRetxResched (sock.m_skipRetxResched),
mathieu@2608
    75
    m_dupAckCount (sock.m_dupAckCount),
mathieu@2608
    76
    m_endPoint (0),
mathieu@2608
    77
    m_node (sock.m_node),
mathieu@2608
    78
    m_tcp (sock.m_tcp),
mathieu@2608
    79
    m_remoteAddress (sock.m_remoteAddress),
mathieu@2608
    80
    m_remotePort (sock.m_remotePort),
mathieu@2608
    81
    m_localAddress (sock.m_localAddress),
mathieu@2608
    82
    m_localPort (sock.m_localPort),
mathieu@2608
    83
    m_errno (sock.m_errno),
mathieu@2608
    84
    m_shutdownSend (sock.m_shutdownSend),
mathieu@2608
    85
    m_shutdownRecv (sock.m_shutdownRecv),
mathieu@2608
    86
    m_connected (sock.m_connected),
mathieu@2608
    87
    m_state (sock.m_state),
mathieu@2608
    88
    m_closeNotified (sock.m_closeNotified),
mathieu@2608
    89
    m_closeRequestNotified (sock.m_closeRequestNotified),
mathieu@2608
    90
    m_closeOnEmpty (sock.m_closeOnEmpty),
mathieu@2608
    91
    m_pendingClose (sock.m_pendingClose),
mathieu@2608
    92
    m_nextTxSequence (sock.m_nextTxSequence),
mathieu@2608
    93
    m_highTxMark (sock.m_highTxMark),
mathieu@2608
    94
    m_highestRxAck (sock.m_highestRxAck),
mathieu@2608
    95
    m_lastRxAck (sock.m_lastRxAck),
mathieu@2608
    96
    m_nextRxSequence (sock.m_nextRxSequence),
mathieu@2608
    97
    m_pendingData (0),
mathieu@2608
    98
    m_segmentSize (sock.m_segmentSize),
mathieu@2608
    99
    m_rxWindowSize (sock.m_rxWindowSize),
mathieu@2608
   100
    m_advertisedWindowSize (sock.m_advertisedWindowSize),
mathieu@2608
   101
    m_cWnd (sock.m_cWnd),
mathieu@2608
   102
    m_ssThresh (sock.m_ssThresh),
mathieu@2608
   103
    m_initialCWnd (sock.m_initialCWnd),
mathieu@2608
   104
    m_rtt (0),
mathieu@2608
   105
    m_lastMeasuredRtt (Seconds(0.0)),
mathieu@2608
   106
    m_cnTimeout (sock.m_cnTimeout),
mathieu@2608
   107
    m_cnCount (sock.m_cnCount)
mathieu@2608
   108
{
mathieu@2608
   109
  NS_LOG_FUNCTION;
mathieu@2608
   110
  NS_LOG_LOGIC("Invoked the copy constructor");
mathieu@2608
   111
  //copy the pending data if necessary
mathieu@2608
   112
  if(sock.m_pendingData)
mathieu@2608
   113
    {
mathieu@2608
   114
      m_pendingData = sock.m_pendingData->Copy();
mathieu@2608
   115
    }
mathieu@2608
   116
  //copy the rtt if necessary
mathieu@2608
   117
  if (sock.m_rtt)
mathieu@2608
   118
    {
mathieu@2608
   119
      m_rtt = sock.m_rtt->Copy();
mathieu@2608
   120
    }
mathieu@2608
   121
  //can't "copy" the endpoint just yes, must do this when we know the peer info
mathieu@2608
   122
  //too; this is in SYN_ACK_TX
mathieu@2608
   123
}
mathieu@2608
   124
raj@2224
   125
TcpSocket::~TcpSocket ()
raj@2224
   126
{
raj@2224
   127
  NS_LOG_FUNCTION;
raj@2668
   128
  NS_LOG_PARAMS(this);
raj@2224
   129
  m_node = 0;
raj@2224
   130
  if (m_endPoint != 0)
raj@2224
   131
    {
raj@2224
   132
      NS_ASSERT (m_tcp != 0);
raj@2224
   133
      /**
raj@2224
   134
       * Note that this piece of code is a bit tricky:
raj@2224
   135
       * when DeAllocate is called, it will call into
raj@2224
   136
       * Ipv4EndPointDemux::Deallocate which triggers
raj@2224
   137
       * a delete of the associated endPoint which triggers
raj@2224
   138
       * in turn a call to the method ::Destroy below
raj@2224
   139
       * will will zero the m_endPoint field.
raj@2224
   140
       */
raj@2224
   141
      NS_ASSERT (m_endPoint != 0);
raj@2224
   142
      m_tcp->DeAllocate (m_endPoint);
raj@2224
   143
      NS_ASSERT (m_endPoint == 0);
raj@2224
   144
    }
raj@2224
   145
  m_tcp = 0;
raj@2224
   146
  delete m_pendingData; //prevents leak
raj@2353
   147
  m_pendingData = 0;
raj@2224
   148
}
raj@2224
   149
mathieu@2592
   150
void
mathieu@2592
   151
TcpSocket::SetNode (Ptr<Node> node)
mathieu@2592
   152
{
mathieu@2592
   153
  m_node = node;
mathieu@2592
   154
  Ptr<Tcp> t = node->GetObject<Tcp> ();
mathieu@2592
   155
  m_segmentSize = t->GetDefaultSegSize ();
mathieu@2592
   156
  m_rxWindowSize = t->GetDefaultAdvWin ();
mathieu@2592
   157
  m_advertisedWindowSize = t->GetDefaultAdvWin ();
mathieu@2592
   158
  m_cWnd = t->GetDefaultInitialCwnd () * m_segmentSize;
mathieu@2592
   159
  m_ssThresh = t->GetDefaultSsThresh ();
mathieu@2592
   160
  m_initialCWnd = t->GetDefaultInitialCwnd ();
mathieu@2592
   161
  m_cnTimeout = Seconds (t->GetDefaultConnTimeout ());
mathieu@2592
   162
  m_cnCount = t->GetDefaultConnCount ();
mathieu@2592
   163
}
mathieu@2592
   164
mathieu@2592
   165
void 
mathieu@2592
   166
TcpSocket::SetTcp (Ptr<TcpL4Protocol> tcp)
mathieu@2592
   167
{
mathieu@2592
   168
  m_tcp = tcp;
mathieu@2592
   169
}
mathieu@2592
   170
void 
mathieu@2592
   171
TcpSocket::SetRtt (Ptr<RttEstimator> rtt)
mathieu@2592
   172
{
mathieu@2592
   173
  m_rtt = rtt;
mathieu@2592
   174
}
mathieu@2592
   175
mathieu@2592
   176
raj@2224
   177
enum Socket::SocketErrno
raj@2224
   178
TcpSocket::GetErrno (void) const
raj@2224
   179
{
raj@2224
   180
  NS_LOG_FUNCTION;
raj@2224
   181
  return m_errno;
raj@2224
   182
}
raj@2224
   183
raj@2224
   184
Ptr<Node>
raj@2224
   185
TcpSocket::GetNode (void) const
raj@2224
   186
{
raj@2224
   187
  NS_LOG_FUNCTION;
raj@2224
   188
  return m_node;
raj@2224
   189
}
raj@2224
   190
raj@2224
   191
void 
raj@2224
   192
TcpSocket::Destroy (void)
raj@2224
   193
{
raj@2224
   194
  NS_LOG_FUNCTION;
raj@2224
   195
  m_node = 0;
raj@2224
   196
  m_endPoint = 0;
raj@2224
   197
  m_tcp = 0;
raj@2353
   198
  m_retxEvent.Cancel ();
raj@2224
   199
}
raj@2224
   200
int
raj@2224
   201
TcpSocket::FinishBind (void)
raj@2224
   202
{
raj@2224
   203
  NS_LOG_FUNCTION;
raj@2224
   204
  if (m_endPoint == 0)
raj@2224
   205
    {
raj@2224
   206
      return -1;
raj@2224
   207
    }
raj@2668
   208
  m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr<TcpSocket>(this)));
raj@2668
   209
  m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr<TcpSocket>(this)));
mathieu@2608
   210
  m_localAddress = m_endPoint->GetLocalAddress ();
mathieu@2608
   211
  m_localPort = m_endPoint->GetLocalPort ();
raj@2224
   212
  return 0;
raj@2224
   213
}
raj@2224
   214
raj@2224
   215
int
raj@2224
   216
TcpSocket::Bind (void)
raj@2224
   217
{
raj@2224
   218
  NS_LOG_FUNCTION;
raj@2224
   219
  m_endPoint = m_tcp->Allocate ();
raj@2224
   220
  return FinishBind ();
raj@2224
   221
}
raj@2224
   222
int 
raj@2224
   223
TcpSocket::Bind (const Address &address)
raj@2224
   224
{
raj@2224
   225
  NS_LOG_FUNCTION;
raj@2224
   226
  NS_LOG_PARAMS (this<<address);
raj@2224
   227
  if (!InetSocketAddress::IsMatchingType (address))
raj@2224
   228
    {
raj@2224
   229
      return ERROR_INVAL;
raj@2224
   230
    }
raj@2224
   231
  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
raj@2224
   232
  Ipv4Address ipv4 = transport.GetIpv4 ();
raj@2224
   233
  uint16_t port = transport.GetPort ();
raj@2224
   234
  if (ipv4 == Ipv4Address::GetAny () && port == 0)
raj@2224
   235
    {
raj@2224
   236
      m_endPoint = m_tcp->Allocate ();
raj@2224
   237
      NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
raj@2224
   238
    }
raj@2224
   239
  else if (ipv4 == Ipv4Address::GetAny () && port != 0)
raj@2224
   240
    {
raj@2224
   241
      m_endPoint = m_tcp->Allocate (port);
raj@2224
   242
      NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
raj@2224
   243
    }
raj@2224
   244
  else if (ipv4 != Ipv4Address::GetAny () && port == 0)
raj@2224
   245
    {
mathieu@2608
   246
      m_endPoint = m_tcp->Allocate (ipv4);
raj@2224
   247
      NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
raj@2224
   248
    }
raj@2224
   249
  else if (ipv4 != Ipv4Address::GetAny () && port != 0)
raj@2224
   250
    {
mathieu@2608
   251
      m_endPoint = m_tcp->Allocate (ipv4, port);
raj@2224
   252
      NS_LOG_LOGIC ("TcpSocket "<<this<<" got an endpoint: "<<m_endPoint);
raj@2224
   253
    }
raj@2224
   254
raj@2224
   255
  return FinishBind ();
raj@2224
   256
}
raj@2224
   257
raj@2224
   258
int 
raj@2224
   259
TcpSocket::ShutdownSend (void)
raj@2224
   260
{
raj@2224
   261
  NS_LOG_FUNCTION;
raj@2224
   262
  m_shutdownSend = true;
raj@2224
   263
  return 0;
raj@2224
   264
}
raj@2224
   265
int 
raj@2224
   266
TcpSocket::ShutdownRecv (void)
raj@2224
   267
{
raj@2224
   268
  NS_LOG_FUNCTION;
raj@2224
   269
  m_shutdownRecv = false;
raj@2224
   270
  return 0;
raj@2224
   271
}
raj@2224
   272
raj@2224
   273
int
raj@2224
   274
TcpSocket::Close (void)
raj@2224
   275
{
raj@2224
   276
  NS_LOG_FUNCTION;
raj@2224
   277
  if (m_state == CLOSED) 
raj@2224
   278
    {
raj@2224
   279
      return -1;
raj@2224
   280
    }
mathieu@2608
   281
  if (m_pendingData && m_pendingData->Size() != 0)
mathieu@2608
   282
    { // App close with pending data must wait until all data transmitted
mathieu@2608
   283
      m_closeOnEmpty = true;
mathieu@2608
   284
      NS_LOG_LOGIC("Socket " << this << 
mathieu@2608
   285
                   " deferring close, state " << m_state);
mathieu@2608
   286
      return 0;
mathieu@2608
   287
    }
mathieu@2608
   288
raj@2224
   289
  Actions_t action  = ProcessEvent (APP_CLOSE);
raj@2224
   290
  ProcessAction (action);
raj@2224
   291
  ShutdownSend ();
raj@2224
   292
  return 0;
raj@2224
   293
}
raj@2224
   294
raj@2224
   295
int
raj@2224
   296
TcpSocket::Connect (const Address & address)
raj@2224
   297
{
raj@2224
   298
  NS_LOG_FUNCTION;
raj@2224
   299
  NS_LOG_PARAMS (this << address);
raj@2224
   300
  if (m_endPoint == 0)
raj@2224
   301
    {
raj@2224
   302
      if (Bind () == -1)
raj@2224
   303
        {
raj@2224
   304
          NS_ASSERT (m_endPoint == 0);
raj@2224
   305
          return -1;
raj@2224
   306
        }
raj@2224
   307
      NS_ASSERT (m_endPoint != 0);
raj@2224
   308
    }
raj@2224
   309
  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
mathieu@2608
   310
  m_remoteAddress = transport.GetIpv4 ();
mathieu@2608
   311
  m_remotePort = transport.GetPort ();
raj@2224
   312
  
raj@2224
   313
  uint32_t localIfIndex;
mathieu@2257
   314
  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
raj@2224
   315
mathieu@2608
   316
  if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
raj@2224
   317
    {
raj@2224
   318
      m_endPoint->SetLocalAddress (ipv4->GetAddress (localIfIndex));
raj@2224
   319
    }
raj@2224
   320
  else
raj@2224
   321
    {
raj@2224
   322
      m_errno = ERROR_NOROUTETOHOST;
raj@2224
   323
      return -1;
raj@2224
   324
    }
raj@2224
   325
raj@2224
   326
  Actions_t action = ProcessEvent (APP_CONNECT);
raj@2224
   327
  bool success = ProcessAction (action);
raj@2224
   328
  if (success) 
raj@2224
   329
    {
raj@2224
   330
      return 0;
raj@2224
   331
    }
raj@2224
   332
  return -1;
raj@2224
   333
}
raj@2224
   334
int 
raj@2224
   335
TcpSocket::Send (const Ptr<Packet> p) //p here is just data, no headers
mathieu@2608
   336
{ // TCP Does not deal with packets from app, just data
mathieu@2608
   337
  return Send(p->PeekData(), p->GetSize());
raj@2224
   338
}
raj@2224
   339
raj@2224
   340
int TcpSocket::Send (const uint8_t* buf, uint32_t size)
raj@2224
   341
{
raj@2224
   342
  NS_LOG_FUNCTION;
raj@2224
   343
  NS_LOG_PARAMS (this << buf << size);
raj@2224
   344
  if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT)
raj@2224
   345
    { // Ok to buffer some data to send
raj@2224
   346
      if (!m_pendingData)
raj@2224
   347
      {
raj@2224
   348
        m_pendingData = new PendingData ();   // Create if non-existent
raj@2224
   349
        m_firstPendingSequence = m_nextTxSequence; // Note seq of first
raj@2224
   350
      }
raj@2224
   351
      //PendingData::Add always copies the data buffer, never modifies
raj@2224
   352
      m_pendingData->Add (size,buf);
mathieu@2608
   353
      NS_LOG_DEBUG("TcpSock::Send, pdsize " << m_pendingData->Size() << 
mathieu@2608
   354
                   " state " << m_state);
raj@2224
   355
      Actions_t action = ProcessEvent (APP_SEND);
mathieu@2608
   356
      NS_LOG_DEBUG(" action " << action);
raj@2224
   357
      if (!ProcessAction (action)) 
raj@2224
   358
        {
raj@2224
   359
          return -1; // Failed, return zero
raj@2224
   360
        }
raj@2224
   361
      return size;
raj@2224
   362
    }
raj@2224
   363
  else
raj@2224
   364
  {
raj@2224
   365
    m_errno = ERROR_NOTCONN;
raj@2224
   366
    return -1;
raj@2224
   367
  }
raj@2224
   368
}
raj@2224
   369
raj@2224
   370
int TcpSocket::DoSendTo (Ptr<Packet> p, const Address &address)
raj@2224
   371
{
raj@2224
   372
  NS_LOG_FUNCTION;
raj@2224
   373
  NS_LOG_PARAMS (this << p << address);
raj@2224
   374
  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
raj@2224
   375
  Ipv4Address ipv4 = transport.GetIpv4 ();
raj@2224
   376
  uint16_t port = transport.GetPort ();
raj@2224
   377
  return DoSendTo (p, ipv4, port);
raj@2224
   378
}
raj@2224
   379
raj@2224
   380
int TcpSocket::DoSendTo (Ptr<Packet> p, Ipv4Address ipv4, uint16_t port)
raj@2224
   381
{
raj@2224
   382
  NS_LOG_FUNCTION;
raj@2224
   383
  NS_LOG_PARAMS (this << p << ipv4 << port);
raj@2224
   384
  if (m_endPoint == 0)
raj@2224
   385
    {
raj@2224
   386
      if (Bind () == -1)
raj@2224
   387
	{
raj@2224
   388
          NS_ASSERT (m_endPoint == 0);
raj@2224
   389
	  return -1;
raj@2224
   390
	}
raj@2224
   391
      NS_ASSERT (m_endPoint != 0);
raj@2224
   392
    }
raj@2224
   393
  if (m_shutdownSend)
raj@2224
   394
    {
raj@2224
   395
      m_errno = ERROR_SHUTDOWN;
raj@2224
   396
      return -1;
raj@2224
   397
    }
raj@2224
   398
  m_tcp->Send (p, m_endPoint->GetLocalAddress (), ipv4,
raj@2224
   399
                  m_endPoint->GetLocalPort (), port);
raj@2224
   400
  NotifyDataSent (p->GetSize ());
raj@2224
   401
  return 0;
raj@2224
   402
}
raj@2224
   403
raj@2224
   404
int 
raj@2224
   405
TcpSocket::SendTo (const Address &address, Ptr<Packet> p)
raj@2224
   406
{
raj@2224
   407
  NS_LOG_FUNCTION;
raj@2224
   408
  NS_LOG_PARAMS (this << address << p);
raj@2224
   409
  if (!m_connected)
raj@2224
   410
    {
raj@2224
   411
      m_errno = ERROR_NOTCONN;
raj@2224
   412
      return -1;
raj@2224
   413
    }
raj@2224
   414
  else
raj@2224
   415
    {
raj@2224
   416
      return Send (p); //drop the address according to BSD manpages
raj@2224
   417
    }
raj@2224
   418
}
raj@2224
   419
raj@2224
   420
int
raj@2224
   421
TcpSocket::Listen (uint32_t q)
raj@2224
   422
{
raj@2224
   423
  NS_LOG_FUNCTION;
raj@2224
   424
  NS_LOG_PARAMS (this << q);
raj@2224
   425
  Actions_t action = ProcessEvent (APP_LISTEN);
raj@2224
   426
  ProcessAction (action);
raj@2224
   427
  return 0;
raj@2224
   428
}
raj@2224
   429
raj@2224
   430
void
raj@2224
   431
TcpSocket::ForwardUp (Ptr<Packet> packet, Ipv4Address ipv4, uint16_t port)
raj@2224
   432
{
mathieu@2608
   433
  NS_LOG_DEBUG("Socket " << this << " got forward up" <<
mathieu@2608
   434
               " dport " << m_endPoint->GetLocalPort() <<
mathieu@2608
   435
               " daddr " << m_endPoint->GetLocalAddress() <<
mathieu@2608
   436
               " sport " << m_endPoint->GetPeerPort() <<
mathieu@2608
   437
               " saddr " << m_endPoint->GetPeerAddress());
mathieu@2608
   438
raj@2224
   439
  NS_LOG_FUNCTION;
raj@2224
   440
  NS_LOG_PARAMS (this << packet << ipv4 << port);
raj@2224
   441
  if (m_shutdownRecv)
raj@2224
   442
    {
raj@2224
   443
      return;
raj@2224
   444
    }
raj@2224
   445
  TcpHeader tcpHeader;
raj@2224
   446
  packet->RemoveHeader (tcpHeader);
raj@2224
   447
raj@2224
   448
  if (tcpHeader.GetFlags () & TcpHeader::ACK)
raj@2224
   449
    {
raj@2224
   450
      Time m = m_rtt->AckSeq (tcpHeader.GetAckNumber () );
raj@2224
   451
      if (m != Seconds (0.0))
raj@2224
   452
        {
raj@2224
   453
          m_lastMeasuredRtt = m;
raj@2224
   454
        }
raj@2224
   455
    }
raj@2224
   456
raj@2224
   457
  Events_t event = SimulationSingleton<TcpStateMachine>::Get ()->FlagsEvent (tcpHeader.GetFlags () );
raj@2224
   458
  Actions_t action = ProcessEvent (event); //updates the state
raj@2224
   459
  Address address = InetSocketAddress (ipv4, port);
mathieu@2608
   460
  NS_LOG_DEBUG("Socket " << this << 
mathieu@2608
   461
               " processing pkt action, " << action <<
mathieu@2608
   462
               " current state " << m_state);
raj@2224
   463
  ProcessPacketAction (action, packet, tcpHeader, address);
raj@2224
   464
}
raj@2224
   465
raj@2224
   466
Actions_t TcpSocket::ProcessEvent (Events_t e)
raj@2224
   467
{
raj@2224
   468
  NS_LOG_FUNCTION;
raj@2224
   469
  NS_LOG_PARAMS (this << e);
raj@2224
   470
  States_t saveState = m_state;
raj@2224
   471
  NS_LOG_LOGIC ("TcpSocket " << this << " processing event " << e);
raj@2224
   472
  // simulation singleton is a way to get a single global static instance of a
raj@2224
   473
  // class intended to be a singleton; see simulation-singleton.h
raj@2224
   474
  SA stateAction = SimulationSingleton<TcpStateMachine>::Get ()->Lookup (m_state,e);
raj@2224
   475
  // debug
raj@2224
   476
  if (stateAction.action == RST_TX)
raj@2224
   477
    {
raj@2224
   478
      NS_LOG_LOGIC ("TcpSocket " << this << " sending RST from state "
raj@2224
   479
              << saveState << " event " << e);
raj@2224
   480
    }
raj@2224
   481
  bool needCloseNotify = (stateAction.state == CLOSED && m_state != CLOSED 
raj@2224
   482
    && e != TIMEOUT);
raj@2224
   483
  m_state = stateAction.state;
raj@2224
   484
  NS_LOG_LOGIC ("TcpSocket " << this << " moved from state " << saveState 
raj@2224
   485
    << " to state " <<m_state);
raj@2224
   486
  NS_LOG_LOGIC ("TcpSocket " << this << " pendingData " << m_pendingData);
mathieu@2608
   487
mathieu@2608
   488
  //extra event logic is here for RX events
mathieu@2608
   489
  //e = SYN_ACK_RX
raj@2224
   490
  if (saveState == SYN_SENT && m_state == ESTABLISHED)
raj@2224
   491
    // this means the application side has completed its portion of 
raj@2224
   492
    // the handshaking
raj@2224
   493
    {
mathieu@2608
   494
      Simulator::ScheduleNow(&TcpSocket::ConnectionSucceeded, this);
mathieu@2608
   495
      //NotifyConnectionSucceeded ();
raj@2224
   496
      m_connected = true;
mathieu@2608
   497
      m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
raj@2224
   498
      NS_LOG_LOGIC ("TcpSocket " << this << " Connected!");
raj@2224
   499
    }
mathieu@2608
   500
raj@2224
   501
  if (needCloseNotify && !m_closeNotified)
raj@2224
   502
    {
raj@2224
   503
      NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from " 
raj@2224
   504
               << m_state << " event " << e << " closeNot " << m_closeNotified
raj@2224
   505
               << " action " << stateAction.action);
raj@2224
   506
      NotifyCloseCompleted ();
raj@2224
   507
      m_closeNotified = true;
raj@2224
   508
      NS_LOG_LOGIC ("TcpSocket " << this << " calling Closed from PE"
raj@2224
   509
              << " origState " << saveState
raj@2224
   510
              << " event " << e);
raj@2224
   511
      NS_LOG_LOGIC ("TcpSocket " << this << " transition to CLOSED from "
raj@2224
   512
          << m_state << " event " << e
raj@2224
   513
          << " set CloseNotif ");
raj@2224
   514
    }
raj@2224
   515
  return stateAction.action;
raj@2224
   516
}
raj@2224
   517
raj@2224
   518
void TcpSocket::SendEmptyPacket (uint8_t flags)
raj@2224
   519
{
raj@2224
   520
  NS_LOG_FUNCTION;
raj@2224
   521
  NS_LOG_PARAMS (this << flags);
raj@2224
   522
  Ptr<Packet> p = Create<Packet> ();
raj@2224
   523
  TcpHeader header;
raj@2224
   524
raj@2224
   525
  header.SetFlags (flags);
raj@2224
   526
  header.SetSequenceNumber (m_nextTxSequence);
raj@2224
   527
  header.SetAckNumber (m_nextRxSequence);
raj@2224
   528
  header.SetSourcePort (m_endPoint->GetLocalPort ());
mathieu@2608
   529
  header.SetDestinationPort (m_remotePort);
raj@2224
   530
  header.SetWindowSize (m_advertisedWindowSize);
raj@2224
   531
  m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), 
mathieu@2608
   532
    m_remoteAddress);
raj@2224
   533
  Time rto = m_rtt->RetransmitTimeout ();
raj@2224
   534
  if (flags & TcpHeader::SYN)
raj@2224
   535
    {
raj@2224
   536
      rto = m_cnTimeout;
m@2352
   537
      m_cnTimeout = m_cnTimeout + m_cnTimeout;
raj@2224
   538
      m_cnCount--;
raj@2224
   539
    }
raj@2224
   540
  if (m_retxEvent.IsExpired () ) //no outstanding timer
raj@2224
   541
  {
raj@2224
   542
    NS_LOG_LOGIC ("Schedule retransmission timeout at time " 
raj@2224
   543
          << Simulator::Now ().GetSeconds () << " to expire at time " 
raj@2224
   544
          << (Simulator::Now () + rto).GetSeconds ());
raj@2224
   545
    m_retxEvent = Simulator::Schedule (rto, &TcpSocket::ReTxTimeout, this);
raj@2224
   546
  }
raj@2224
   547
}
raj@2224
   548
raj@2224
   549
bool TcpSocket::ProcessAction (Actions_t a)
raj@2224
   550
{ // These actions do not require a packet or any TCP Headers
raj@2224
   551
  NS_LOG_FUNCTION;
raj@2224
   552
  NS_LOG_PARAMS (this << a);
raj@2224
   553
  switch (a)
raj@2224
   554
  {
raj@2224
   555
    case NO_ACT:
raj@2224
   556
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action: NO_ACT");
raj@2224
   557
      break;
raj@2224
   558
    case ACK_TX:
raj@2224
   559
      SendEmptyPacket (TcpHeader::ACK);
raj@2224
   560
      break;
raj@2224
   561
    case ACK_TX_1:
raj@2224
   562
      NS_ASSERT (false); // This should be processed in ProcessPacketAction
raj@2224
   563
      break;
raj@2224
   564
    case RST_TX:
raj@2224
   565
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action RST_TX");
raj@2224
   566
      SendEmptyPacket (TcpHeader::RST);
raj@2224
   567
      break;
raj@2224
   568
    case SYN_TX:
raj@2224
   569
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_TX");
raj@2224
   570
      // TCP SYN Flag consumes one byte
raj@2316
   571
      // is the above correct? we're SENDING a syn, not acking back -- Raj
raj@2316
   572
      // commented out for now
raj@2316
   573
      // m_nextTxSequence+= 1;
raj@2224
   574
      SendEmptyPacket (TcpHeader::SYN);
raj@2224
   575
      break;
raj@2224
   576
    case SYN_ACK_TX:
raj@2224
   577
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX");
mathieu@2608
   578
      // TCP SYN Flag consumes one byte
mathieu@2608
   579
      ++m_nextRxSequence;
raj@2224
   580
      SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
raj@2224
   581
      break;
raj@2224
   582
    case FIN_TX:
raj@2224
   583
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_TX");
raj@2224
   584
      SendEmptyPacket (TcpHeader::FIN);
raj@2224
   585
      break;
raj@2224
   586
    case FIN_ACK_TX:
raj@2224
   587
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action FIN_ACK_TX");
raj@2224
   588
      SendEmptyPacket (TcpHeader::FIN | TcpHeader::ACK);
raj@2224
   589
      break;
raj@2224
   590
    case NEW_ACK:
raj@2224
   591
      NS_ASSERT (false); // This should be processed in ProcessPacketAction
raj@2224
   592
      break;
raj@2224
   593
    case NEW_SEQ_RX:
raj@2224
   594
      NS_ASSERT (false); // This should be processed in ProcessPacketAction
raj@2224
   595
      break;
raj@2224
   596
    case RETX:
raj@2224
   597
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action RETX");
raj@2224
   598
      break;
raj@2224
   599
    case TX_DATA:
raj@2224
   600
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action TX_DATA");
raj@2224
   601
      SendPendingData ();
raj@2224
   602
      break;
raj@2224
   603
    case PEER_CLOSE:
raj@2224
   604
      NS_ASSERT (false); // This should be processed in ProcessPacketAction
raj@2224
   605
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action PEER_CLOSE");
raj@2224
   606
      break;
raj@2224
   607
    case APP_CLOSED:
raj@2224
   608
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_CLOSED");
raj@2224
   609
      break;
raj@2224
   610
    case CANCEL_TM:
raj@2224
   611
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action CANCEL_TM");
raj@2224
   612
      break;
raj@2224
   613
    case APP_NOTIFY:
raj@2224
   614
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action APP_NOTIFY");
raj@2224
   615
      break;
raj@2224
   616
    case SERV_NOTIFY:
raj@2316
   617
      NS_ASSERT (false); // This should be processed in ProcessPacketAction
raj@2224
   618
      break;
raj@2224
   619
    case LAST_ACTION:
raj@2224
   620
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action LAST_ACTION");
raj@2224
   621
      break;
raj@2224
   622
  }
raj@2224
   623
  return true;
raj@2224
   624
}
raj@2224
   625
raj@2224
   626
bool TcpSocket::ProcessPacketAction (Actions_t a, Ptr<Packet> p,
raj@2224
   627
                                     const TcpHeader& tcpHeader,
raj@2224
   628
                                     const Address& fromAddress)
raj@2224
   629
{
raj@2224
   630
  NS_LOG_FUNCTION;
mathieu@2608
   631
  NS_LOG_PARAMS (this << a << p  << fromAddress);
raj@2224
   632
  uint32_t localIfIndex;
mathieu@2257
   633
  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
raj@2224
   634
  switch (a)
raj@2224
   635
  {
raj@2224
   636
    case SYN_ACK_TX:
raj@2224
   637
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action SYN_ACK_TX");
mathieu@2608
   638
//      m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
mathieu@2608
   639
//      m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
mathieu@2608
   640
//       if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
mathieu@2608
   641
//         {
mathieu@2608
   642
//           m_localAddress = ipv4->GetAddress (localIfIndex);
mathieu@2608
   643
//         }
mathieu@2608
   644
      if (m_state == LISTEN) //this means we should fork a new TcpSocket
raj@2224
   645
        {
mathieu@2608
   646
          NS_LOG_DEBUG("In SYN_ACK_TX, m_state is LISTEN, this " << this);
mathieu@2608
   647
          //notify the server that we got a SYN
mathieu@2608
   648
          // If server refuses connection do nothing
mathieu@2608
   649
          if (!NotifyConnectionRequest(fromAddress)) return true;
mathieu@2608
   650
          // Clone the socket
mathieu@2608
   651
          Ptr<TcpSocket> newSock = Copy ();
mathieu@2608
   652
          NS_LOG_LOGIC ("Cloned a TcpSocket " << newSock);
mathieu@2608
   653
          //this listening socket should do nothing more
mathieu@2608
   654
          Simulator::ScheduleNow (&TcpSocket::CompleteFork, newSock,
mathieu@2608
   655
                                  p, tcpHeader,fromAddress);
mathieu@2608
   656
          return true;
raj@2224
   657
        }
mathieu@2608
   658
        // This is the cloned endpoint
mathieu@2608
   659
        m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
mathieu@2608
   660
        if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex))
mathieu@2608
   661
          {
mathieu@2608
   662
            m_localAddress = ipv4->GetAddress (localIfIndex);
mathieu@2608
   663
            m_endPoint->SetLocalAddress (m_localAddress);
mathieu@2608
   664
            // Leave local addr in the portmap to any, as the path from
mathieu@2608
   665
            // remote can change and packets can arrive on different interfaces
mathieu@2608
   666
            //m_endPoint->SetLocalAddress (Ipv4Address::GetAny());
mathieu@2608
   667
          }
mathieu@2608
   668
        // TCP SYN consumes one byte
mathieu@2608
   669
        m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
mathieu@2608
   670
        SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK);
raj@2224
   671
      break;
raj@2224
   672
    case ACK_TX_1:
raj@2224
   673
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action ACK_TX_1");
raj@2224
   674
      // TCP SYN consumes one byte
raj@2316
   675
      m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1);
mathieu@2608
   676
      NS_LOG_DEBUG ("TcpSocket " << this << " ACK_TX_1" <<
mathieu@2608
   677
                    " nextRxSeq " << m_nextRxSequence);
raj@2224
   678
      SendEmptyPacket (TcpHeader::ACK);
raj@2224
   679
      m_rxWindowSize = tcpHeader.GetWindowSize ();
raj@2316
   680
      m_nextTxSequence = tcpHeader.GetAckNumber ();
raj@2224
   681
      if (tcpHeader.GetAckNumber () > m_highestRxAck)
raj@2224
   682
      {
raj@2224
   683
        m_highestRxAck = tcpHeader.GetAckNumber ();
raj@2224
   684
      }
raj@2224
   685
      SendPendingData ();
raj@2224
   686
      break;
raj@2224
   687
    case NEW_ACK:
raj@2224
   688
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_ACK_TX");
raj@2224
   689
      if (tcpHeader.GetAckNumber () < m_highestRxAck) //old ack, do nothing
raj@2224
   690
      {
raj@2224
   691
        break;
raj@2224
   692
      }
raj@2224
   693
      if (tcpHeader.GetAckNumber () == m_highestRxAck && 
raj@2224
   694
         tcpHeader.GetAckNumber ()  < m_nextTxSequence)
raj@2224
   695
      {
raj@2224
   696
        DupAck (tcpHeader, ++m_dupAckCount);
raj@2224
   697
        break;
raj@2224
   698
      }
raj@2224
   699
      if (tcpHeader.GetAckNumber () > m_highestRxAck)  
raj@2224
   700
        {
raj@2224
   701
          m_dupAckCount = 0;
raj@2224
   702
        }
raj@2224
   703
      NewAck (tcpHeader.GetAckNumber ());
raj@2224
   704
      break;
raj@2224
   705
    case NEW_SEQ_RX:
mathieu@2608
   706
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action NEW_SEQ_RX");
raj@2224
   707
      NewRx (p, tcpHeader, fromAddress); // Process new data received
raj@2224
   708
      break;
raj@2224
   709
    case PEER_CLOSE:
raj@2224
   710
    {
raj@2224
   711
      // First we have to be sure the FIN packet was not received
raj@2224
   712
      // out of sequence.  If so, note pending close and process
raj@2224
   713
      // new sequence rx
raj@2224
   714
      if (tcpHeader.GetSequenceNumber () != m_nextRxSequence)
raj@2224
   715
        { // process close later
raj@2224
   716
          m_pendingClose = true;
raj@2224
   717
          NS_LOG_LOGIC ("TcpSocket " << this << " setting pendingClose" 
raj@2224
   718
            << " rxseq " << tcpHeader.GetSequenceNumber () 
raj@2224
   719
            << " nextRxSeq " << m_nextRxSequence);
raj@2224
   720
          NewRx (p, tcpHeader, fromAddress);
raj@2224
   721
          return true;
raj@2224
   722
        }
raj@2224
   723
      // Now we need to see if any data came with the FIN
raj@2224
   724
      // if so, call NewRx
raj@2224
   725
      if (p->GetSize () != 0)
raj@2224
   726
        {
raj@2224
   727
          NewRx (p, tcpHeader, fromAddress);
raj@2224
   728
        }
raj@2224
   729
      States_t saveState = m_state; // Used to see if app responds
raj@2224
   730
      NS_LOG_LOGIC ("TcpSocket " << this 
raj@2224
   731
          << " peer close, state " << m_state);
raj@2224
   732
      if (!m_closeRequestNotified)
raj@2224
   733
        {
raj@2224
   734
          NS_LOG_LOGIC ("TCP " << this 
raj@2224
   735
              << " calling AppCloseRequest");
mathieu@2608
   736
          NotifyHalfClose ();
raj@2224
   737
          m_closeRequestNotified = true;
raj@2224
   738
        }
raj@2224
   739
      NS_LOG_LOGIC ("TcpSocket " << this 
raj@2224
   740
          << " peer close, state after " << m_state);
raj@2224
   741
      if (m_state == saveState)
raj@2224
   742
        { // Need to ack, the application will close later
raj@2224
   743
          SendEmptyPacket (TcpHeader::ACK);
raj@2224
   744
              // Also need to re-tx the ack if we
raj@2224
   745
        }
raj@2224
   746
      if (m_state == LAST_ACK)
raj@2224
   747
        {
raj@2224
   748
          NS_LOG_LOGIC ("TcpSocket " << this << " scheduling LATO1");
raj@2224
   749
          m_lastAckEvent = Simulator::Schedule (m_rtt->RetransmitTimeout (),
raj@2224
   750
                                                &TcpSocket::LastAckTimeout,this);
raj@2224
   751
        }
raj@2224
   752
      break;
raj@2224
   753
    }
raj@2316
   754
    case SERV_NOTIFY:
raj@2316
   755
      NS_LOG_LOGIC ("TcpSocket " << this <<" Action SERV_NOTIFY");
raj@2316
   756
      NS_LOG_LOGIC ("TcpSocket " << this << " Connected!");
raj@2330
   757
      NotifyNewConnectionCreated (this, fromAddress);
raj@2316
   758
      m_connected = true; // ! This is bogus; fix when we clone the tcp
mathieu@2608
   759
      m_endPoint->SetPeer (m_remoteAddress, m_remotePort);
raj@2316
   760
      //treat the connection orientation final ack as a newack
raj@2316
   761
      CommonNewAck (tcpHeader.GetAckNumber (), true);
raj@2316
   762
      break;
raj@2224
   763
    default:
raj@2224
   764
      break;
raj@2224
   765
  }
raj@2224
   766
  return true;
raj@2224
   767
}
raj@2224
   768
mathieu@2608
   769
void TcpSocket::CompleteFork(Ptr<Packet> p, const TcpHeader& h, const Address& fromAddress)
mathieu@2608
   770
{
mathieu@2608
   771
  // Get port and address from peer (connecting host)
mathieu@2608
   772
  m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort ();
mathieu@2608
   773
  m_remoteAddress = InetSocketAddress::ConvertFrom (fromAddress).GetIpv4 ();
mathieu@2608
   774
  m_endPoint = m_tcp->Allocate (m_localAddress,
mathieu@2608
   775
                                m_localPort,
mathieu@2608
   776
                                m_remoteAddress,
mathieu@2608
   777
                                m_remotePort);
mathieu@2608
   778
  //the cloned socket with be in listen state, so manually change state
mathieu@2608
   779
  m_state = SYN_RCVD;
mathieu@2608
   780
  //equivalent to FinishBind
raj@2668
   781
  m_endPoint->SetRxCallback (MakeCallback (&TcpSocket::ForwardUp, Ptr<TcpSocket>(this)));
raj@2668
   782
  m_endPoint->SetDestroyCallback (MakeCallback (&TcpSocket::Destroy, Ptr<TcpSocket>(this)));
mathieu@2608
   783
  ProcessPacketAction(SYN_ACK_TX, p, h, fromAddress);
mathieu@2608
   784
 }
mathieu@2608
   785
mathieu@2608
   786
void TcpSocket::ConnectionSucceeded()
mathieu@2608
   787
{ // We would preferred to have scheduled an event directly to
mathieu@2608
   788
  // NotifyConnectionSucceeded, but (sigh) these are protected
mathieu@2608
   789
  // and we can get the address of it :(
mathieu@2608
   790
  NotifyConnectionSucceeded();
mathieu@2608
   791
}
mathieu@2608
   792
raj@2224
   793
bool TcpSocket::SendPendingData (bool withAck)
raj@2224
   794
{
raj@2224
   795
  NS_LOG_FUNCTION;
raj@2224
   796
  NS_LOG_PARAMS (this << withAck);
raj@2224
   797
  NS_LOG_LOGIC ("ENTERING SendPendingData");
raj@2224
   798
  if (!m_pendingData)
raj@2224
   799
    {
raj@2224
   800
      return false; // No data exists
raj@2224
   801
    }
raj@2224
   802
  uint32_t nPacketsSent = 0;
raj@2224
   803
  while (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence))
raj@2224
   804
    {
raj@2224
   805
      uint32_t w = AvailableWindow ();// Get available window size
raj@2224
   806
      NS_LOG_LOGIC ("TcpSocket " << this << " SendPendingData"
raj@2224
   807
           << " w " << w 
raj@2224
   808
           << " rxwin " << m_rxWindowSize
raj@2224
   809
           << " cWnd " << m_cWnd
raj@2224
   810
           << " segsize " << m_segmentSize
raj@2224
   811
           << " nextTxSeq " << m_nextTxSequence
raj@2224
   812
           << " highestRxAck " << m_highestRxAck 
raj@2224
   813
           << " pd->Size " << m_pendingData->Size ()
raj@2224
   814
           << " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence));
raj@2224
   815
raj@2224
   816
      if (w < m_segmentSize && m_pendingData->Size () > w)
raj@2224
   817
        {
raj@2224
   818
          break; // No more
raj@2224
   819
        }
raj@2224
   820
      uint32_t s = std::min (w, m_segmentSize);  // Send no more than window
raj@2354
   821
      Ptr<Packet> p = m_pendingData->CopyFromSeq (s, m_firstPendingSequence, 
raj@2224
   822
        m_nextTxSequence);
raj@2224
   823
      NS_LOG_LOGIC("TcpSocket " << this << " sendPendingData"
raj@2224
   824
                   << " txseq " << m_nextTxSequence
raj@2224
   825
                   << " s " << s 
raj@2354
   826
                   << " datasize " << p->GetSize() );
raj@2224
   827
      uint8_t flags = 0;
raj@2224
   828
      if (withAck)
raj@2224
   829
        {
raj@2224
   830
          flags |= TcpHeader::ACK;
raj@2224
   831
        }
raj@2354
   832
      uint32_t sz = p->GetSize (); // Size of packet
raj@2224
   833
      uint32_t remainingData = m_pendingData->SizeFromSeq(
raj@2224
   834
          m_firstPendingSequence,
raj@2224
   835
          m_nextTxSequence + SequenceNumber (sz));
raj@2224
   836
      if (m_closeOnEmpty && (remainingData == 0))
raj@2224
   837
        {
raj@2224
   838
          flags = TcpHeader::FIN;
raj@2224
   839
          m_state = FIN_WAIT_1;
raj@2224
   840
        }
raj@2224
   841
raj@2224
   842
      TcpHeader header;
raj@2224
   843
      header.SetFlags (flags);
raj@2224
   844
      header.SetSequenceNumber (m_nextTxSequence);
raj@2224
   845
      header.SetAckNumber (m_nextRxSequence);
raj@2224
   846
      header.SetSourcePort (m_endPoint->GetLocalPort());
mathieu@2608
   847
      header.SetDestinationPort (m_remotePort);
raj@2224
   848
      if (m_shutdownSend)
raj@2224
   849
        {
raj@2224
   850
          m_errno = ERROR_SHUTDOWN;
raj@2224
   851
          return -1;
raj@2224
   852
        }
raj@2224
   853
raj@2224
   854
      Time rto = m_rtt->RetransmitTimeout ();
raj@2224
   855
      if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit
raj@2224
   856
        {
raj@2224
   857
          NS_LOG_LOGIC ("Schedule retransmission timeout at time " << 
raj@2224
   858
              Simulator::Now ().GetSeconds () << " to expire at time " <<
raj@2224
   859
              (Simulator::Now () + rto).GetSeconds () );
raj@2224
   860
          m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this);
raj@2224
   861
        }
raj@2224
   862
      NS_LOG_LOGIC ("About to send a packet with flags: " << flags);
raj@2224
   863
      m_tcp->SendPacket (p, header,
raj@2224
   864
                         m_endPoint->GetLocalAddress (),
mathieu@2608
   865
                         m_remoteAddress);
tomh@2340
   866
      m_rtt->SentSeq(m_nextTxSequence, sz);       // notify the RTT
tomh@2340
   867
      // Notify the application
tomh@2340
   868
      Simulator::ScheduleNow(&TcpSocket::NotifyDataSent, this, p->GetSize ());
tomh@2340
   869
      nPacketsSent++;                             // Count sent this loop
tomh@2340
   870
      m_nextTxSequence += sz;                     // Advance next tx sequence
tomh@2340
   871
      // Note the high water mark
tomh@2340
   872
      m_highTxMark = std::max (m_nextTxSequence, m_highTxMark);
raj@2224
   873
    }
raj@2224
   874
  NS_LOG_LOGIC ("Sent "<<nPacketsSent<<" packets");
raj@2224
   875
  NS_LOG_LOGIC("RETURN SendPendingData");
raj@2224
   876
  return (nPacketsSent>0);
raj@2224
   877
}
raj@2224
   878
raj@2224
   879
uint32_t  TcpSocket::UnAckDataCount ()
raj@2224
   880
{
raj@2224
   881
  NS_LOG_FUNCTION;
raj@2224
   882
  return m_nextTxSequence - m_highestRxAck;
raj@2224
   883
}
raj@2224
   884
raj@2224
   885
uint32_t  TcpSocket::BytesInFlight ()
raj@2224
   886
{
raj@2224
   887
  NS_LOG_FUNCTION;
raj@2224
   888
  return m_highTxMark - m_highestRxAck;
raj@2224
   889
}
raj@2224
   890
raj@2224
   891
uint32_t  TcpSocket::Window ()
raj@2224
   892
{
raj@2224
   893
  NS_LOG_FUNCTION;
raj@2224
   894
  NS_LOG_LOGIC ("TcpSocket::Window() "<<this);
raj@2224
   895
  return std::min (m_rxWindowSize, m_cWnd);
raj@2224
   896
}
raj@2224
   897
raj@2224
   898
uint32_t  TcpSocket::AvailableWindow ()
raj@2224
   899
{
raj@2224
   900
  NS_LOG_FUNCTION;
raj@2224
   901
  uint32_t unack = UnAckDataCount (); // Number of outstanding bytes
raj@2224
   902
  uint32_t win = Window ();
raj@2224
   903
  if (win < unack) 
raj@2224
   904
    {
raj@2224
   905
      return 0;  // No space available
raj@2224
   906
    }
raj@2224
   907
  return (win - unack);       // Amount of window space available
raj@2224
   908
}
raj@2224
   909
raj@2224
   910
void TcpSocket::NewRx (Ptr<Packet> p,
raj@2224
   911
                        const TcpHeader& tcpHeader, 
raj@2224
   912
                        const Address& fromAddress)
raj@2224
   913
{
raj@2224
   914
  NS_LOG_FUNCTION;
raj@2224
   915
  NS_LOG_PARAMS (this << p << "tcpHeader " << fromAddress);
mathieu@2608
   916
  NS_LOG_LOGIC ("TcpSocket " << this << " NewRx,"
mathieu@2608
   917
                << " seq " << tcpHeader.GetSequenceNumber()
mathieu@2608
   918
                << " ack " << tcpHeader.GetAckNumber()
mathieu@2608
   919
                << " p.size is " << p->GetSize () );
mathieu@2608
   920
  NS_LOG_DEBUG ("TcpSocket " << this <<
mathieu@2608
   921
                " NewRx," <<
mathieu@2608
   922
                " seq " << tcpHeader.GetSequenceNumber() <<
mathieu@2608
   923
                " ack " << tcpHeader.GetAckNumber() <<
mathieu@2608
   924
                " p.size is " << p->GetSize());
raj@2224
   925
  States_t origState = m_state;
raj@2224
   926
  uint32_t s = p->GetSize ();  // Size of associated data
raj@2224
   927
  if (s == 0)
raj@2224
   928
    {// Nothing to do if no associated data
raj@2224
   929
      return;
raj@2224
   930
    }
raj@2224
   931
  // Log sequence received if enabled
raj@2224
   932
  // NoteTimeSeq(LOG_SEQ_RX, h->sequenceNumber);
raj@2224
   933
  // Three possibilities
raj@2224
   934
  // 1) Received seq is expected, deliver this and any buffered data
raj@2224
   935
  // 2) Received seq is < expected, just re-ack previous
raj@2224
   936
  // 3) Received seq is > expected, just re-ack previous and buffer data
raj@2224
   937
  if (tcpHeader.GetSequenceNumber () == m_nextRxSequence)
raj@2224
   938
    { // If seq is expected seq
raj@2224
   939
      // 1) Update nextRxSeq
raj@2224
   940
      // 2) Deliver to application this packet
raj@2224
   941
      // 3) See if any buffered can be delivered
raj@2224
   942
      // 4) Send the ack
raj@2224
   943
      m_nextRxSequence += s;           // Advance next expected sequence
raj@2224
   944
      //bytesReceived += s;       // Statistics
raj@2224
   945
      NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence );
mathieu@2608
   946
      NotifyDataReceived (p, fromAddress);
raj@2224
   947
      if (m_closeNotified)
raj@2224
   948
        {
raj@2224
   949
          NS_LOG_LOGIC ("Tcp " << this << " HuH?  Got data after closeNotif");
raj@2224
   950
        }
raj@2224
   951
      NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq by " << s);
raj@2224
   952
      // Look for buffered data
raj@2224
   953
      UnAckData_t::iterator i;
raj@2224
   954
      // Note that the bufferedData list DOES contain the tcp header
raj@2224
   955
      while (!m_bufferedData.empty ())
raj@2224
   956
        { // Check the buffered data for delivery
raj@2224
   957
          NS_LOG_LOGIC("TCP " << this << " bufferedData.size() " 
raj@2224
   958
              << m_bufferedData.size () 
raj@2224
   959
              << " time " << Simulator::Now ());
raj@2224
   960
          i = m_bufferedData.begin ();
raj@2224
   961
          Ptr<Packet> p1 = i->second;
raj@2224
   962
          SequenceNumber s1 = 0;
raj@2224
   963
          if (i->first > m_nextRxSequence) 
raj@2224
   964
            {
raj@2224
   965
              break;  // Not next expected
raj@2224
   966
            }
raj@2224
   967
          // already have the header as a param
raj@2224
   968
          //TCPHeader* h = dynamic_cast<TCPHeader*>(p1->PopPDU());
raj@2224
   969
          // Check non-null here...
raj@2224
   970
          uint8_t flags = tcpHeader.GetFlags ();           // Flags (used below)
raj@2224
   971
          if (i->first < m_nextRxSequence)
raj@2224
   972
            { // remove already delivered data
raj@2224
   973
              // Two cases here.
raj@2224
   974
              // 1) seq + length <= nextRxSeq, just discard
raj@2224
   975
              // 2) seq + length > nextRxSeq, can deliver partial
raj@2224
   976
              s1 = p->GetSize ();
raj@2224
   977
              if (i->first + s1 < m_nextRxSequence)
raj@2224
   978
                { // Just remove from list
raj@2224
   979
                  //bufferedData.erase(i);
raj@2224
   980
                  p1 = 0; // Nothing to deliver
raj@2224
   981
                }
raj@2224
   982
              else
raj@2224
   983
                { // Remove partial data to prepare for delivery
raj@2224
   984
                  uint32_t dup = m_nextRxSequence - i->first;
raj@2224
   985
                  i->second = p1->CreateFragment (0, p1->GetSize () - dup);
raj@2224
   986
                  p1 = i->second;
raj@2224
   987
                }
raj@2224
   988
            }
raj@2224
   989
          else
raj@2224
   990
            { // At this point i->first must equal nextRxSeq
raj@2224
   991
              if (i->first != m_nextRxSequence)
raj@2224
   992
                {
raj@2224
   993
                  NS_FATAL_ERROR ("HuH?  NexRx failure, first " 
raj@2224
   994
                      << i->first << " nextRxSeq " << m_nextRxSequence);
raj@2224
   995
                }
raj@2224
   996
              s1 = p1->GetSize ();
raj@2224
   997
            }
raj@2224
   998
          NotifyDataReceived (p1, fromAddress);
raj@2224
   999
raj@2224
  1000
          NS_LOG_LOGIC ("TcpSocket " << this << " adv rxseq1 by " << s1 );
raj@2224
  1001
          m_nextRxSequence += s1;           // Note data received
raj@2224
  1002
          m_bufferedData.erase (i);     // Remove from list
raj@2224
  1003
          if (flags & TcpHeader::FIN)
raj@2224
  1004
            NS_LOG_LOGIC("TcpSocket " << this 
raj@2224
  1005
                    << " found FIN in buffered");
raj@2224
  1006
        }
raj@2224
  1007
raj@2224
  1008
      if (m_pendingClose || (origState > ESTABLISHED))
raj@2224
  1009
        { // See if we can close now
raj@2224
  1010
          if (m_bufferedData.empty())
raj@2224
  1011
            {
raj@2224
  1012
              ProcessPacketAction (PEER_CLOSE, p, tcpHeader, fromAddress);
raj@2224
  1013
            }
raj@2224
  1014
        }
raj@2224
  1015
    }
raj@2224
  1016
  else if (SequenceNumber (tcpHeader.GetSequenceNumber ()) >= m_nextRxSequence)
raj@2224
  1017
    { // Need to buffer this one
raj@2224
  1018
      NS_LOG_LOGIC ("Case 2, buffering " << tcpHeader.GetSequenceNumber () );
raj@2224
  1019
      UnAckData_t::iterator i = 
raj@2224
  1020
        m_bufferedData.find (tcpHeader.GetSequenceNumber () );
raj@2224
  1021
      if (i != m_bufferedData.end () )
raj@2224
  1022
        {
raj@2224
  1023
          i->second = 0; // relase reference to already buffered
raj@2224
  1024
        }
raj@2224
  1025
      // Save for later delivery
raj@2224
  1026
      m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;  
raj@2224
  1027
    }
raj@2224
  1028
  else
raj@2224
  1029
    { // debug
raj@2224
  1030
      NS_LOG_LOGIC("TCP " << this 
raj@2224
  1031
               << " got seq " << tcpHeader.GetSequenceNumber ()
raj@2224
  1032
               << " expected " << m_nextRxSequence
raj@2224
  1033
               << "       flags " << tcpHeader.GetFlags ());
raj@2224
  1034
    }
raj@2224
  1035
  // Now send a new ack packet acknowledging all received and delivered data
raj@2224
  1036
  SendEmptyPacket (TcpHeader::ACK);
raj@2224
  1037
}
raj@2224
  1038
raj@2224
  1039
raj@2224
  1040
void TcpSocket::CommonNewAck (SequenceNumber ack, bool skipTimer)
raj@2224
  1041
{ // CommonNewAck is called only for "New" (non-duplicate) acks
raj@2224
  1042
  // and MUST be called by any subclass, from the NewAck function
raj@2224
  1043
  // Always cancel any pending re-tx timer on new acknowledgement
raj@2224
  1044
  NS_LOG_FUNCTION;
raj@2224
  1045
  NS_LOG_PARAMS (this << ack << skipTimer);
raj@2224
  1046
  //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl));
raj@2224
  1047
  if (!skipTimer)
raj@2224
  1048
    {
raj@2224
  1049
      m_retxEvent.Cancel ();
raj@2224
  1050
    }
raj@2224
  1051
  NS_LOG_LOGIC ("TCP " << this << " NewAck " << ack 
tomh@2227
  1052
           << " numberAck " << (ack - m_highestRxAck)); // Number bytes ack'ed
raj@2224
  1053
  m_highestRxAck = ack;         // Note the highest recieved Ack
raj@2224
  1054
  if (ack > m_nextTxSequence) 
raj@2224
  1055
    {
raj@2224
  1056
      m_nextTxSequence = ack; // If advanced
raj@2224
  1057
    }
raj@2224
  1058
  // See if all pending ack'ed; if so we can delete the data
raj@2224
  1059
  if (m_pendingData)
raj@2224
  1060
    { // Data exists, see if can be deleted
raj@2224
  1061
      if (m_pendingData->SizeFromSeq (m_firstPendingSequence, m_highestRxAck) == 0)
raj@2224
  1062
        { // All pending acked, can be deleted
raj@2224
  1063
          m_pendingData->Clear ();
raj@2224
  1064
          delete m_pendingData;
raj@2224
  1065
          m_pendingData = 0;
raj@2224
  1066
          // Insure no re-tx timer
raj@2353
  1067
          m_retxEvent.Cancel ();
raj@2224
  1068
        }
raj@2224
  1069
    }
raj@2224
  1070
  // Try to send more data
raj@2224
  1071
  SendPendingData();
raj@2224
  1072
}
raj@2224
  1073
mathieu@2608
  1074
Ptr<TcpSocket> TcpSocket::Copy ()
mathieu@2608
  1075
{
mathieu@2608
  1076
  return CopyObject<TcpSocket> (this);
mathieu@2608
  1077
}
mathieu@2608
  1078
raj@2224
  1079
void TcpSocket::NewAck (SequenceNumber seq)
raj@2224
  1080
{ // New acknowledgement up to sequence number "seq"
raj@2224
  1081
  // Adjust congestion window in response to new ack's received
raj@2224
  1082
  NS_LOG_FUNCTION;
raj@2224
  1083
  NS_LOG_PARAMS (this << seq);
raj@2224
  1084
  NS_LOG_LOGIC ("TcpSocket " << this << " NewAck "
raj@2224
  1085
           << " seq " << seq
raj@2224
  1086
           << " cWnd " << m_cWnd
raj@2224
  1087
           << " ssThresh " << m_ssThresh);
raj@2224
  1088
  if (m_cWnd < m_ssThresh)
raj@2224
  1089
    { // Slow start mode, add one segSize to cWnd
raj@2224
  1090
      m_cWnd += m_segmentSize;
raj@2224
  1091
      NS_LOG_LOGIC ("TcpSocket " << this << " NewCWnd SlowStart, cWnd " << m_cWnd 
raj@2224
  1092
          << " sst " << m_ssThresh);
raj@2224
  1093
    }
raj@2224
  1094
  else
raj@2224
  1095
    { // Congestion avoidance mode, adjust by (ackBytes*segSize) / cWnd
raj@2224
  1096
      double adder =  ((double) m_segmentSize * m_segmentSize) / m_cWnd;
raj@2224
  1097
      if (adder < 1.0) 
raj@2224
  1098
        {
raj@2224
  1099
          adder = 1.0;
raj@2224
  1100
        }
raj@2224
  1101
      m_cWnd += (uint32_t) adder;
raj@2224
  1102
      NS_LOG_LOGIC ("NewCWnd CongAvoid, cWnd " << m_cWnd 
raj@2224
  1103
           << " sst " << m_ssThresh);
raj@2224
  1104
    }
raj@2224
  1105
  CommonNewAck (seq, false);           // Complete newAck processing
raj@2224
  1106
}
raj@2224
  1107
raj@2224
  1108
void TcpSocket::DupAck (const TcpHeader& t, uint32_t count)
raj@2224
  1109
{
raj@2224
  1110
  NS_LOG_FUNCTION;
raj@2224
  1111
  NS_LOG_PARAMS (this << "t " << count);
raj@2224
  1112
  NS_LOG_LOGIC ("TcpSocket " << this << " DupAck " <<  t.GetAckNumber ()
raj@2224
  1113
      << ", count " << count
raj@2224
  1114
      << ", time " << Simulator::Now ());
raj@2224
  1115
  if (count == 3)
raj@2224
  1116
  { // Count of three indicates triple duplicate ack
raj@2224
  1117
    m_ssThresh = Window () / 2; // Per RFC2581
raj@2224
  1118
    m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
raj@2224
  1119
    NS_LOG_LOGIC("TcpSocket " << this << "Tahoe TDA, time " << Simulator::Now ()
raj@2224
  1120
        << " seq " << t.GetAckNumber ()
raj@2224
  1121
        << " in flight " << BytesInFlight ()
raj@2224
  1122
        << " new ssthresh " << m_ssThresh);
raj@2224
  1123
raj@2224
  1124
    m_cWnd = m_segmentSize; // Collapse cwnd (re-enter slowstart)
raj@2224
  1125
    // For Tahoe, we also reset nextTxSeq
raj@2224
  1126
    m_nextTxSequence = m_highestRxAck;
raj@2224
  1127
    SendPendingData ();
raj@2224
  1128
  }
raj@2224
  1129
}
raj@2224
  1130
raj@2224
  1131
void TcpSocket::ReTxTimeout ()
raj@2224
  1132
{ // Retransmit timeout
raj@2224
  1133
  NS_LOG_FUNCTION;
raj@2224
  1134
  NS_LOG_PARAMS (this);
raj@2224
  1135
  m_ssThresh = Window () / 2; // Per RFC2581
raj@2224
  1136
  m_ssThresh = std::max (m_ssThresh, 2 * m_segmentSize);
raj@2224
  1137
  // Set cWnd to segSize on timeout,  per rfc2581
raj@2224
  1138
  // Collapse congestion window (re-enter slowstart)
raj@2224
  1139
  m_cWnd = m_segmentSize;           
raj@2224
  1140
  m_nextTxSequence = m_highestRxAck; // Start from highest Ack
raj@2224
  1141
  m_rtt->IncreaseMultiplier (); // Double timeout value for next retx timer
raj@2224
  1142
  Retransmit ();             // Retransmit the packet
raj@2224
  1143
}
raj@2224
  1144
raj@2224
  1145
void TcpSocket::LastAckTimeout ()
raj@2224
  1146
{
raj@2224
  1147
  m_lastAckEvent.Cancel ();
raj@2224
  1148
  if (m_state == LAST_ACK)
raj@2224
  1149
    {
raj@2224
  1150
      Actions_t action = ProcessEvent (TIMEOUT);
raj@2224
  1151
      ProcessAction (action);
raj@2224
  1152
    }
raj@2224
  1153
  if (!m_closeNotified)
raj@2224
  1154
    {
raj@2224
  1155
      m_closeNotified = true;
raj@2224
  1156
    }
raj@2224
  1157
}
raj@2224
  1158
raj@2224
  1159
void TcpSocket::Retransmit ()
raj@2224
  1160
{
raj@2224
  1161
  NS_LOG_FUNCTION;
raj@2224
  1162
  NS_LOG_PARAMS (this);
raj@2224
  1163
  uint8_t flags = TcpHeader::NONE;
raj@2224
  1164
  if (m_state == SYN_SENT) 
raj@2224
  1165
    {
raj@2224
  1166
      if (m_cnCount > 0) 
raj@2224
  1167
        {
raj@2224
  1168
          SendEmptyPacket (TcpHeader::SYN);
raj@2224
  1169
          return;
raj@2224
  1170
        }
raj@2224
  1171
      else
raj@2224
  1172
        {
raj@2224
  1173
          NotifyConnectionFailed ();
raj@2224
  1174
          return;
raj@2224
  1175
        }
raj@2224
  1176
    } 
raj@2224
  1177
  if (!m_pendingData)
raj@2224
  1178
    {
raj@2224
  1179
      if (m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2)
raj@2224
  1180
        { // Must have lost FIN, re-send
raj@2224
  1181
          SendEmptyPacket (TcpHeader::FIN);
raj@2224
  1182
        }
raj@2224
  1183
      return;
raj@2224
  1184
    }
raj@2354
  1185
  Ptr<Packet> p = m_pendingData->CopyFromSeq (m_segmentSize,
raj@2224
  1186
                                            m_firstPendingSequence,
raj@2224
  1187
                                            m_highestRxAck);
raj@2224
  1188
  // Calculate remaining data for COE check
raj@2354
  1189
  uint32_t remainingData = m_pendingData->SizeFromSeq (
raj@2354
  1190
      m_firstPendingSequence,
raj@2354
  1191
      m_nextTxSequence + SequenceNumber(p->GetSize ()));
raj@2224
  1192
  if (m_closeOnEmpty && remainingData == 0)
raj@2224
  1193
    { // Add the FIN flag
raj@2224
  1194
      flags = flags | TcpHeader::FIN;
raj@2224
  1195
    }
raj@2354
  1196
raj@2224
  1197
  NS_LOG_LOGIC ("TcpSocket " << this << " retxing seq " << m_highestRxAck);
raj@2224
  1198
  if (m_retxEvent.IsExpired () )
raj@2224
  1199
    {
raj@2224
  1200
      Time rto = m_rtt->RetransmitTimeout ();
raj@2224
  1201
      NS_LOG_LOGIC ("Schedule retransmission timeout at time "
raj@2224
  1202
          << Simulator::Now ().GetSeconds () << " to expire at time "
raj@2224
  1203
          << (Simulator::Now () + rto).GetSeconds ());
raj@2224
  1204
      m_retxEvent = Simulator::Schedule (rto,&TcpSocket::ReTxTimeout,this);
raj@2224
  1205
    }
raj@2354
  1206
  m_rtt->SentSeq (m_highestRxAck,p->GetSize ());
raj@2224
  1207
  // And send the packet
raj@2224
  1208
  TcpHeader tcpHeader;
raj@2224
  1209
  tcpHeader.SetSequenceNumber (m_nextTxSequence);
raj@2224
  1210
  tcpHeader.SetAckNumber (m_nextRxSequence);
raj@2224
  1211
  tcpHeader.SetSourcePort (m_endPoint->GetLocalPort());
mathieu@2608
  1212
  tcpHeader.SetDestinationPort (m_remotePort);
raj@2224
  1213
  tcpHeader.SetFlags (flags);
raj@2224
  1214
  tcpHeader.SetWindowSize (m_advertisedWindowSize);
raj@2224
  1215
raj@2224
  1216
  m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (),
mathieu@2608
  1217
    m_remoteAddress);
raj@2224
  1218
}
raj@2224
  1219
raj@2224
  1220
}//namespace ns3