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