Add David Evensky's tcp-2way regression test
authorRaj Bhattacharjea <raj.b@gatech.edu>
Wed Jul 09 17:04:29 2008 -0400 (2008-07-09)
changeset 3400fd69b15002ee
parent 3399 5782cdf815e1
child 3401 52b0ae2057a6
Add David Evensky's tcp-2way regression test
examples/tcp-2way.cc
examples/wscript
regression/tests/test-tcp-2way.py
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/examples/tcp-2way.cc	Wed Jul 09 17:04:29 2008 -0400
     1.3 @@ -0,0 +1,785 @@
     1.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     1.5 +/*
     1.6 + * Copyright 2007 University of Washington
     1.7 + * Copyright 2007 Georgia Tech Research Corporation
     1.8 + * Copyright 2008 Sandia Corporation
     1.9 + *
    1.10 + * This program is free software; you can redistribute it and/or modify
    1.11 + * it under the terms of the GNU General Public License version 2 as
    1.12 + * published by the Free Software Foundation;
    1.13 + *
    1.14 + * This program is distributed in the hope that it will be useful,
    1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 + * GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License
    1.20 + * along with this program; if not, write to the Free Software
    1.21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.22 + *
    1.23 + *
    1.24 + * Sandia is a multiprogram laboratory operated by Sandia
    1.25 + * Corporation, a Lockheed Martin Company, for the United States
    1.26 + * Department of Energy's National Nuclear Security Administration
    1.27 + * under Contract DE-AC04-94AL85000.
    1.28 + *
    1.29 + * Author: David Evensky, Sandia National Labs
    1.30 + *
    1.31 + * includes GPL'ed ns-3-dev code from:
    1.32 + *   udp-echo,          // ??, (c) U. Wash. 2007
    1.33 + *   tcp-large-transfer // ??
    1.34 + *   packet-sink        // Tom Henderson, (c) U. Wash. 2007
    1.35 + *   onoff              // George F. Riley, (c) GT Res Corp. 2007
    1.36 + */
    1.37 +
    1.38 +
    1.39 +/* NOTE
    1.40 +This isn't really an example file, so don't look to closely at it as a starting
    1.41 +script.  It is here for validation of the TCP model.
    1.42 +*/
    1.43 +
    1.44 +#include <iostream>
    1.45 +#include <fstream>
    1.46 +#include <sstream>
    1.47 +#include <string>
    1.48 +#include <iomanip>
    1.49 +#include <map>
    1.50 +
    1.51 +#include "ns3/core-module.h"
    1.52 +#include "ns3/helper-module.h"
    1.53 +#include "ns3/node-module.h"
    1.54 +#include "ns3/global-route-manager.h"
    1.55 +#include "ns3/simulator-module.h"
    1.56 +#include "ns3/log.h"
    1.57 +
    1.58 +using namespace ns3;
    1.59 +
    1.60 +NS_LOG_COMPONENT_DEFINE ("tcp-2way");
    1.61 +
    1.62 +//----------defines-------------------------------------------------------------
    1.63 +//define to print more debugging info.
    1.64 +#define VERBOSE_TESTING
    1.65 +
    1.66 +/* define to die because Socket::Recv() is told to
    1.67 + * only read an "undesired" number of bytes
    1.68 + * fails NS_ASSERT in HandleRead because rx_addr_tag
    1.69 + * tag isn't there.
    1.70 + */
    1.71 +//#define TOO_SMALL_BUG
    1.72 +
    1.73 +//define to print this pointer in NS_LOG_FUNCTION
    1.74 +//#define PRINT_THIS
    1.75 +
    1.76 +/*define to print packet info in HandleRead
    1.77 + *expected output is of the form:
    1.78 + *536:P{536} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00] <0|536|884018>
    1.79 + * ^  ^      ^              ^             ^                  ^   ^ ^
    1.80 + * |  |      |              |             |                  |   | |
    1.81 + * |  |      |              |             |                  |   | +bytes left
    1.82 + * |  |      |              |             |                  |   |  to read in
    1.83 + * |  |      |              |             |                  |   |  sent buffer
    1.84 + * |  |      |              |             |                  |   +bytes read in
    1.85 + * |  |      |              |             |                  |    this packet if
    1.86 + * |  |      |              |             |                  |    header read,
    1.87 + * |  |      |              |             |                  |    prints size
    1.88 + * |  |      |              |             |                  |    in ()
    1.89 + * |  |      |              |             |                  +bytes cur. packet
    1.90 + * |  |      |              |             |                   left to process
    1.91 + * |  |      |              |             +mac addr of sender
    1.92 + * |  |      |              +IP addr of sender
    1.93 + * |  |      +print '*' while processing first chunk in a received packet.
    1.94 + * |  |       if there are multiple small sent packets, these can appear in
    1.95 + * |  |       a single packet, and are processed by a do {} while() loop.
    1.96 + * |  +rle output of packet::PeekData(), in this case filled with 536 bytes
    1.97 + * |   filled with the letter 'P' (brought to you by the letter 'Q' and the
    1.98 + * |   number '9' :-))
    1.99 + * + packet::GetSize()
   1.100 + *
   1.101 + * If there is a header it will look more like:
   1.102 + * 536:N{317}@B.{6}HELLOP{206} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
   1.103 + *                                                                   <219|317|0>
   1.104 + * 536:N{317}@B.{6}HELLOP{206}  bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
   1.105 + *                               <0|206(13)|999794> (ArchHeader=HELLO:1000000)
   1.106 + * where you can see that this first packet includes 317 bytes from the
   1.107 + * previous send packet (filled with N) and 13 bytes of header before the 206
   1.108 + * bytes of payload (filled with P).
   1.109 + */
   1.110 +
   1.111 +#define RECV_PRINT
   1.112 +
   1.113 +// dcl non-method functions....
   1.114 +std::string rle(const uint8_t *, int );
   1.115 +std::ofstream fileOut("tcp-2way.out");
   1.116 +
   1.117 +//----------class ArchHeader dcl and definition---------------------------------
   1.118 +/*
   1.119 + * ArchHeader: A toy header that holds a string
   1.120 + * and a uint32_t. The string is an abitrary label
   1.121 + * and the int is used as the length of the payload.
   1.122 + */
   1.123 +
   1.124 +class ArchHeader : public Header {
   1.125 +public:
   1.126 +  virtual uint32_t  GetSerializedSize (void) const;
   1.127 +  virtual void      Serialize (Buffer::Iterator) const;
   1.128 +  virtual uint32_t  Deserialize (Buffer::Iterator);
   1.129 +  virtual void      Print (std::ostream &) const;
   1.130 +  static  TypeId    GetTypeId (void);
   1.131 +  virtual TypeId    GetInstanceTypeId (void) const;
   1.132 +
   1.133 +  // accessor functions.....
   1.134 +  void        SetIntValue (uint32_t);
   1.135 +  uint32_t    GetIntValue (void) const;
   1.136 +  void        SetStrValue (const std::string &s);
   1.137 +  std::string GetStrValue (void) const;
   1.138 +private:
   1.139 +  uint32_t          int_value;
   1.140 +  std::string       str_value;
   1.141 +};
   1.142 +
   1.143 +
   1.144 +TypeId
   1.145 +ArchHeader::GetTypeId (void)
   1.146 +{
   1.147 +  static TypeId tid = TypeId ("ns3::ArchHeader")
   1.148 +    .AddConstructor<ArchHeader> () // NOTE: Required for ????
   1.149 +    .SetParent<Header> ()          // ditto
   1.150 +    ;
   1.151 +  return tid;
   1.152 +}
   1.153 +
   1.154 +TypeId
   1.155 +ArchHeader::GetInstanceTypeId (void) const
   1.156 +{
   1.157 +  return GetTypeId ();
   1.158 +}
   1.159 +
   1.160 +uint32_t
   1.161 +ArchHeader::GetSerializedSize (void) const
   1.162 +{
   1.163 +  return 2*sizeof (uint32_t) + str_value.size (); // int, str len & bytes
   1.164 +}
   1.165 +
   1.166 +void
   1.167 +ArchHeader::Serialize (Buffer::Iterator i) const
   1.168 +{
   1.169 +  i.WriteU32 (int_value);
   1.170 +  uint32_t str_len = str_value.size ();
   1.171 +  i.WriteU32 (str_len);
   1.172 +  for (uint32_t j = 0; j < str_value.size (); j++)
   1.173 +    i.WriteU8 (str_value[j]);
   1.174 +}
   1.175 +  
   1.176 +uint32_t
   1.177 +ArchHeader::Deserialize (Buffer::Iterator i)
   1.178 +{
   1.179 +  int_value = i.ReadU32 ();
   1.180 +  uint32_t str_len = i.ReadU32 ();
   1.181 +  str_value.reserve (str_len);
   1.182 +  for (uint32_t j = 0; j < str_len; j++) {
   1.183 +    char v = i.ReadU8 ();
   1.184 +    str_value.push_back (v);
   1.185 +  }
   1.186 +  return 2*sizeof (uint32_t) + str_value.size ();
   1.187 +}
   1.188 +
   1.189 +
   1.190 +void
   1.191 +ArchHeader::SetIntValue (uint32_t v_)
   1.192 +{
   1.193 +  int_value = v_;
   1.194 +}
   1.195 +
   1.196 +uint32_t
   1.197 +ArchHeader::GetIntValue (void) const
   1.198 +{
   1.199 +  return int_value;
   1.200 +}
   1.201 +
   1.202 +void
   1.203 +ArchHeader::SetStrValue (const std::string &s)
   1.204 +{
   1.205 +  str_value = s;
   1.206 +}
   1.207 +
   1.208 +std::string
   1.209 +ArchHeader::GetStrValue (void) const
   1.210 +{
   1.211 +  return str_value;
   1.212 +}
   1.213 +   
   1.214 +void
   1.215 +ArchHeader::Print (std::ostream &os) const
   1.216 +{
   1.217 +  os << "(ArchHeader=" << str_value << ":" << int_value << ")";
   1.218 +}
   1.219 +
   1.220 +//----------class TalkerApp dcl and definition----------------------------------
   1.221 +/*
   1.222 + * TalkerApp:
   1.223 + * An an Application that can serve as both Rx and Tx side.
   1.224 + * and is configured by ConfRecv/ConfSend and driven by
   1.225 + * ScheduleSendPacket. Becareful not to try to send a packet
   1.226 + * from the Rx side to the Tx side (back channel) before the
   1.227 + * connection is setup, which has to be from the Tx to the Rx
   1.228 + * (the forward channel).
   1.229 + */
   1.230 +
   1.231 +class TalkerApp : public Application {
   1.232 +public:
   1.233 +  TalkerApp ();
   1.234 +  virtual ~TalkerApp ();
   1.235 +  void ConfRecv (Ptr<Node>,const Address &);
   1.236 +  void ConfSend (Ptr<Node>,const Address &);
   1.237 +  void ScheduleSendPacket(const Time ,const char , const uint32_t size );
   1.238 +
   1.239 +protected:
   1.240 +  virtual void DoDispose (void);
   1.241 +private:
   1.242 +  virtual void StartApplication (void);
   1.243 +  virtual void StopApplication (void);
   1.244 +
   1.245 +  void StartApplicationRecv (void);
   1.246 +  void StartApplicationSend (void);
   1.247 +
   1.248 +  void HandleRead (Ptr<Socket>);
   1.249 +  void SendPacket (std::string,char,uint32_t);
   1.250 +
   1.251 +  void CloseConnection (Ptr<Socket> socket);
   1.252 +  void ConnectionSucceeded (Ptr<Socket>);
   1.253 +  void ConnectionFailed (Ptr<Socket>);
   1.254 +  bool ConnectionRequested (Ptr<Socket>, const Address &);
   1.255 +  void ConnectionCreated (Ptr<Socket>, const Address &);
   1.256 +
   1.257 +
   1.258 +  bool            verbose;
   1.259 +  Ptr<Socket>     m_socket;
   1.260 +  Ptr<Socket>     m_servsocket;
   1.261 +  Address         m_local;
   1.262 +  Address         m_remote;
   1.263 +  int             i_am_listener;
   1.264 +  typedef std::map<Ptr<Socket>, uint32_t>::iterator left_to_read_iterator_type;
   1.265 +  std::map<Ptr<Socket>, uint32_t> m_left_to_read;
   1.266 +};
   1.267 +
   1.268 +class TalkerApp_sub : public TalkerApp {
   1.269 +public:
   1.270 +  int foo(void);
   1.271 +};
   1.272 +
   1.273 +int
   1.274 +TalkerApp_sub::foo(void) {return 0;}
   1.275 +
   1.276 +TalkerApp::TalkerApp () :
   1.277 +  verbose (false),
   1.278 +  m_socket (0),
   1.279 +  m_servsocket (0),
   1.280 +  i_am_listener (0)
   1.281 +{}
   1.282 +
   1.283 +TalkerApp::~TalkerApp ()
   1.284 +{}
   1.285 +
   1.286 +void
   1.287 +TalkerApp::DoDispose (void)
   1.288 +{
   1.289 +  m_socket = 0;
   1.290 +  m_servsocket = 0;
   1.291 +  Application::DoDispose ();
   1.292 +}
   1.293 +
   1.294 +
   1.295 +void
   1.296 +TalkerApp::CloseConnection (Ptr<Socket> sock)
   1.297 +{
   1.298 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.299 +#ifdef PRINT_THIS                  
   1.300 +                  << this
   1.301 +#endif
   1.302 +                  << sock
   1.303 +                  );
   1.304 +  sock->Close ();
   1.305 +}
   1.306 +
   1.307 +void
   1.308 +TalkerApp::ConnectionSucceeded (Ptr<Socket> sock)
   1.309 +{
   1.310 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.311 +#ifdef PRINT_THIS                  
   1.312 +                  << this
   1.313 +#endif
   1.314 +                  << sock
   1.315 +	
   1.316 +		   );
   1.317 +}
   1.318 +
   1.319 +void
   1.320 +TalkerApp::ConnectionFailed (Ptr<Socket> sock)
   1.321 +{
   1.322 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.323 +#ifdef PRINT_THIS                  
   1.324 +                  << this
   1.325 +#endif
   1.326 +                  << sock
   1.327 +                  );
   1.328 +}
   1.329 +
   1.330 +bool
   1.331 +TalkerApp::ConnectionRequested (Ptr<Socket> sock, const Address &addr)
   1.332 +{
   1.333 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.334 +#ifdef PRINT_THIS                  
   1.335 +                  << this
   1.336 +#endif
   1.337 +                  << sock
   1.338 +                  << addr
   1.339 +                  );
   1.340 +  return true;
   1.341 +}
   1.342 +
   1.343 +void
   1.344 +TalkerApp::ConnectionCreated (Ptr<Socket> sock, const Address &addr)
   1.345 +{
   1.346 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.347 +#ifdef PRINT_THIS                  
   1.348 +                  << this
   1.349 +#endif
   1.350 +                  << sock
   1.351 +                  << addr
   1.352 +                  );
   1.353 +  m_socket = sock;
   1.354 +  m_socket->SetRecvCallback(MakeCallback (&TalkerApp::HandleRead, this));
   1.355 +}
   1.356 +
   1.357 +void 
   1.358 +TalkerApp::ScheduleSendPacket (const Time dt,const char fill,
   1.359 +                               const uint32_t size)
   1.360 +{
   1.361 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.362 +#ifdef PRINT_THIS                  
   1.363 +                  << this
   1.364 +#endif
   1.365 +                   << dt
   1.366 +                   << fill
   1.367 +                   << size
   1.368 +                   );
   1.369 +  Simulator::Schedule(dt,&TalkerApp::SendPacket, this,
   1.370 +                      std::string("HELLO"),fill,size);
   1.371 +}
   1.372 +
   1.373 +
   1.374 +void
   1.375 +TalkerApp::StartApplication ()
   1.376 +{
   1.377 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.378 +#ifdef PRINT_THIS                  
   1.379 +                  << this
   1.380 +#endif
   1.381 +                  );
   1.382 +  if (i_am_listener)
   1.383 +    StartApplicationRecv ();
   1.384 +  else
   1.385 +    StartApplicationSend ();
   1.386 +}
   1.387 +
   1.388 +void
   1.389 +TalkerApp::StartApplicationSend ()
   1.390 +{
   1.391 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.392 +#ifdef PRINT_THIS                  
   1.393 +                  << this
   1.394 +#endif
   1.395 +                  );
   1.396 +
   1.397 +  if (!m_socket) {
   1.398 +    m_socket = Socket::CreateSocket (GetNode (),
   1.399 +				    TcpSocketFactory::GetTypeId ());
   1.400 +    m_socket->Bind ();
   1.401 +  }
   1.402 +
   1.403 +  m_socket->Connect (m_remote);
   1.404 +  m_socket->SetConnectCallback
   1.405 +    (
   1.406 +     MakeCallback (&TalkerApp::ConnectionSucceeded,this),
   1.407 +     MakeCallback (&TalkerApp::ConnectionFailed,this)
   1.408 +     );
   1.409 +  m_socket->SetRecvCallback (MakeCallback (&TalkerApp::HandleRead, this));
   1.410 +}
   1.411 +
   1.412 +void
   1.413 +TalkerApp::StartApplicationRecv ()
   1.414 +{
   1.415 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.416 +#ifdef PRINT_THIS                  
   1.417 +                  << this
   1.418 +#endif
   1.419 +                  );
   1.420 +  if (!m_servsocket) {
   1.421 +    m_servsocket = Socket::CreateSocket (GetNode (),
   1.422 +					TcpSocketFactory::GetTypeId ());
   1.423 +    m_servsocket->Bind (m_local);
   1.424 +    m_servsocket->Listen (0);
   1.425 +  }
   1.426 +
   1.427 +  m_servsocket->SetAcceptCallback
   1.428 +    (
   1.429 +     MakeCallback (&TalkerApp::ConnectionRequested,this),
   1.430 +     MakeCallback (&TalkerApp::ConnectionCreated,this)
   1.431 +     );
   1.432 +}
   1.433 + 
   1.434 +void
   1.435 +TalkerApp::ConfRecv (Ptr<Node> node, const Address &addr)
   1.436 +{
   1.437 +  i_am_listener = 1;
   1.438 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.439 +#ifdef PRINT_THIS                  
   1.440 +                  << this
   1.441 +#endif
   1.442 +                  << node
   1.443 +                  << addr
   1.444 +                  );
   1.445 +  m_local = addr;
   1.446 +  node->AddApplication (this);
   1.447 +}
   1.448 +
   1.449 +void
   1.450 +TalkerApp::ConfSend (Ptr<Node> node, const Address &addr)
   1.451 +{
   1.452 +  i_am_listener = 0;
   1.453 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.454 +#ifdef PRINT_THIS                  
   1.455 +                  << this
   1.456 +#endif
   1.457 +                  << node
   1.458 +                  << addr
   1.459 +                  );
   1.460 +  m_remote = addr;
   1.461 +  node->AddApplication (this);
   1.462 +}
   1.463 +
   1.464 +
   1.465 +void
   1.466 +TalkerApp::SendPacket (std::string label,char fill,uint32_t payloadsize)
   1.467 +{
   1.468 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.469 +#ifdef PRINT_THIS                  
   1.470 +                  << this
   1.471 +#endif
   1.472 +                  << label
   1.473 +                  << fill
   1.474 +                  << payloadsize
   1.475 +                  );
   1.476 +
   1.477 +#if 0
   1.478 +  Ptr<Packet> p = Create<Packet> (payloadsize); // zero byte filled packet.
   1.479 +#else
   1.480 +  uint8_t *buf = (uint8_t *) malloc(payloadsize*sizeof(uint8_t));
   1.481 +  memset(buf,fill,payloadsize);
   1.482 +  Ptr<Packet> p = Create<Packet> (buf,payloadsize); // filled packet.
   1.483 +  free(buf);
   1.484 +#endif
   1.485 +  if (verbose) {
   1.486 +    p->Print (fileOut << "Before Marking|");
   1.487 +    fileOut << std::endl;
   1.488 +  }
   1.489 +
   1.490 +  ArchHeader hdr;
   1.491 +  hdr.SetStrValue (label);
   1.492 +  hdr.SetIntValue (p->GetSize());
   1.493 +  p->AddHeader (hdr);
   1.494 +  if (verbose) {
   1.495 +    p->Print(fileOut << "After Header Marking|");
   1.496 +    fileOut << std::endl;
   1.497 +  }
   1.498 +
   1.499 +  m_socket->Send (p);
   1.500 +}
   1.501 +
   1.502 +void
   1.503 +TalkerApp::StopApplication ()
   1.504 +{
   1.505 +  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
   1.506 +#ifdef PRINT_THIS                  
   1.507 +                  << this
   1.508 +#endif
   1.509 +                  );
   1.510 +  if (m_socket)
   1.511 +    m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
   1.512 +}
   1.513 +
   1.514 +void
   1.515 +TalkerApp::HandleRead (Ptr<Socket> socket)
   1.516 +{
   1.517 +  left_to_read_iterator_type iter = m_left_to_read.find (socket);
   1.518 +  if (iter == m_left_to_read.end ())
   1.519 +    m_left_to_read[socket] = 0;
   1.520 +
   1.521 +  std::ostringstream  pretty;
   1.522 +  pretty << (i_am_listener ? "Server" : "Client")
   1.523 +         << (iter == m_left_to_read.end () ? 
   1.524 +             "(new)" : "(old)")
   1.525 +         << "|";
   1.526 +
   1.527 +  NS_LOG_FUNCTION ( pretty.str ()
   1.528 +#ifdef PRINT_THIS                  
   1.529 +                  << this
   1.530 +#endif
   1.531 +                  << socket
   1.532 +                  );
   1.533 +  /*
   1.534 +   * NOTE: I can crash with the # bytes == 500 rather than 536
   1.535 +   * which seems to be the default MTU
   1.536 +   */
   1.537 +
   1.538 +#ifdef TOO_SMALL_BUG
   1.539 +  const uint32_t number_of_bytes_willing_to_read = 500;
   1.540 +#else
   1.541 +  const uint32_t number_of_bytes_willing_to_read = 536;
   1.542 +#endif
   1.543 +  const uint32_t unused_flags = 0;
   1.544 +
   1.545 +  Ptr<Packet> packet;
   1.546 +  while (packet = socket->Recv (number_of_bytes_willing_to_read,
   1.547 +                                unused_flags) ){
   1.548 +    std::string raw_rle = rle(packet->PeekData(),
   1.549 +                              packet->GetSize());
   1.550 +    SocketAddressTag rx_addr_tag;
   1.551 +    bool found;
   1.552 +    found = packet->FindFirstMatchingTag (rx_addr_tag);
   1.553 +    NS_ASSERT (found);
   1.554 +    Address from = rx_addr_tag.GetAddress ();
   1.555 +    // XXX packet->RemoveTag (tag);
   1.556 +    if (InetSocketAddress::IsMatchingType (from)) {
   1.557 +      InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
   1.558 +
   1.559 +#ifdef VERBOSE_TESTING
   1.560 +      packet->Print (fileOut << "Packet Dump: ");
   1.561 +      fileOut << std::endl;
   1.562 +#endif
   1.563 +
   1.564 +
   1.565 +      bool freshly_in_the_loop = true;
   1.566 +      do {
   1.567 +#if defined(RECV_PRINT)
   1.568 +        fileOut
   1.569 +          << raw_rle // <length>:<rle of packet->PeekBuffer>
   1.570 +          << (freshly_in_the_loop ? " *" : "  ") /* used to see if the do while
   1.571 +                                                  * does anything */
   1.572 +          << "bytes from "
   1.573 +          << address.GetIpv4 () << " [" << address << "] ";
   1.574 +#endif
   1.575 +        freshly_in_the_loop = false;
   1.576 +        int header_bytes = 0;
   1.577 +        ArchHeader* hdr =  0; // sadly, can't be a Ptr<>
   1.578 +        if (
   1.579 +            (m_left_to_read[socket] == 0)
   1.580 +            ) {
   1.581 +          hdr =  new ArchHeader;
   1.582 +          if (packet->RemoveHeader (*hdr)) {
   1.583 +            m_left_to_read[socket] = hdr->GetIntValue ();
   1.584 +            header_bytes = hdr->GetSerializedSize ();
   1.585 +          } else {
   1.586 +            ; // never get here, ns3 dumps if no header is there.
   1.587 +          }
   1.588 +        }
   1.589 +        uint32_t num_bytes_processed = 0;
   1.590 +        if (m_left_to_read[socket] <= packet->GetSize ()) {
   1.591 +          packet->RemoveAtStart (m_left_to_read[socket]);
   1.592 +          num_bytes_processed = m_left_to_read[socket];
   1.593 +          m_left_to_read[socket] = 0;
   1.594 +
   1.595 +        } else {
   1.596 +          m_left_to_read[socket] -= packet->GetSize ();
   1.597 +          num_bytes_processed = packet->GetSize ();
   1.598 +          packet->RemoveAtStart (packet->GetSize ());
   1.599 +        }
   1.600 +
   1.601 +#if defined(RECV_PRINT)
   1.602 +        fileOut
   1.603 +          << "<"
   1.604 +          << packet->GetSize ()
   1.605 +          << "|"
   1.606 +          <<  num_bytes_processed
   1.607 +          ;
   1.608 +        if (header_bytes)
   1.609 +          fileOut
   1.610 +            << "("
   1.611 +            << header_bytes
   1.612 +            << ")"
   1.613 +            ;
   1.614 +        fileOut
   1.615 +          << "|"
   1.616 +          << m_left_to_read[socket]
   1.617 +          << ">";
   1.618 +#ifdef VERBOSE_TESTING
   1.619 +        if (hdr)
   1.620 +          hdr->Print(fileOut << " ");
   1.621 +#endif
   1.622 +        fileOut << std::endl;
   1.623 +#endif
   1.624 +        if (hdr)
   1.625 +          delete hdr; // free what we new....
   1.626 +      } while (
   1.627 +               packet->GetSize ()
   1.628 +               );
   1.629 +    } else {
   1.630 +      fileOut << "not a match in HandleRead" << std::endl;
   1.631 +    }
   1.632 +
   1.633 +  }
   1.634 +}
   1.635 +
   1.636 +//---------------Non-member functions-------------------------------------------
   1.637 +/*
   1.638 + * returns a string containing the length of the buffer,
   1.639 + * followed by an run length encoded version of the buffer
   1.640 + * un-printables are represented by '.' (i.e. special_marker
   1.641 + * const).
   1.642 + */
   1.643 +std::string rle(const uint8_t *buf, int buflen) {
   1.644 +
   1.645 +  int justify = 5;
   1.646 +  std::ostringstream o;
   1.647 +  const uint8_t min_rep = 3;
   1.648 +  uint8_t cur_char = 0;
   1.649 +  const uint8_t special_marker = '.';
   1.650 +  int cur_cnt = 0;
   1.651 +  if (justify) {
   1.652 +    o << std::setw(justify) << std::right << buflen << ":";
   1.653 +  } else {
   1.654 +    o << buflen << ":";
   1.655 +  }
   1.656 +
   1.657 +  for (int i = 0; i < buflen; i++) {
   1.658 +    if (
   1.659 +        (!isprint(buf[i]) && cur_char == special_marker) ||
   1.660 +        (buf[i] == cur_char)
   1.661 +        )
   1.662 +      cur_cnt++;
   1.663 +    else {
   1.664 +      if (cur_cnt >= min_rep)
   1.665 +        o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
   1.666 +          << cur_cnt << "}";
   1.667 +      else
   1.668 +        for (int irep=0; irep < cur_cnt; irep++)
   1.669 +          o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
   1.670 +      if (isprint(buf[i]))
   1.671 +        cur_char = buf[i];
   1.672 +      else
   1.673 +        cur_char = special_marker;
   1.674 +      cur_cnt = 1;
   1.675 +    }
   1.676 +  }
   1.677 +  if (cur_cnt >= min_rep)
   1.678 +    o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
   1.679 +      << cur_cnt << "}";
   1.680 +  else
   1.681 +    for (int irep=0; irep < cur_cnt; irep++)
   1.682 +      o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
   1.683 +  return o.str();
   1.684 +}
   1.685 +
   1.686 +//---------------Main-----------------------------------------------------------
   1.687 +int
   1.688 +main (int argc, char *argv[]) {
   1.689 +
   1.690 +  std::clog.rdbuf (fileOut.rdbuf ()); /* till we can do this in ns3::log
   1.691 +                                         * without this ns3 logging messages
   1.692 +                                         * are far away from normal output
   1.693 +                                         */
   1.694 +
   1.695 +#ifdef VERBOSE_TESTING  
   1.696 +  LogComponentEnable ("tcp-2way",LOG_LEVEL_ALL);
   1.697 +#endif
   1.698 +
   1.699 +  RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
   1.700 +  Packet::EnableMetadata ();
   1.701 +
   1.702 +  // boilerplate:  "c0[0]" is Tx, "c0[1]" is Rx.
   1.703 +  NodeContainer c0;
   1.704 +  c0.Create (2);
   1.705 +
   1.706 +  // We create the channels first without any IP addressing information
   1.707 +  PointToPointHelper p2p;
   1.708 +  p2p.SetDeviceAttribute ("DataRate",DataRateValue (DataRate (10000000)));
   1.709 +  p2p.SetChannelAttribute ("Delay",TimeValue (MilliSeconds (10)));
   1.710 +  NetDeviceContainer dev0 = p2p.Install (c0);
   1.711 +
   1.712 +  // add ip/tcp stack to nodes.
   1.713 +  InternetStackHelper internet;
   1.714 +  internet.Install (c0);
   1.715 +
   1.716 +  // Later, we add IP addresses.  
   1.717 +  Ipv4AddressHelper ipv4;
   1.718 +  ipv4.SetBase ("10.1.0.0", "255.255.255.0");
   1.719 +  Ipv4InterfaceContainer ifaces = ipv4.Assign (dev0);
   1.720 +
   1.721 +  // Configure the apps.
   1.722 +  uint16_t servPort = 32;
   1.723 +
   1.724 +
   1.725 +  // setup Rx side using ns3::Node "c0[1]" to listen for ANY:servPort
   1.726 +  Ptr<TalkerApp> sink = CreateObject<TalkerApp_sub>();
   1.727 +  sink->ConfRecv (c0.Get (1),
   1.728 +		InetSocketAddress (Ipv4Address::GetAny (), servPort));
   1.729 +  sink->Start (Seconds (0.0)); // somehow we get by without a Stop. bad form?
   1.730 +
   1.731 +  // setup Tx side using ns3::Node "c0[0]" to talk to "c0[1]":servPort
   1.732 +  Ptr<TalkerApp>  source = CreateObject<TalkerApp_sub>();
   1.733 +  source->ConfSend (c0.Get (0),
   1.734 +                  InetSocketAddress (ifaces.GetAddress (1),
   1.735 +                                     servPort));
   1.736 +  source->Start (Seconds (0.0));
   1.737 +
   1.738 +  // 10 sec is an eternity for this case, we should be done by then.
   1.739 +  Simulator::Stop (Seconds (10));
   1.740 +
   1.741 +
   1.742 +  // For regression use only output ascii and pcap traces.
   1.743 +#ifdef REGRESSION_MODE
   1.744 +  std::ofstream ascii;
   1.745 +  ascii.open ("tcp-2way.tr");
   1.746 +  PointToPointHelper::EnableAsciiAll (ascii);
   1.747 +  PointToPointHelper::EnablePcapAll ("tcp-2way");
   1.748 +#endif
   1.749 +
   1.750 +  /*
   1.751 +   * Now lets schedule some packets and go. For scheduling packets
   1.752 +   * we have to be careful not to do the backchannel too early or
   1.753 +   * we try to use a socket that doesn't yet exist since on the Rx
   1.754 +   * side the socket is created as part of the normal Tx->Rx connection
   1.755 +   * setup.
   1.756 +   *
   1.757 +   * The delay of 40ms was by trial and error and seems good enough. It
   1.758 +   * would be nice to know what the bounds are and why....
   1.759 +   */
   1.760 +
   1.761 +  char tagchar = 'A'; // the fill character in case we fill in SendPacket.
   1.762 +
   1.763 +  Time d2t = MilliSeconds(40); /* rate to change time offset (dt) so packets
   1.764 +                                * are sent in order (Tx->Rx, Rx->Tx for a given
   1.765 +                                * size over a range of sizes).*/
   1.766 +
   1.767 +  Time dt = MilliSeconds(0); /* ns3 doesn't take absolute times, but times
   1.768 +                              * relative to Simulator::Now() */
   1.769 +
   1.770 +  uint32_t size = 0;
   1.771 +  source->ScheduleSendPacket (dt, tagchar, size);
   1.772 +  dt += d2t;
   1.773 +  ++tagchar;
   1.774 +  sink->ScheduleSendPacket (dt, tagchar, size);
   1.775 +  for (size = 1; size <= 1000000; size *= 10) {
   1.776 +    dt += d2t;
   1.777 +    ++tagchar;
   1.778 +    source->ScheduleSendPacket (dt, tagchar, size);
   1.779 +    dt += d2t;
   1.780 +    ++tagchar;
   1.781 +    sink->ScheduleSendPacket (dt, tagchar, size);
   1.782 +  }
   1.783 +
   1.784 +  // Release the Hounds!!
   1.785 +  Simulator::Run ();
   1.786 +  Simulator::Destroy ();
   1.787 +  fileOut.close();
   1.788 +}
     2.1 --- a/examples/wscript	Wed Jul 09 14:10:18 2008 -0400
     2.2 +++ b/examples/wscript	Wed Jul 09 17:04:29 2008 -0400
     2.3 @@ -56,6 +56,10 @@
     2.4          ['point-to-point', 'internet-stack'])
     2.5      obj.source = 'tcp-errors.cc'
     2.6  
     2.7 +    obj = bld.create_ns3_program('tcp-2way',
     2.8 +      ['point-to-point', 'internet-stack'])
     2.9 +    obj.source = 'tcp-2way.cc'
    2.10 +
    2.11      obj = bld.create_ns3_program('tcp-star-server',
    2.12          ['point-to-point', 'internet-stack'])
    2.13      obj.source = 'tcp-star-server.cc'
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/regression/tests/test-tcp-2way.py	Wed Jul 09 17:04:29 2008 -0400
     3.3 @@ -0,0 +1,13 @@
     3.4 +#! /usr/bin/env python
     3.5 +
     3.6 +"""Generic trace-comparison-type regression test."""
     3.7 +
     3.8 +import os
     3.9 +import shutil
    3.10 +import tracediff
    3.11 +
    3.12 +def run(verbose, generate, refDirName):
    3.13 +    """Execute a test."""
    3.14 +
    3.15 +    return tracediff.run_test(verbose, generate, refDirName,
    3.16 +        "tcp-2way")