examples/tcp-2way.cc
author Raj Bhattacharjea <raj.b@gatech.edu>
Wed Jul 09 17:04:29 2008 -0400 (2008-07-09)
changeset 3400 fd69b15002ee
permissions -rw-r--r--
Add David Evensky's tcp-2way regression test
raj@3400
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
raj@3400
     2
/*
raj@3400
     3
 * Copyright 2007 University of Washington
raj@3400
     4
 * Copyright 2007 Georgia Tech Research Corporation
raj@3400
     5
 * Copyright 2008 Sandia Corporation
raj@3400
     6
 *
raj@3400
     7
 * This program is free software; you can redistribute it and/or modify
raj@3400
     8
 * it under the terms of the GNU General Public License version 2 as
raj@3400
     9
 * published by the Free Software Foundation;
raj@3400
    10
 *
raj@3400
    11
 * This program is distributed in the hope that it will be useful,
raj@3400
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
raj@3400
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
raj@3400
    14
 * GNU General Public License for more details.
raj@3400
    15
 *
raj@3400
    16
 * You should have received a copy of the GNU General Public License
raj@3400
    17
 * along with this program; if not, write to the Free Software
raj@3400
    18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
raj@3400
    19
 *
raj@3400
    20
 *
raj@3400
    21
 * Sandia is a multiprogram laboratory operated by Sandia
raj@3400
    22
 * Corporation, a Lockheed Martin Company, for the United States
raj@3400
    23
 * Department of Energy's National Nuclear Security Administration
raj@3400
    24
 * under Contract DE-AC04-94AL85000.
raj@3400
    25
 *
raj@3400
    26
 * Author: David Evensky, Sandia National Labs
raj@3400
    27
 *
raj@3400
    28
 * includes GPL'ed ns-3-dev code from:
raj@3400
    29
 *   udp-echo,          // ??, (c) U. Wash. 2007
raj@3400
    30
 *   tcp-large-transfer // ??
raj@3400
    31
 *   packet-sink        // Tom Henderson, (c) U. Wash. 2007
raj@3400
    32
 *   onoff              // George F. Riley, (c) GT Res Corp. 2007
raj@3400
    33
 */
raj@3400
    34
raj@3400
    35
raj@3400
    36
/* NOTE
raj@3400
    37
This isn't really an example file, so don't look to closely at it as a starting
raj@3400
    38
script.  It is here for validation of the TCP model.
raj@3400
    39
*/
raj@3400
    40
raj@3400
    41
#include <iostream>
raj@3400
    42
#include <fstream>
raj@3400
    43
#include <sstream>
raj@3400
    44
#include <string>
raj@3400
    45
#include <iomanip>
raj@3400
    46
#include <map>
raj@3400
    47
raj@3400
    48
#include "ns3/core-module.h"
raj@3400
    49
#include "ns3/helper-module.h"
raj@3400
    50
#include "ns3/node-module.h"
raj@3400
    51
#include "ns3/global-route-manager.h"
raj@3400
    52
#include "ns3/simulator-module.h"
raj@3400
    53
#include "ns3/log.h"
raj@3400
    54
raj@3400
    55
using namespace ns3;
raj@3400
    56
raj@3400
    57
NS_LOG_COMPONENT_DEFINE ("tcp-2way");
raj@3400
    58
raj@3400
    59
//----------defines-------------------------------------------------------------
raj@3400
    60
//define to print more debugging info.
raj@3400
    61
#define VERBOSE_TESTING
raj@3400
    62
raj@3400
    63
/* define to die because Socket::Recv() is told to
raj@3400
    64
 * only read an "undesired" number of bytes
raj@3400
    65
 * fails NS_ASSERT in HandleRead because rx_addr_tag
raj@3400
    66
 * tag isn't there.
raj@3400
    67
 */
raj@3400
    68
//#define TOO_SMALL_BUG
raj@3400
    69
raj@3400
    70
//define to print this pointer in NS_LOG_FUNCTION
raj@3400
    71
//#define PRINT_THIS
raj@3400
    72
raj@3400
    73
/*define to print packet info in HandleRead
raj@3400
    74
 *expected output is of the form:
raj@3400
    75
 *536:P{536} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00] <0|536|884018>
raj@3400
    76
 * ^  ^      ^              ^             ^                  ^   ^ ^
raj@3400
    77
 * |  |      |              |             |                  |   | |
raj@3400
    78
 * |  |      |              |             |                  |   | +bytes left
raj@3400
    79
 * |  |      |              |             |                  |   |  to read in
raj@3400
    80
 * |  |      |              |             |                  |   |  sent buffer
raj@3400
    81
 * |  |      |              |             |                  |   +bytes read in
raj@3400
    82
 * |  |      |              |             |                  |    this packet if
raj@3400
    83
 * |  |      |              |             |                  |    header read,
raj@3400
    84
 * |  |      |              |             |                  |    prints size
raj@3400
    85
 * |  |      |              |             |                  |    in ()
raj@3400
    86
 * |  |      |              |             |                  +bytes cur. packet
raj@3400
    87
 * |  |      |              |             |                   left to process
raj@3400
    88
 * |  |      |              |             +mac addr of sender
raj@3400
    89
 * |  |      |              +IP addr of sender
raj@3400
    90
 * |  |      +print '*' while processing first chunk in a received packet.
raj@3400
    91
 * |  |       if there are multiple small sent packets, these can appear in
raj@3400
    92
 * |  |       a single packet, and are processed by a do {} while() loop.
raj@3400
    93
 * |  +rle output of packet::PeekData(), in this case filled with 536 bytes
raj@3400
    94
 * |   filled with the letter 'P' (brought to you by the letter 'Q' and the
raj@3400
    95
 * |   number '9' :-))
raj@3400
    96
 * + packet::GetSize()
raj@3400
    97
 *
raj@3400
    98
 * If there is a header it will look more like:
raj@3400
    99
 * 536:N{317}@B.{6}HELLOP{206} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
raj@3400
   100
 *                                                                   <219|317|0>
raj@3400
   101
 * 536:N{317}@B.{6}HELLOP{206}  bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
raj@3400
   102
 *                               <0|206(13)|999794> (ArchHeader=HELLO:1000000)
raj@3400
   103
 * where you can see that this first packet includes 317 bytes from the
raj@3400
   104
 * previous send packet (filled with N) and 13 bytes of header before the 206
raj@3400
   105
 * bytes of payload (filled with P).
raj@3400
   106
 */
raj@3400
   107
raj@3400
   108
#define RECV_PRINT
raj@3400
   109
raj@3400
   110
// dcl non-method functions....
raj@3400
   111
std::string rle(const uint8_t *, int );
raj@3400
   112
std::ofstream fileOut("tcp-2way.out");
raj@3400
   113
raj@3400
   114
//----------class ArchHeader dcl and definition---------------------------------
raj@3400
   115
/*
raj@3400
   116
 * ArchHeader: A toy header that holds a string
raj@3400
   117
 * and a uint32_t. The string is an abitrary label
raj@3400
   118
 * and the int is used as the length of the payload.
raj@3400
   119
 */
raj@3400
   120
raj@3400
   121
class ArchHeader : public Header {
raj@3400
   122
public:
raj@3400
   123
  virtual uint32_t  GetSerializedSize (void) const;
raj@3400
   124
  virtual void      Serialize (Buffer::Iterator) const;
raj@3400
   125
  virtual uint32_t  Deserialize (Buffer::Iterator);
raj@3400
   126
  virtual void      Print (std::ostream &) const;
raj@3400
   127
  static  TypeId    GetTypeId (void);
raj@3400
   128
  virtual TypeId    GetInstanceTypeId (void) const;
raj@3400
   129
raj@3400
   130
  // accessor functions.....
raj@3400
   131
  void        SetIntValue (uint32_t);
raj@3400
   132
  uint32_t    GetIntValue (void) const;
raj@3400
   133
  void        SetStrValue (const std::string &s);
raj@3400
   134
  std::string GetStrValue (void) const;
raj@3400
   135
private:
raj@3400
   136
  uint32_t          int_value;
raj@3400
   137
  std::string       str_value;
raj@3400
   138
};
raj@3400
   139
raj@3400
   140
raj@3400
   141
TypeId
raj@3400
   142
ArchHeader::GetTypeId (void)
raj@3400
   143
{
raj@3400
   144
  static TypeId tid = TypeId ("ns3::ArchHeader")
raj@3400
   145
    .AddConstructor<ArchHeader> () // NOTE: Required for ????
raj@3400
   146
    .SetParent<Header> ()          // ditto
raj@3400
   147
    ;
raj@3400
   148
  return tid;
raj@3400
   149
}
raj@3400
   150
raj@3400
   151
TypeId
raj@3400
   152
ArchHeader::GetInstanceTypeId (void) const
raj@3400
   153
{
raj@3400
   154
  return GetTypeId ();
raj@3400
   155
}
raj@3400
   156
raj@3400
   157
uint32_t
raj@3400
   158
ArchHeader::GetSerializedSize (void) const
raj@3400
   159
{
raj@3400
   160
  return 2*sizeof (uint32_t) + str_value.size (); // int, str len & bytes
raj@3400
   161
}
raj@3400
   162
raj@3400
   163
void
raj@3400
   164
ArchHeader::Serialize (Buffer::Iterator i) const
raj@3400
   165
{
raj@3400
   166
  i.WriteU32 (int_value);
raj@3400
   167
  uint32_t str_len = str_value.size ();
raj@3400
   168
  i.WriteU32 (str_len);
raj@3400
   169
  for (uint32_t j = 0; j < str_value.size (); j++)
raj@3400
   170
    i.WriteU8 (str_value[j]);
raj@3400
   171
}
raj@3400
   172
  
raj@3400
   173
uint32_t
raj@3400
   174
ArchHeader::Deserialize (Buffer::Iterator i)
raj@3400
   175
{
raj@3400
   176
  int_value = i.ReadU32 ();
raj@3400
   177
  uint32_t str_len = i.ReadU32 ();
raj@3400
   178
  str_value.reserve (str_len);
raj@3400
   179
  for (uint32_t j = 0; j < str_len; j++) {
raj@3400
   180
    char v = i.ReadU8 ();
raj@3400
   181
    str_value.push_back (v);
raj@3400
   182
  }
raj@3400
   183
  return 2*sizeof (uint32_t) + str_value.size ();
raj@3400
   184
}
raj@3400
   185
raj@3400
   186
raj@3400
   187
void
raj@3400
   188
ArchHeader::SetIntValue (uint32_t v_)
raj@3400
   189
{
raj@3400
   190
  int_value = v_;
raj@3400
   191
}
raj@3400
   192
raj@3400
   193
uint32_t
raj@3400
   194
ArchHeader::GetIntValue (void) const
raj@3400
   195
{
raj@3400
   196
  return int_value;
raj@3400
   197
}
raj@3400
   198
raj@3400
   199
void
raj@3400
   200
ArchHeader::SetStrValue (const std::string &s)
raj@3400
   201
{
raj@3400
   202
  str_value = s;
raj@3400
   203
}
raj@3400
   204
raj@3400
   205
std::string
raj@3400
   206
ArchHeader::GetStrValue (void) const
raj@3400
   207
{
raj@3400
   208
  return str_value;
raj@3400
   209
}
raj@3400
   210
   
raj@3400
   211
void
raj@3400
   212
ArchHeader::Print (std::ostream &os) const
raj@3400
   213
{
raj@3400
   214
  os << "(ArchHeader=" << str_value << ":" << int_value << ")";
raj@3400
   215
}
raj@3400
   216
raj@3400
   217
//----------class TalkerApp dcl and definition----------------------------------
raj@3400
   218
/*
raj@3400
   219
 * TalkerApp:
raj@3400
   220
 * An an Application that can serve as both Rx and Tx side.
raj@3400
   221
 * and is configured by ConfRecv/ConfSend and driven by
raj@3400
   222
 * ScheduleSendPacket. Becareful not to try to send a packet
raj@3400
   223
 * from the Rx side to the Tx side (back channel) before the
raj@3400
   224
 * connection is setup, which has to be from the Tx to the Rx
raj@3400
   225
 * (the forward channel).
raj@3400
   226
 */
raj@3400
   227
raj@3400
   228
class TalkerApp : public Application {
raj@3400
   229
public:
raj@3400
   230
  TalkerApp ();
raj@3400
   231
  virtual ~TalkerApp ();
raj@3400
   232
  void ConfRecv (Ptr<Node>,const Address &);
raj@3400
   233
  void ConfSend (Ptr<Node>,const Address &);
raj@3400
   234
  void ScheduleSendPacket(const Time ,const char , const uint32_t size );
raj@3400
   235
raj@3400
   236
protected:
raj@3400
   237
  virtual void DoDispose (void);
raj@3400
   238
private:
raj@3400
   239
  virtual void StartApplication (void);
raj@3400
   240
  virtual void StopApplication (void);
raj@3400
   241
raj@3400
   242
  void StartApplicationRecv (void);
raj@3400
   243
  void StartApplicationSend (void);
raj@3400
   244
raj@3400
   245
  void HandleRead (Ptr<Socket>);
raj@3400
   246
  void SendPacket (std::string,char,uint32_t);
raj@3400
   247
raj@3400
   248
  void CloseConnection (Ptr<Socket> socket);
raj@3400
   249
  void ConnectionSucceeded (Ptr<Socket>);
raj@3400
   250
  void ConnectionFailed (Ptr<Socket>);
raj@3400
   251
  bool ConnectionRequested (Ptr<Socket>, const Address &);
raj@3400
   252
  void ConnectionCreated (Ptr<Socket>, const Address &);
raj@3400
   253
raj@3400
   254
raj@3400
   255
  bool            verbose;
raj@3400
   256
  Ptr<Socket>     m_socket;
raj@3400
   257
  Ptr<Socket>     m_servsocket;
raj@3400
   258
  Address         m_local;
raj@3400
   259
  Address         m_remote;
raj@3400
   260
  int             i_am_listener;
raj@3400
   261
  typedef std::map<Ptr<Socket>, uint32_t>::iterator left_to_read_iterator_type;
raj@3400
   262
  std::map<Ptr<Socket>, uint32_t> m_left_to_read;
raj@3400
   263
};
raj@3400
   264
raj@3400
   265
class TalkerApp_sub : public TalkerApp {
raj@3400
   266
public:
raj@3400
   267
  int foo(void);
raj@3400
   268
};
raj@3400
   269
raj@3400
   270
int
raj@3400
   271
TalkerApp_sub::foo(void) {return 0;}
raj@3400
   272
raj@3400
   273
TalkerApp::TalkerApp () :
raj@3400
   274
  verbose (false),
raj@3400
   275
  m_socket (0),
raj@3400
   276
  m_servsocket (0),
raj@3400
   277
  i_am_listener (0)
raj@3400
   278
{}
raj@3400
   279
raj@3400
   280
TalkerApp::~TalkerApp ()
raj@3400
   281
{}
raj@3400
   282
raj@3400
   283
void
raj@3400
   284
TalkerApp::DoDispose (void)
raj@3400
   285
{
raj@3400
   286
  m_socket = 0;
raj@3400
   287
  m_servsocket = 0;
raj@3400
   288
  Application::DoDispose ();
raj@3400
   289
}
raj@3400
   290
raj@3400
   291
raj@3400
   292
void
raj@3400
   293
TalkerApp::CloseConnection (Ptr<Socket> sock)
raj@3400
   294
{
raj@3400
   295
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   296
#ifdef PRINT_THIS                  
raj@3400
   297
                  << this
raj@3400
   298
#endif
raj@3400
   299
                  << sock
raj@3400
   300
                  );
raj@3400
   301
  sock->Close ();
raj@3400
   302
}
raj@3400
   303
raj@3400
   304
void
raj@3400
   305
TalkerApp::ConnectionSucceeded (Ptr<Socket> sock)
raj@3400
   306
{
raj@3400
   307
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   308
#ifdef PRINT_THIS                  
raj@3400
   309
                  << this
raj@3400
   310
#endif
raj@3400
   311
                  << sock
raj@3400
   312
	
raj@3400
   313
		   );
raj@3400
   314
}
raj@3400
   315
raj@3400
   316
void
raj@3400
   317
TalkerApp::ConnectionFailed (Ptr<Socket> sock)
raj@3400
   318
{
raj@3400
   319
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   320
#ifdef PRINT_THIS                  
raj@3400
   321
                  << this
raj@3400
   322
#endif
raj@3400
   323
                  << sock
raj@3400
   324
                  );
raj@3400
   325
}
raj@3400
   326
raj@3400
   327
bool
raj@3400
   328
TalkerApp::ConnectionRequested (Ptr<Socket> sock, const Address &addr)
raj@3400
   329
{
raj@3400
   330
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   331
#ifdef PRINT_THIS                  
raj@3400
   332
                  << this
raj@3400
   333
#endif
raj@3400
   334
                  << sock
raj@3400
   335
                  << addr
raj@3400
   336
                  );
raj@3400
   337
  return true;
raj@3400
   338
}
raj@3400
   339
raj@3400
   340
void
raj@3400
   341
TalkerApp::ConnectionCreated (Ptr<Socket> sock, const Address &addr)
raj@3400
   342
{
raj@3400
   343
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   344
#ifdef PRINT_THIS                  
raj@3400
   345
                  << this
raj@3400
   346
#endif
raj@3400
   347
                  << sock
raj@3400
   348
                  << addr
raj@3400
   349
                  );
raj@3400
   350
  m_socket = sock;
raj@3400
   351
  m_socket->SetRecvCallback(MakeCallback (&TalkerApp::HandleRead, this));
raj@3400
   352
}
raj@3400
   353
raj@3400
   354
void 
raj@3400
   355
TalkerApp::ScheduleSendPacket (const Time dt,const char fill,
raj@3400
   356
                               const uint32_t size)
raj@3400
   357
{
raj@3400
   358
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   359
#ifdef PRINT_THIS                  
raj@3400
   360
                  << this
raj@3400
   361
#endif
raj@3400
   362
                   << dt
raj@3400
   363
                   << fill
raj@3400
   364
                   << size
raj@3400
   365
                   );
raj@3400
   366
  Simulator::Schedule(dt,&TalkerApp::SendPacket, this,
raj@3400
   367
                      std::string("HELLO"),fill,size);
raj@3400
   368
}
raj@3400
   369
raj@3400
   370
raj@3400
   371
void
raj@3400
   372
TalkerApp::StartApplication ()
raj@3400
   373
{
raj@3400
   374
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   375
#ifdef PRINT_THIS                  
raj@3400
   376
                  << this
raj@3400
   377
#endif
raj@3400
   378
                  );
raj@3400
   379
  if (i_am_listener)
raj@3400
   380
    StartApplicationRecv ();
raj@3400
   381
  else
raj@3400
   382
    StartApplicationSend ();
raj@3400
   383
}
raj@3400
   384
raj@3400
   385
void
raj@3400
   386
TalkerApp::StartApplicationSend ()
raj@3400
   387
{
raj@3400
   388
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   389
#ifdef PRINT_THIS                  
raj@3400
   390
                  << this
raj@3400
   391
#endif
raj@3400
   392
                  );
raj@3400
   393
raj@3400
   394
  if (!m_socket) {
raj@3400
   395
    m_socket = Socket::CreateSocket (GetNode (),
raj@3400
   396
				    TcpSocketFactory::GetTypeId ());
raj@3400
   397
    m_socket->Bind ();
raj@3400
   398
  }
raj@3400
   399
raj@3400
   400
  m_socket->Connect (m_remote);
raj@3400
   401
  m_socket->SetConnectCallback
raj@3400
   402
    (
raj@3400
   403
     MakeCallback (&TalkerApp::ConnectionSucceeded,this),
raj@3400
   404
     MakeCallback (&TalkerApp::ConnectionFailed,this)
raj@3400
   405
     );
raj@3400
   406
  m_socket->SetRecvCallback (MakeCallback (&TalkerApp::HandleRead, this));
raj@3400
   407
}
raj@3400
   408
raj@3400
   409
void
raj@3400
   410
TalkerApp::StartApplicationRecv ()
raj@3400
   411
{
raj@3400
   412
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   413
#ifdef PRINT_THIS                  
raj@3400
   414
                  << this
raj@3400
   415
#endif
raj@3400
   416
                  );
raj@3400
   417
  if (!m_servsocket) {
raj@3400
   418
    m_servsocket = Socket::CreateSocket (GetNode (),
raj@3400
   419
					TcpSocketFactory::GetTypeId ());
raj@3400
   420
    m_servsocket->Bind (m_local);
raj@3400
   421
    m_servsocket->Listen (0);
raj@3400
   422
  }
raj@3400
   423
raj@3400
   424
  m_servsocket->SetAcceptCallback
raj@3400
   425
    (
raj@3400
   426
     MakeCallback (&TalkerApp::ConnectionRequested,this),
raj@3400
   427
     MakeCallback (&TalkerApp::ConnectionCreated,this)
raj@3400
   428
     );
raj@3400
   429
}
raj@3400
   430
 
raj@3400
   431
void
raj@3400
   432
TalkerApp::ConfRecv (Ptr<Node> node, const Address &addr)
raj@3400
   433
{
raj@3400
   434
  i_am_listener = 1;
raj@3400
   435
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   436
#ifdef PRINT_THIS                  
raj@3400
   437
                  << this
raj@3400
   438
#endif
raj@3400
   439
                  << node
raj@3400
   440
                  << addr
raj@3400
   441
                  );
raj@3400
   442
  m_local = addr;
raj@3400
   443
  node->AddApplication (this);
raj@3400
   444
}
raj@3400
   445
raj@3400
   446
void
raj@3400
   447
TalkerApp::ConfSend (Ptr<Node> node, const Address &addr)
raj@3400
   448
{
raj@3400
   449
  i_am_listener = 0;
raj@3400
   450
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   451
#ifdef PRINT_THIS                  
raj@3400
   452
                  << this
raj@3400
   453
#endif
raj@3400
   454
                  << node
raj@3400
   455
                  << addr
raj@3400
   456
                  );
raj@3400
   457
  m_remote = addr;
raj@3400
   458
  node->AddApplication (this);
raj@3400
   459
}
raj@3400
   460
raj@3400
   461
raj@3400
   462
void
raj@3400
   463
TalkerApp::SendPacket (std::string label,char fill,uint32_t payloadsize)
raj@3400
   464
{
raj@3400
   465
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   466
#ifdef PRINT_THIS                  
raj@3400
   467
                  << this
raj@3400
   468
#endif
raj@3400
   469
                  << label
raj@3400
   470
                  << fill
raj@3400
   471
                  << payloadsize
raj@3400
   472
                  );
raj@3400
   473
raj@3400
   474
#if 0
raj@3400
   475
  Ptr<Packet> p = Create<Packet> (payloadsize); // zero byte filled packet.
raj@3400
   476
#else
raj@3400
   477
  uint8_t *buf = (uint8_t *) malloc(payloadsize*sizeof(uint8_t));
raj@3400
   478
  memset(buf,fill,payloadsize);
raj@3400
   479
  Ptr<Packet> p = Create<Packet> (buf,payloadsize); // filled packet.
raj@3400
   480
  free(buf);
raj@3400
   481
#endif
raj@3400
   482
  if (verbose) {
raj@3400
   483
    p->Print (fileOut << "Before Marking|");
raj@3400
   484
    fileOut << std::endl;
raj@3400
   485
  }
raj@3400
   486
raj@3400
   487
  ArchHeader hdr;
raj@3400
   488
  hdr.SetStrValue (label);
raj@3400
   489
  hdr.SetIntValue (p->GetSize());
raj@3400
   490
  p->AddHeader (hdr);
raj@3400
   491
  if (verbose) {
raj@3400
   492
    p->Print(fileOut << "After Header Marking|");
raj@3400
   493
    fileOut << std::endl;
raj@3400
   494
  }
raj@3400
   495
raj@3400
   496
  m_socket->Send (p);
raj@3400
   497
}
raj@3400
   498
raj@3400
   499
void
raj@3400
   500
TalkerApp::StopApplication ()
raj@3400
   501
{
raj@3400
   502
  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
raj@3400
   503
#ifdef PRINT_THIS                  
raj@3400
   504
                  << this
raj@3400
   505
#endif
raj@3400
   506
                  );
raj@3400
   507
  if (m_socket)
raj@3400
   508
    m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
raj@3400
   509
}
raj@3400
   510
raj@3400
   511
void
raj@3400
   512
TalkerApp::HandleRead (Ptr<Socket> socket)
raj@3400
   513
{
raj@3400
   514
  left_to_read_iterator_type iter = m_left_to_read.find (socket);
raj@3400
   515
  if (iter == m_left_to_read.end ())
raj@3400
   516
    m_left_to_read[socket] = 0;
raj@3400
   517
raj@3400
   518
  std::ostringstream  pretty;
raj@3400
   519
  pretty << (i_am_listener ? "Server" : "Client")
raj@3400
   520
         << (iter == m_left_to_read.end () ? 
raj@3400
   521
             "(new)" : "(old)")
raj@3400
   522
         << "|";
raj@3400
   523
raj@3400
   524
  NS_LOG_FUNCTION ( pretty.str ()
raj@3400
   525
#ifdef PRINT_THIS                  
raj@3400
   526
                  << this
raj@3400
   527
#endif
raj@3400
   528
                  << socket
raj@3400
   529
                  );
raj@3400
   530
  /*
raj@3400
   531
   * NOTE: I can crash with the # bytes == 500 rather than 536
raj@3400
   532
   * which seems to be the default MTU
raj@3400
   533
   */
raj@3400
   534
raj@3400
   535
#ifdef TOO_SMALL_BUG
raj@3400
   536
  const uint32_t number_of_bytes_willing_to_read = 500;
raj@3400
   537
#else
raj@3400
   538
  const uint32_t number_of_bytes_willing_to_read = 536;
raj@3400
   539
#endif
raj@3400
   540
  const uint32_t unused_flags = 0;
raj@3400
   541
raj@3400
   542
  Ptr<Packet> packet;
raj@3400
   543
  while (packet = socket->Recv (number_of_bytes_willing_to_read,
raj@3400
   544
                                unused_flags) ){
raj@3400
   545
    std::string raw_rle = rle(packet->PeekData(),
raj@3400
   546
                              packet->GetSize());
raj@3400
   547
    SocketAddressTag rx_addr_tag;
raj@3400
   548
    bool found;
raj@3400
   549
    found = packet->FindFirstMatchingTag (rx_addr_tag);
raj@3400
   550
    NS_ASSERT (found);
raj@3400
   551
    Address from = rx_addr_tag.GetAddress ();
raj@3400
   552
    // XXX packet->RemoveTag (tag);
raj@3400
   553
    if (InetSocketAddress::IsMatchingType (from)) {
raj@3400
   554
      InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
raj@3400
   555
raj@3400
   556
#ifdef VERBOSE_TESTING
raj@3400
   557
      packet->Print (fileOut << "Packet Dump: ");
raj@3400
   558
      fileOut << std::endl;
raj@3400
   559
#endif
raj@3400
   560
raj@3400
   561
raj@3400
   562
      bool freshly_in_the_loop = true;
raj@3400
   563
      do {
raj@3400
   564
#if defined(RECV_PRINT)
raj@3400
   565
        fileOut
raj@3400
   566
          << raw_rle // <length>:<rle of packet->PeekBuffer>
raj@3400
   567
          << (freshly_in_the_loop ? " *" : "  ") /* used to see if the do while
raj@3400
   568
                                                  * does anything */
raj@3400
   569
          << "bytes from "
raj@3400
   570
          << address.GetIpv4 () << " [" << address << "] ";
raj@3400
   571
#endif
raj@3400
   572
        freshly_in_the_loop = false;
raj@3400
   573
        int header_bytes = 0;
raj@3400
   574
        ArchHeader* hdr =  0; // sadly, can't be a Ptr<>
raj@3400
   575
        if (
raj@3400
   576
            (m_left_to_read[socket] == 0)
raj@3400
   577
            ) {
raj@3400
   578
          hdr =  new ArchHeader;
raj@3400
   579
          if (packet->RemoveHeader (*hdr)) {
raj@3400
   580
            m_left_to_read[socket] = hdr->GetIntValue ();
raj@3400
   581
            header_bytes = hdr->GetSerializedSize ();
raj@3400
   582
          } else {
raj@3400
   583
            ; // never get here, ns3 dumps if no header is there.
raj@3400
   584
          }
raj@3400
   585
        }
raj@3400
   586
        uint32_t num_bytes_processed = 0;
raj@3400
   587
        if (m_left_to_read[socket] <= packet->GetSize ()) {
raj@3400
   588
          packet->RemoveAtStart (m_left_to_read[socket]);
raj@3400
   589
          num_bytes_processed = m_left_to_read[socket];
raj@3400
   590
          m_left_to_read[socket] = 0;
raj@3400
   591
raj@3400
   592
        } else {
raj@3400
   593
          m_left_to_read[socket] -= packet->GetSize ();
raj@3400
   594
          num_bytes_processed = packet->GetSize ();
raj@3400
   595
          packet->RemoveAtStart (packet->GetSize ());
raj@3400
   596
        }
raj@3400
   597
raj@3400
   598
#if defined(RECV_PRINT)
raj@3400
   599
        fileOut
raj@3400
   600
          << "<"
raj@3400
   601
          << packet->GetSize ()
raj@3400
   602
          << "|"
raj@3400
   603
          <<  num_bytes_processed
raj@3400
   604
          ;
raj@3400
   605
        if (header_bytes)
raj@3400
   606
          fileOut
raj@3400
   607
            << "("
raj@3400
   608
            << header_bytes
raj@3400
   609
            << ")"
raj@3400
   610
            ;
raj@3400
   611
        fileOut
raj@3400
   612
          << "|"
raj@3400
   613
          << m_left_to_read[socket]
raj@3400
   614
          << ">";
raj@3400
   615
#ifdef VERBOSE_TESTING
raj@3400
   616
        if (hdr)
raj@3400
   617
          hdr->Print(fileOut << " ");
raj@3400
   618
#endif
raj@3400
   619
        fileOut << std::endl;
raj@3400
   620
#endif
raj@3400
   621
        if (hdr)
raj@3400
   622
          delete hdr; // free what we new....
raj@3400
   623
      } while (
raj@3400
   624
               packet->GetSize ()
raj@3400
   625
               );
raj@3400
   626
    } else {
raj@3400
   627
      fileOut << "not a match in HandleRead" << std::endl;
raj@3400
   628
    }
raj@3400
   629
raj@3400
   630
  }
raj@3400
   631
}
raj@3400
   632
raj@3400
   633
//---------------Non-member functions-------------------------------------------
raj@3400
   634
/*
raj@3400
   635
 * returns a string containing the length of the buffer,
raj@3400
   636
 * followed by an run length encoded version of the buffer
raj@3400
   637
 * un-printables are represented by '.' (i.e. special_marker
raj@3400
   638
 * const).
raj@3400
   639
 */
raj@3400
   640
std::string rle(const uint8_t *buf, int buflen) {
raj@3400
   641
raj@3400
   642
  int justify = 5;
raj@3400
   643
  std::ostringstream o;
raj@3400
   644
  const uint8_t min_rep = 3;
raj@3400
   645
  uint8_t cur_char = 0;
raj@3400
   646
  const uint8_t special_marker = '.';
raj@3400
   647
  int cur_cnt = 0;
raj@3400
   648
  if (justify) {
raj@3400
   649
    o << std::setw(justify) << std::right << buflen << ":";
raj@3400
   650
  } else {
raj@3400
   651
    o << buflen << ":";
raj@3400
   652
  }
raj@3400
   653
raj@3400
   654
  for (int i = 0; i < buflen; i++) {
raj@3400
   655
    if (
raj@3400
   656
        (!isprint(buf[i]) && cur_char == special_marker) ||
raj@3400
   657
        (buf[i] == cur_char)
raj@3400
   658
        )
raj@3400
   659
      cur_cnt++;
raj@3400
   660
    else {
raj@3400
   661
      if (cur_cnt >= min_rep)
raj@3400
   662
        o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
raj@3400
   663
          << cur_cnt << "}";
raj@3400
   664
      else
raj@3400
   665
        for (int irep=0; irep < cur_cnt; irep++)
raj@3400
   666
          o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
raj@3400
   667
      if (isprint(buf[i]))
raj@3400
   668
        cur_char = buf[i];
raj@3400
   669
      else
raj@3400
   670
        cur_char = special_marker;
raj@3400
   671
      cur_cnt = 1;
raj@3400
   672
    }
raj@3400
   673
  }
raj@3400
   674
  if (cur_cnt >= min_rep)
raj@3400
   675
    o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
raj@3400
   676
      << cur_cnt << "}";
raj@3400
   677
  else
raj@3400
   678
    for (int irep=0; irep < cur_cnt; irep++)
raj@3400
   679
      o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
raj@3400
   680
  return o.str();
raj@3400
   681
}
raj@3400
   682
raj@3400
   683
//---------------Main-----------------------------------------------------------
raj@3400
   684
int
raj@3400
   685
main (int argc, char *argv[]) {
raj@3400
   686
raj@3400
   687
  std::clog.rdbuf (fileOut.rdbuf ()); /* till we can do this in ns3::log
raj@3400
   688
                                         * without this ns3 logging messages
raj@3400
   689
                                         * are far away from normal output
raj@3400
   690
                                         */
raj@3400
   691
raj@3400
   692
#ifdef VERBOSE_TESTING  
raj@3400
   693
  LogComponentEnable ("tcp-2way",LOG_LEVEL_ALL);
raj@3400
   694
#endif
raj@3400
   695
raj@3400
   696
  RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
raj@3400
   697
  Packet::EnableMetadata ();
raj@3400
   698
raj@3400
   699
  // boilerplate:  "c0[0]" is Tx, "c0[1]" is Rx.
raj@3400
   700
  NodeContainer c0;
raj@3400
   701
  c0.Create (2);
raj@3400
   702
raj@3400
   703
  // We create the channels first without any IP addressing information
raj@3400
   704
  PointToPointHelper p2p;
raj@3400
   705
  p2p.SetDeviceAttribute ("DataRate",DataRateValue (DataRate (10000000)));
raj@3400
   706
  p2p.SetChannelAttribute ("Delay",TimeValue (MilliSeconds (10)));
raj@3400
   707
  NetDeviceContainer dev0 = p2p.Install (c0);
raj@3400
   708
raj@3400
   709
  // add ip/tcp stack to nodes.
raj@3400
   710
  InternetStackHelper internet;
raj@3400
   711
  internet.Install (c0);
raj@3400
   712
raj@3400
   713
  // Later, we add IP addresses.  
raj@3400
   714
  Ipv4AddressHelper ipv4;
raj@3400
   715
  ipv4.SetBase ("10.1.0.0", "255.255.255.0");
raj@3400
   716
  Ipv4InterfaceContainer ifaces = ipv4.Assign (dev0);
raj@3400
   717
raj@3400
   718
  // Configure the apps.
raj@3400
   719
  uint16_t servPort = 32;
raj@3400
   720
raj@3400
   721
raj@3400
   722
  // setup Rx side using ns3::Node "c0[1]" to listen for ANY:servPort
raj@3400
   723
  Ptr<TalkerApp> sink = CreateObject<TalkerApp_sub>();
raj@3400
   724
  sink->ConfRecv (c0.Get (1),
raj@3400
   725
		InetSocketAddress (Ipv4Address::GetAny (), servPort));
raj@3400
   726
  sink->Start (Seconds (0.0)); // somehow we get by without a Stop. bad form?
raj@3400
   727
raj@3400
   728
  // setup Tx side using ns3::Node "c0[0]" to talk to "c0[1]":servPort
raj@3400
   729
  Ptr<TalkerApp>  source = CreateObject<TalkerApp_sub>();
raj@3400
   730
  source->ConfSend (c0.Get (0),
raj@3400
   731
                  InetSocketAddress (ifaces.GetAddress (1),
raj@3400
   732
                                     servPort));
raj@3400
   733
  source->Start (Seconds (0.0));
raj@3400
   734
raj@3400
   735
  // 10 sec is an eternity for this case, we should be done by then.
raj@3400
   736
  Simulator::Stop (Seconds (10));
raj@3400
   737
raj@3400
   738
raj@3400
   739
  // For regression use only output ascii and pcap traces.
raj@3400
   740
#ifdef REGRESSION_MODE
raj@3400
   741
  std::ofstream ascii;
raj@3400
   742
  ascii.open ("tcp-2way.tr");
raj@3400
   743
  PointToPointHelper::EnableAsciiAll (ascii);
raj@3400
   744
  PointToPointHelper::EnablePcapAll ("tcp-2way");
raj@3400
   745
#endif
raj@3400
   746
raj@3400
   747
  /*
raj@3400
   748
   * Now lets schedule some packets and go. For scheduling packets
raj@3400
   749
   * we have to be careful not to do the backchannel too early or
raj@3400
   750
   * we try to use a socket that doesn't yet exist since on the Rx
raj@3400
   751
   * side the socket is created as part of the normal Tx->Rx connection
raj@3400
   752
   * setup.
raj@3400
   753
   *
raj@3400
   754
   * The delay of 40ms was by trial and error and seems good enough. It
raj@3400
   755
   * would be nice to know what the bounds are and why....
raj@3400
   756
   */
raj@3400
   757
raj@3400
   758
  char tagchar = 'A'; // the fill character in case we fill in SendPacket.
raj@3400
   759
raj@3400
   760
  Time d2t = MilliSeconds(40); /* rate to change time offset (dt) so packets
raj@3400
   761
                                * are sent in order (Tx->Rx, Rx->Tx for a given
raj@3400
   762
                                * size over a range of sizes).*/
raj@3400
   763
raj@3400
   764
  Time dt = MilliSeconds(0); /* ns3 doesn't take absolute times, but times
raj@3400
   765
                              * relative to Simulator::Now() */
raj@3400
   766
raj@3400
   767
  uint32_t size = 0;
raj@3400
   768
  source->ScheduleSendPacket (dt, tagchar, size);
raj@3400
   769
  dt += d2t;
raj@3400
   770
  ++tagchar;
raj@3400
   771
  sink->ScheduleSendPacket (dt, tagchar, size);
raj@3400
   772
  for (size = 1; size <= 1000000; size *= 10) {
raj@3400
   773
    dt += d2t;
raj@3400
   774
    ++tagchar;
raj@3400
   775
    source->ScheduleSendPacket (dt, tagchar, size);
raj@3400
   776
    dt += d2t;
raj@3400
   777
    ++tagchar;
raj@3400
   778
    sink->ScheduleSendPacket (dt, tagchar, size);
raj@3400
   779
  }
raj@3400
   780
raj@3400
   781
  // Release the Hounds!!
raj@3400
   782
  Simulator::Run ();
raj@3400
   783
  Simulator::Destroy ();
raj@3400
   784
  fileOut.close();
raj@3400
   785
}