merge
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Fri, 11 Jul 2008 18:15:52 +0100
changeset 3415 5dd595cb7eba
parent 3414 48d69d8eac38 (current diff)
parent 3406 3efa652c47ef (diff)
child 3416 926ccb845111
merge
wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tcp-2way.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -0,0 +1,785 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 2007 University of Washington
+ * Copyright 2007 Georgia Tech Research Corporation
+ * Copyright 2008 Sandia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * Sandia is a multiprogram laboratory operated by Sandia
+ * Corporation, a Lockheed Martin Company, for the United States
+ * Department of Energy's National Nuclear Security Administration
+ * under Contract DE-AC04-94AL85000.
+ *
+ * Author: David Evensky, Sandia National Labs
+ *
+ * includes GPL'ed ns-3-dev code from:
+ *   udp-echo,          // ??, (c) U. Wash. 2007
+ *   tcp-large-transfer // ??
+ *   packet-sink        // Tom Henderson, (c) U. Wash. 2007
+ *   onoff              // George F. Riley, (c) GT Res Corp. 2007
+ */
+
+
+/* NOTE
+This isn't really an example file, so don't look to closely at it as a starting
+script.  It is here for validation of the TCP model.
+*/
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <iomanip>
+#include <map>
+
+#include "ns3/core-module.h"
+#include "ns3/helper-module.h"
+#include "ns3/node-module.h"
+#include "ns3/global-route-manager.h"
+#include "ns3/simulator-module.h"
+#include "ns3/log.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("tcp-2way");
+
+//----------defines-------------------------------------------------------------
+//define to print more debugging info.
+#define VERBOSE_TESTING
+
+/* define to die because Socket::Recv() is told to
+ * only read an "undesired" number of bytes
+ * fails NS_ASSERT in HandleRead because rx_addr_tag
+ * tag isn't there.
+ */
+//#define TOO_SMALL_BUG
+
+//define to print this pointer in NS_LOG_FUNCTION
+//#define PRINT_THIS
+
+/*define to print packet info in HandleRead
+ *expected output is of the form:
+ *536:P{536} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00] <0|536|884018>
+ * ^  ^      ^              ^             ^                  ^   ^ ^
+ * |  |      |              |             |                  |   | |
+ * |  |      |              |             |                  |   | +bytes left
+ * |  |      |              |             |                  |   |  to read in
+ * |  |      |              |             |                  |   |  sent buffer
+ * |  |      |              |             |                  |   +bytes read in
+ * |  |      |              |             |                  |    this packet if
+ * |  |      |              |             |                  |    header read,
+ * |  |      |              |             |                  |    prints size
+ * |  |      |              |             |                  |    in ()
+ * |  |      |              |             |                  +bytes cur. packet
+ * |  |      |              |             |                   left to process
+ * |  |      |              |             +mac addr of sender
+ * |  |      |              +IP addr of sender
+ * |  |      +print '*' while processing first chunk in a received packet.
+ * |  |       if there are multiple small sent packets, these can appear in
+ * |  |       a single packet, and are processed by a do {} while() loop.
+ * |  +rle output of packet::PeekData(), in this case filled with 536 bytes
+ * |   filled with the letter 'P' (brought to you by the letter 'Q' and the
+ * |   number '9' :-))
+ * + packet::GetSize()
+ *
+ * If there is a header it will look more like:
+ * 536:N{317}@B.{6}HELLOP{206} *bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
+ *                                                                   <219|317|0>
+ * 536:N{317}@B.{6}HELLOP{206}  bytes from 10.1.0.2 [02-06-0a:01:00:02:20:00]\
+ *                               <0|206(13)|999794> (ArchHeader=HELLO:1000000)
+ * where you can see that this first packet includes 317 bytes from the
+ * previous send packet (filled with N) and 13 bytes of header before the 206
+ * bytes of payload (filled with P).
+ */
+
+#define RECV_PRINT
+
+// dcl non-method functions....
+std::string rle(const uint8_t *, int );
+std::ofstream fileOut("tcp-2way.out");
+
+//----------class ArchHeader dcl and definition---------------------------------
+/*
+ * ArchHeader: A toy header that holds a string
+ * and a uint32_t. The string is an abitrary label
+ * and the int is used as the length of the payload.
+ */
+
+class ArchHeader : public Header {
+public:
+  virtual uint32_t  GetSerializedSize (void) const;
+  virtual void      Serialize (Buffer::Iterator) const;
+  virtual uint32_t  Deserialize (Buffer::Iterator);
+  virtual void      Print (std::ostream &) const;
+  static  TypeId    GetTypeId (void);
+  virtual TypeId    GetInstanceTypeId (void) const;
+
+  // accessor functions.....
+  void        SetIntValue (uint32_t);
+  uint32_t    GetIntValue (void) const;
+  void        SetStrValue (const std::string &s);
+  std::string GetStrValue (void) const;
+private:
+  uint32_t          int_value;
+  std::string       str_value;
+};
+
+
+TypeId
+ArchHeader::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ArchHeader")
+    .AddConstructor<ArchHeader> () // NOTE: Required for ????
+    .SetParent<Header> ()          // ditto
+    ;
+  return tid;
+}
+
+TypeId
+ArchHeader::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+ArchHeader::GetSerializedSize (void) const
+{
+  return 2*sizeof (uint32_t) + str_value.size (); // int, str len & bytes
+}
+
+void
+ArchHeader::Serialize (Buffer::Iterator i) const
+{
+  i.WriteU32 (int_value);
+  uint32_t str_len = str_value.size ();
+  i.WriteU32 (str_len);
+  for (uint32_t j = 0; j < str_value.size (); j++)
+    i.WriteU8 (str_value[j]);
+}
+  
+uint32_t
+ArchHeader::Deserialize (Buffer::Iterator i)
+{
+  int_value = i.ReadU32 ();
+  uint32_t str_len = i.ReadU32 ();
+  str_value.reserve (str_len);
+  for (uint32_t j = 0; j < str_len; j++) {
+    char v = i.ReadU8 ();
+    str_value.push_back (v);
+  }
+  return 2*sizeof (uint32_t) + str_value.size ();
+}
+
+
+void
+ArchHeader::SetIntValue (uint32_t v_)
+{
+  int_value = v_;
+}
+
+uint32_t
+ArchHeader::GetIntValue (void) const
+{
+  return int_value;
+}
+
+void
+ArchHeader::SetStrValue (const std::string &s)
+{
+  str_value = s;
+}
+
+std::string
+ArchHeader::GetStrValue (void) const
+{
+  return str_value;
+}
+   
+void
+ArchHeader::Print (std::ostream &os) const
+{
+  os << "(ArchHeader=" << str_value << ":" << int_value << ")";
+}
+
+//----------class TalkerApp dcl and definition----------------------------------
+/*
+ * TalkerApp:
+ * An an Application that can serve as both Rx and Tx side.
+ * and is configured by ConfRecv/ConfSend and driven by
+ * ScheduleSendPacket. Becareful not to try to send a packet
+ * from the Rx side to the Tx side (back channel) before the
+ * connection is setup, which has to be from the Tx to the Rx
+ * (the forward channel).
+ */
+
+class TalkerApp : public Application {
+public:
+  TalkerApp ();
+  virtual ~TalkerApp ();
+  void ConfRecv (Ptr<Node>,const Address &);
+  void ConfSend (Ptr<Node>,const Address &);
+  void ScheduleSendPacket(const Time ,const char , const uint32_t size );
+
+protected:
+  virtual void DoDispose (void);
+private:
+  virtual void StartApplication (void);
+  virtual void StopApplication (void);
+
+  void StartApplicationRecv (void);
+  void StartApplicationSend (void);
+
+  void HandleRead (Ptr<Socket>);
+  void SendPacket (std::string,char,uint32_t);
+
+  void CloseConnection (Ptr<Socket> socket);
+  void ConnectionSucceeded (Ptr<Socket>);
+  void ConnectionFailed (Ptr<Socket>);
+  bool ConnectionRequested (Ptr<Socket>, const Address &);
+  void ConnectionCreated (Ptr<Socket>, const Address &);
+
+
+  bool            verbose;
+  Ptr<Socket>     m_socket;
+  Ptr<Socket>     m_servsocket;
+  Address         m_local;
+  Address         m_remote;
+  int             i_am_listener;
+  typedef std::map<Ptr<Socket>, uint32_t>::iterator left_to_read_iterator_type;
+  std::map<Ptr<Socket>, uint32_t> m_left_to_read;
+};
+
+class TalkerApp_sub : public TalkerApp {
+public:
+  int foo(void);
+};
+
+int
+TalkerApp_sub::foo(void) {return 0;}
+
+TalkerApp::TalkerApp () :
+  verbose (false),
+  m_socket (0),
+  m_servsocket (0),
+  i_am_listener (0)
+{}
+
+TalkerApp::~TalkerApp ()
+{}
+
+void
+TalkerApp::DoDispose (void)
+{
+  m_socket = 0;
+  m_servsocket = 0;
+  Application::DoDispose ();
+}
+
+
+void
+TalkerApp::CloseConnection (Ptr<Socket> sock)
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << sock
+                  );
+  sock->Close ();
+}
+
+void
+TalkerApp::ConnectionSucceeded (Ptr<Socket> sock)
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << sock
+	
+		   );
+}
+
+void
+TalkerApp::ConnectionFailed (Ptr<Socket> sock)
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << sock
+                  );
+}
+
+bool
+TalkerApp::ConnectionRequested (Ptr<Socket> sock, const Address &addr)
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << sock
+                  << addr
+                  );
+  return true;
+}
+
+void
+TalkerApp::ConnectionCreated (Ptr<Socket> sock, const Address &addr)
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << sock
+                  << addr
+                  );
+  m_socket = sock;
+  m_socket->SetRecvCallback(MakeCallback (&TalkerApp::HandleRead, this));
+}
+
+void 
+TalkerApp::ScheduleSendPacket (const Time dt,const char fill,
+                               const uint32_t size)
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                   << dt
+                   << fill
+                   << size
+                   );
+  Simulator::Schedule(dt,&TalkerApp::SendPacket, this,
+                      std::string("HELLO"),fill,size);
+}
+
+
+void
+TalkerApp::StartApplication ()
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  );
+  if (i_am_listener)
+    StartApplicationRecv ();
+  else
+    StartApplicationSend ();
+}
+
+void
+TalkerApp::StartApplicationSend ()
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  );
+
+  if (!m_socket) {
+    m_socket = Socket::CreateSocket (GetNode (),
+				    TcpSocketFactory::GetTypeId ());
+    m_socket->Bind ();
+  }
+
+  m_socket->Connect (m_remote);
+  m_socket->SetConnectCallback
+    (
+     MakeCallback (&TalkerApp::ConnectionSucceeded,this),
+     MakeCallback (&TalkerApp::ConnectionFailed,this)
+     );
+  m_socket->SetRecvCallback (MakeCallback (&TalkerApp::HandleRead, this));
+}
+
+void
+TalkerApp::StartApplicationRecv ()
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  );
+  if (!m_servsocket) {
+    m_servsocket = Socket::CreateSocket (GetNode (),
+					TcpSocketFactory::GetTypeId ());
+    m_servsocket->Bind (m_local);
+    m_servsocket->Listen (0);
+  }
+
+  m_servsocket->SetAcceptCallback
+    (
+     MakeCallback (&TalkerApp::ConnectionRequested,this),
+     MakeCallback (&TalkerApp::ConnectionCreated,this)
+     );
+}
+ 
+void
+TalkerApp::ConfRecv (Ptr<Node> node, const Address &addr)
+{
+  i_am_listener = 1;
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << node
+                  << addr
+                  );
+  m_local = addr;
+  node->AddApplication (this);
+}
+
+void
+TalkerApp::ConfSend (Ptr<Node> node, const Address &addr)
+{
+  i_am_listener = 0;
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << node
+                  << addr
+                  );
+  m_remote = addr;
+  node->AddApplication (this);
+}
+
+
+void
+TalkerApp::SendPacket (std::string label,char fill,uint32_t payloadsize)
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << label
+                  << fill
+                  << payloadsize
+                  );
+
+#if 0
+  Ptr<Packet> p = Create<Packet> (payloadsize); // zero byte filled packet.
+#else
+  uint8_t *buf = (uint8_t *) malloc(payloadsize*sizeof(uint8_t));
+  memset(buf,fill,payloadsize);
+  Ptr<Packet> p = Create<Packet> (buf,payloadsize); // filled packet.
+  free(buf);
+#endif
+  if (verbose) {
+    p->Print (fileOut << "Before Marking|");
+    fileOut << std::endl;
+  }
+
+  ArchHeader hdr;
+  hdr.SetStrValue (label);
+  hdr.SetIntValue (p->GetSize());
+  p->AddHeader (hdr);
+  if (verbose) {
+    p->Print(fileOut << "After Header Marking|");
+    fileOut << std::endl;
+  }
+
+  m_socket->Send (p);
+}
+
+void
+TalkerApp::StopApplication ()
+{
+  NS_LOG_FUNCTION ((i_am_listener ? "Server|" : "Client|")
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  );
+  if (m_socket)
+    m_socket->SetRecvCallback (MakeNullCallback<void, Ptr<Socket> > ());
+}
+
+void
+TalkerApp::HandleRead (Ptr<Socket> socket)
+{
+  left_to_read_iterator_type iter = m_left_to_read.find (socket);
+  if (iter == m_left_to_read.end ())
+    m_left_to_read[socket] = 0;
+
+  std::ostringstream  pretty;
+  pretty << (i_am_listener ? "Server" : "Client")
+         << (iter == m_left_to_read.end () ? 
+             "(new)" : "(old)")
+         << "|";
+
+  NS_LOG_FUNCTION ( pretty.str ()
+#ifdef PRINT_THIS                  
+                  << this
+#endif
+                  << socket
+                  );
+  /*
+   * NOTE: I can crash with the # bytes == 500 rather than 536
+   * which seems to be the default MTU
+   */
+
+#ifdef TOO_SMALL_BUG
+  const uint32_t number_of_bytes_willing_to_read = 500;
+#else
+  const uint32_t number_of_bytes_willing_to_read = 536;
+#endif
+  const uint32_t unused_flags = 0;
+
+  Ptr<Packet> packet;
+  while (packet = socket->Recv (number_of_bytes_willing_to_read,
+                                unused_flags) ){
+    std::string raw_rle = rle(packet->PeekData(),
+                              packet->GetSize());
+    SocketAddressTag rx_addr_tag;
+    bool found;
+    found = packet->FindFirstMatchingTag (rx_addr_tag);
+    NS_ASSERT (found);
+    Address from = rx_addr_tag.GetAddress ();
+    // XXX packet->RemoveTag (tag);
+    if (InetSocketAddress::IsMatchingType (from)) {
+      InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+
+#ifdef VERBOSE_TESTING
+      packet->Print (fileOut << "Packet Dump: ");
+      fileOut << std::endl;
+#endif
+
+
+      bool freshly_in_the_loop = true;
+      do {
+#if defined(RECV_PRINT)
+        fileOut
+          << raw_rle // <length>:<rle of packet->PeekBuffer>
+          << (freshly_in_the_loop ? " *" : "  ") /* used to see if the do while
+                                                  * does anything */
+          << "bytes from "
+          << address.GetIpv4 () << " [" << address << "] ";
+#endif
+        freshly_in_the_loop = false;
+        int header_bytes = 0;
+        ArchHeader* hdr =  0; // sadly, can't be a Ptr<>
+        if (
+            (m_left_to_read[socket] == 0)
+            ) {
+          hdr =  new ArchHeader;
+          if (packet->RemoveHeader (*hdr)) {
+            m_left_to_read[socket] = hdr->GetIntValue ();
+            header_bytes = hdr->GetSerializedSize ();
+          } else {
+            ; // never get here, ns3 dumps if no header is there.
+          }
+        }
+        uint32_t num_bytes_processed = 0;
+        if (m_left_to_read[socket] <= packet->GetSize ()) {
+          packet->RemoveAtStart (m_left_to_read[socket]);
+          num_bytes_processed = m_left_to_read[socket];
+          m_left_to_read[socket] = 0;
+
+        } else {
+          m_left_to_read[socket] -= packet->GetSize ();
+          num_bytes_processed = packet->GetSize ();
+          packet->RemoveAtStart (packet->GetSize ());
+        }
+
+#if defined(RECV_PRINT)
+        fileOut
+          << "<"
+          << packet->GetSize ()
+          << "|"
+          <<  num_bytes_processed
+          ;
+        if (header_bytes)
+          fileOut
+            << "("
+            << header_bytes
+            << ")"
+            ;
+        fileOut
+          << "|"
+          << m_left_to_read[socket]
+          << ">";
+#ifdef VERBOSE_TESTING
+        if (hdr)
+          hdr->Print(fileOut << " ");
+#endif
+        fileOut << std::endl;
+#endif
+        if (hdr)
+          delete hdr; // free what we new....
+      } while (
+               packet->GetSize ()
+               );
+    } else {
+      fileOut << "not a match in HandleRead" << std::endl;
+    }
+
+  }
+}
+
+//---------------Non-member functions-------------------------------------------
+/*
+ * returns a string containing the length of the buffer,
+ * followed by an run length encoded version of the buffer
+ * un-printables are represented by '.' (i.e. special_marker
+ * const).
+ */
+std::string rle(const uint8_t *buf, int buflen) {
+
+  int justify = 5;
+  std::ostringstream o;
+  const uint8_t min_rep = 3;
+  uint8_t cur_char = 0;
+  const uint8_t special_marker = '.';
+  int cur_cnt = 0;
+  if (justify) {
+    o << std::setw(justify) << std::right << buflen << ":";
+  } else {
+    o << buflen << ":";
+  }
+
+  for (int i = 0; i < buflen; i++) {
+    if (
+        (!isprint(buf[i]) && cur_char == special_marker) ||
+        (buf[i] == cur_char)
+        )
+      cur_cnt++;
+    else {
+      if (cur_cnt >= min_rep)
+        o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
+          << cur_cnt << "}";
+      else
+        for (int irep=0; irep < cur_cnt; irep++)
+          o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
+      if (isprint(buf[i]))
+        cur_char = buf[i];
+      else
+        cur_char = special_marker;
+      cur_cnt = 1;
+    }
+  }
+  if (cur_cnt >= min_rep)
+    o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.') << "{"
+      << cur_cnt << "}";
+  else
+    for (int irep=0; irep < cur_cnt; irep++)
+      o << (isprint(cur_char) ? static_cast<char>(cur_char) : '.');
+  return o.str();
+}
+
+//---------------Main-----------------------------------------------------------
+int
+main (int argc, char *argv[]) {
+
+  std::clog.rdbuf (fileOut.rdbuf ()); /* till we can do this in ns3::log
+                                         * without this ns3 logging messages
+                                         * are far away from normal output
+                                         */
+
+#ifdef VERBOSE_TESTING  
+  LogComponentEnable ("tcp-2way",LOG_LEVEL_ALL);
+#endif
+
+  RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
+  Packet::EnableMetadata ();
+
+  // boilerplate:  "c0[0]" is Tx, "c0[1]" is Rx.
+  NodeContainer c0;
+  c0.Create (2);
+
+  // We create the channels first without any IP addressing information
+  PointToPointHelper p2p;
+  p2p.SetDeviceAttribute ("DataRate",DataRateValue (DataRate (10000000)));
+  p2p.SetChannelAttribute ("Delay",TimeValue (MilliSeconds (10)));
+  NetDeviceContainer dev0 = p2p.Install (c0);
+
+  // add ip/tcp stack to nodes.
+  InternetStackHelper internet;
+  internet.Install (c0);
+
+  // Later, we add IP addresses.  
+  Ipv4AddressHelper ipv4;
+  ipv4.SetBase ("10.1.0.0", "255.255.255.0");
+  Ipv4InterfaceContainer ifaces = ipv4.Assign (dev0);
+
+  // Configure the apps.
+  uint16_t servPort = 32;
+
+
+  // setup Rx side using ns3::Node "c0[1]" to listen for ANY:servPort
+  Ptr<TalkerApp> sink = CreateObject<TalkerApp_sub>();
+  sink->ConfRecv (c0.Get (1),
+		InetSocketAddress (Ipv4Address::GetAny (), servPort));
+  sink->Start (Seconds (0.0)); // somehow we get by without a Stop. bad form?
+
+  // setup Tx side using ns3::Node "c0[0]" to talk to "c0[1]":servPort
+  Ptr<TalkerApp>  source = CreateObject<TalkerApp_sub>();
+  source->ConfSend (c0.Get (0),
+                  InetSocketAddress (ifaces.GetAddress (1),
+                                     servPort));
+  source->Start (Seconds (0.0));
+
+  // 10 sec is an eternity for this case, we should be done by then.
+  Simulator::Stop (Seconds (10));
+
+
+  // For regression use only output ascii and pcap traces.
+#ifdef REGRESSION_MODE
+  std::ofstream ascii;
+  ascii.open ("tcp-2way.tr");
+  PointToPointHelper::EnableAsciiAll (ascii);
+  PointToPointHelper::EnablePcapAll ("tcp-2way");
+#endif
+
+  /*
+   * Now lets schedule some packets and go. For scheduling packets
+   * we have to be careful not to do the backchannel too early or
+   * we try to use a socket that doesn't yet exist since on the Rx
+   * side the socket is created as part of the normal Tx->Rx connection
+   * setup.
+   *
+   * The delay of 40ms was by trial and error and seems good enough. It
+   * would be nice to know what the bounds are and why....
+   */
+
+  char tagchar = 'A'; // the fill character in case we fill in SendPacket.
+
+  Time d2t = MilliSeconds(40); /* rate to change time offset (dt) so packets
+                                * are sent in order (Tx->Rx, Rx->Tx for a given
+                                * size over a range of sizes).*/
+
+  Time dt = MilliSeconds(0); /* ns3 doesn't take absolute times, but times
+                              * relative to Simulator::Now() */
+
+  uint32_t size = 0;
+  source->ScheduleSendPacket (dt, tagchar, size);
+  dt += d2t;
+  ++tagchar;
+  sink->ScheduleSendPacket (dt, tagchar, size);
+  for (size = 1; size <= 1000000; size *= 10) {
+    dt += d2t;
+    ++tagchar;
+    source->ScheduleSendPacket (dt, tagchar, size);
+    dt += d2t;
+    ++tagchar;
+    sink->ScheduleSendPacket (dt, tagchar, size);
+  }
+
+  // Release the Hounds!!
+  Simulator::Run ();
+  Simulator::Destroy ();
+  fileOut.close();
+}
--- a/examples/wscript	Wed Jul 09 18:50:28 2008 +0100
+++ b/examples/wscript	Fri Jul 11 18:15:52 2008 +0100
@@ -56,6 +56,10 @@
         ['point-to-point', 'internet-stack'])
     obj.source = 'tcp-errors.cc'
 
+    obj = bld.create_ns3_program('tcp-2way',
+      ['point-to-point', 'internet-stack'])
+    obj.source = 'tcp-2way.cc'
+
     obj = bld.create_ns3_program('tcp-star-server',
         ['point-to-point', 'internet-stack'])
     obj.source = 'tcp-star-server.cc'
--- a/src/common/buffer.cc	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/common/buffer.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -1128,6 +1128,12 @@
   return ~sum;
 }
 
+uint32_t 
+Buffer::Iterator::GetSize (void) const
+{
+  return m_dataEnd - m_dataStart;
+}
+
 } // namespace ns3
 
 
--- a/src/common/buffer.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/common/buffer.h	Fri Jul 11 18:15:52 2008 +0100
@@ -358,6 +358,11 @@
        */
       uint16_t CalculateIpChecksum(uint16_t size, uint32_t initialChecksum);
 
+      /**
+       * \returns the size of the underlying buffer we are iterating
+       */
+      uint32_t GetSize (void) const;
+
   private:
       friend class Buffer;
       Iterator (Buffer const*buffer);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/deprecated.h	Fri Jul 11 18:15:52 2008 +0100
@@ -0,0 +1,10 @@
+#ifndef NS3_DEPRECATED_H
+#define NS3_DEPRECATED_H
+
+#ifdef __GNUC__
+#define NS_DEPRECATED __attribute__ ((deprecated))
+#else
+#define NS_DEPRECATED
+#endif
+
+#endif /* NS3_DEPRECATED_H */
--- a/src/core/wscript	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/core/wscript	Fri Jul 11 18:15:52 2008 +0100
@@ -110,5 +110,6 @@
         'trace-source-accessor.h',
         'config.h',
         'object-vector.h',
+        'deprecated.h'
         ]
 
--- a/src/helper/csma-helper.cc	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/helper/csma-helper.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -64,6 +64,17 @@
 }
 
 void 
+CsmaHelper::SetDeviceParameter (std::string n1, const AttributeValue &v1)
+{
+  SetDeviceAttribute (n1, v1);
+}
+void 
+CsmaHelper::SetChannelParameter (std::string n1, const AttributeValue &v1)
+{
+  SetChannelAttribute (n1, v1);
+}
+
+void 
 CsmaHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid)
 {
   std::ostringstream oss;
--- a/src/helper/csma-helper.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/helper/csma-helper.h	Fri Jul 11 18:15:52 2008 +0100
@@ -27,6 +27,7 @@
 #include "ns3/net-device-container.h"
 #include "ns3/node-container.h"
 #include "ns3/csma-channel.h"
+#include "ns3/deprecated.h"
 
 namespace ns3 {
 
@@ -79,6 +80,9 @@
    */
   void SetChannelAttribute (std::string n1, const AttributeValue &v1);
 
+  void SetDeviceParameter (std::string n1, const AttributeValue &v1) NS_DEPRECATED;
+  void SetChannelParameter (std::string n1, const AttributeValue &v1) NS_DEPRECATED;
+
   /**
    * \param filename filename prefix to use for pcap files.
    * \param nodeid the id of the node to generate pcap output for.
--- a/src/helper/point-to-point-helper.cc	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/helper/point-to-point-helper.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -64,6 +64,17 @@
 }
 
 void 
+PointToPointHelper::SetDeviceParameter (std::string name, const AttributeValue &value)
+{
+  SetDeviceAttribute (name, value);
+}
+void 
+PointToPointHelper::SetChannelParameter (std::string name, const AttributeValue &value)
+{
+  SetChannelAttribute (name, value);
+}
+
+void 
 PointToPointHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid)
 {
   std::ostringstream oss;
--- a/src/helper/point-to-point-helper.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/helper/point-to-point-helper.h	Fri Jul 11 18:15:52 2008 +0100
@@ -23,6 +23,7 @@
 #include "ns3/object-factory.h"
 #include "ns3/net-device-container.h"
 #include "ns3/node-container.h"
+#include "ns3/deprecated.h"
 #include <string>
 
 namespace ns3 {
@@ -78,6 +79,9 @@
    */
   void SetChannelAttribute (std::string name, const AttributeValue &value);
 
+  void SetDeviceParameter (std::string name, const AttributeValue &value) NS_DEPRECATED;
+  void SetChannelParameter (std::string name, const AttributeValue &value) NS_DEPRECATED;
+
   /**
    * \param filename filename prefix to use for pcap files.
    * \param nodeid the id of the node to generate pcap output for.
--- a/src/internet-stack/tcp-header.cc	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/internet-stack/tcp-header.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -23,6 +23,7 @@
 #include "tcp-socket-impl.h"
 #include "tcp-header.h"
 #include "ns3/buffer.h"
+#include "ns3/address-utils.h"
 
 namespace ns3 {
 
@@ -37,8 +38,6 @@
     m_flags (0),
     m_windowSize (0xffff),
     m_urgentPointer (0),
-    m_initialChecksum(0),
-    m_checksum (0),
     m_calcChecksum(false),
     m_goodChecksum(true)
 {}
@@ -52,11 +51,6 @@
   m_calcChecksum = true;
 }
 
-void TcpHeader::SetPayloadSize(uint16_t payloadSize)
-{
-  m_payloadSize = payloadSize;
-}
-
 void TcpHeader::SetSourcePort (uint16_t port)
 {
   m_sourcePort = port;
@@ -85,10 +79,6 @@
 {
   m_windowSize = windowSize;
 }
-void TcpHeader::SetChecksum (uint16_t checksum)
-{
-  m_checksum = checksum;
-}
 void TcpHeader::SetUrgentPointer (uint16_t urgentPointer)
 {
   m_urgentPointer = urgentPointer;
@@ -122,10 +112,6 @@
 {
   return m_windowSize;
 }
-uint16_t TcpHeader::GetChecksum () const
-{
-  return m_checksum;
-}
 uint16_t TcpHeader::GetUrgentPointer () const
 {
   return m_urgentPointer;
@@ -133,29 +119,31 @@
 
 void 
 TcpHeader::InitializeChecksum (Ipv4Address source, 
-                                   Ipv4Address destination,
-                                   uint8_t protocol)
+                               Ipv4Address destination,
+                               uint8_t protocol)
 {
-  Buffer buf = Buffer(12);
-  uint8_t tmp[4];
-  Buffer::Iterator it;
-  uint16_t tcpLength = m_payloadSize + GetSerializedSize();
-
-  buf.AddAtStart(12);
-  it = buf.Begin();
+  m_source = source;
+  m_destination = destination;
+  m_protocol = protocol;
+}
 
-  source.Serialize(tmp);
-  it.Write(tmp, 4); /* source IP address */
-  destination.Serialize(tmp);
-  it.Write(tmp, 4); /* destination IP address */
-  it.WriteU8(0); /* protocol */
-  it.WriteU8(protocol); /* protocol */
-  it.WriteU8(tcpLength >> 8); /* length */
-  it.WriteU8(tcpLength & 0xff); /* length */
+uint16_t
+TcpHeader::CalculateHeaderChecksum (uint16_t size) const
+{
+  Buffer buf = Buffer (12);
+  buf.AddAtStart (12);
+  Buffer::Iterator it = buf.Begin ();
 
-  it = buf.Begin();
+  WriteTo (it, m_source);
+  WriteTo (it, m_destination);
+  it.WriteU8 (0); /* protocol */
+  it.WriteU8 (m_protocol); /* protocol */
+  it.WriteU8 (size >> 8); /* length */
+  it.WriteU8 (size & 0xff); /* length */
+
+  it = buf.Begin ();
   /* we don't CompleteChecksum ( ~ ) now */
-  m_initialChecksum = ~(it.CalculateIpChecksum(12));
+  return ~(it.CalculateIpChecksum (12));
 }
 
 bool
@@ -219,7 +207,6 @@
 void TcpHeader::Serialize (Buffer::Iterator start)  const
 {
   Buffer::Iterator i = start;
-  uint16_t tcpLength = m_payloadSize + GetSerializedSize();
   i.WriteHtonU16 (m_sourcePort);
   i.WriteHtonU16 (m_destinationPort);
   i.WriteHtonU32 (m_sequenceNumber);
@@ -231,8 +218,9 @@
 
   if(m_calcChecksum)
   {
+    uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
     i = start;
-    uint16_t checksum = i.CalculateIpChecksum(tcpLength, m_initialChecksum);
+    uint16_t checksum = i.CalculateIpChecksum(start.GetSize (), headerChecksum);
     
     i = start;
     i.Next(16);
@@ -250,16 +238,16 @@
   m_flags = field & 0x3F;
   m_length = field>>12;
   m_windowSize = i.ReadNtohU16 ();
-  m_checksum = i.ReadU16 ();
+  i.Next (2);
   m_urgentPointer = i.ReadNtohU16 ();
 
   if(m_calcChecksum)
-  {
+    {
+      uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
       i = start;
-      uint16_t checksum = i.CalculateIpChecksum(m_payloadSize + GetSerializedSize(), m_initialChecksum);
-
+      uint16_t checksum = i.CalculateIpChecksum(start.GetSize (), headerChecksum);
       m_goodChecksum = (checksum == 0);
-  }
+    }
 
   return GetSerializedSize ();
 }
--- a/src/internet-stack/tcp-header.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/internet-stack/tcp-header.h	Fri Jul 11 18:15:52 2008 +0100
@@ -78,10 +78,6 @@
    */
   void SetWindowSize (uint16_t windowSize);
   /**
-   * \param checksum the checksum for this TcpHeader
-   */
-  void SetChecksum (uint16_t checksum);
-  /**
    * \param urgentPointer the urgent pointer for this TcpHeader
    */
   void SetUrgentPointer (uint16_t urgentPointer);
@@ -117,10 +113,6 @@
    */
   uint16_t GetWindowSize () const;
   /**
-   * \return the checksum for this TcpHeader
-   */
-  uint16_t GetChecksum () const;
-  /**
    * \return the urgent pointer for this TcpHeader
    */
   uint16_t GetUrgentPointer () const;
@@ -151,17 +143,13 @@
   virtual uint32_t Deserialize (Buffer::Iterator start);
 
   /**
-   * \param size The payload size in bytes
-   */
-  void SetPayloadSize (uint16_t size);
-
-  /**
    * \brief Is the TCP checksum correct ?
    * \returns true if the checksum is correct, false otherwise.
    */
   bool IsChecksumOk (void) const;
 
 private:
+  uint16_t CalculateHeaderChecksum (uint16_t size) const;
   uint16_t m_sourcePort;
   uint16_t m_destinationPort;
   uint32_t m_sequenceNumber;
@@ -170,13 +158,14 @@
   uint8_t m_flags;      // really a uint6_t
   uint16_t m_windowSize;
   uint16_t m_urgentPointer;
-  uint16_t m_payloadSize;
+
+  Ipv4Address m_source;
+  Ipv4Address m_destination;
+  uint8_t m_protocol;
+
   uint16_t m_initialChecksum;
-  uint16_t m_checksum;
-
   bool m_calcChecksum;
   bool m_goodChecksum;
-
 };
 
 }; // namespace ns3
--- a/src/internet-stack/tcp-l4-protocol.cc	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/internet-stack/tcp-l4-protocol.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -448,6 +448,7 @@
   if(m_calcChecksum)
   {
     tcpHeader.EnableChecksums();
+    tcpHeader.InitializeChecksum (source, destination, PROT_NUMBER);
   }
 
   packet->PeekHeader (tcpHeader);
@@ -495,7 +496,6 @@
   TcpHeader tcpHeader;
   tcpHeader.SetDestinationPort (dport);
   tcpHeader.SetSourcePort (sport);
-  tcpHeader.SetPayloadSize(packet->GetSize());
   if(m_calcChecksum)
   {
     tcpHeader.EnableChecksums();
@@ -529,7 +529,6 @@
   // XXX outgoingHeader cannot be logged
 
   outgoingHeader.SetLength (5); //header length in units of 32bit words
-  outgoingHeader.SetPayloadSize(packet->GetSize());
   /* outgoingHeader.SetUrgentPointer (0); //XXX */
   if(m_calcChecksum)
   {
--- a/src/internet-stack/tcp-socket-impl.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/internet-stack/tcp-socket-impl.h	Fri Jul 11 18:15:52 2008 +0100
@@ -50,7 +50,13 @@
  * This class contains an implementation of TCP Tahoe, as well as a sockets
  * interface for talking to TCP.  Features include connection orientation,
  * reliability through cumulative acknowledgements, congestion and flow 
- * control.  Finite send/receive buffer semantics are modeled.
+ * control.  Finite send buffer semantics are modeled, but as of yet, finite
+ * receive buffer modelling is unimplemented.
+ *
+ * The closedown of these sockets is as of yet not compliant with the relevent
+ * RFCs, i.e. the FIN handshaking isn't correct.  While this is visible at the
+ * PCAP tracing level, it has no effect on the statistics users are interested
+ * in, i.e. throughput, delay, etc. of actual payload data.
  *
  * Asynchronous callbacks to provide notifications to higher layers that a 
  * protocol event has occured, such as space freeing up in the send buffer
--- a/src/internet-stack/udp-header.cc	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/internet-stack/udp-header.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -19,6 +19,7 @@
  */
 
 #include "udp-header.h"
+#include "ns3/address-utils.h"
 
 namespace ns3 {
 
@@ -32,8 +33,6 @@
   : m_sourcePort (0xfffd),
     m_destinationPort (0xfffd),
     m_payloadSize (0xfffd),
-    m_initialChecksum (0),
-    m_checksum(0),
     m_calcChecksum(false),
     m_goodChecksum(true)
 {}
@@ -71,35 +70,31 @@
   return m_destinationPort;
 }
 void 
-UdpHeader::SetPayloadSize (uint16_t size)
-{
-  m_payloadSize = size;
-}
-void 
 UdpHeader::InitializeChecksum (Ipv4Address source, 
                               Ipv4Address destination,
                               uint8_t protocol)
 {
-  Buffer buf = Buffer(12);
-  uint8_t tmp[4];
-  Buffer::Iterator it;
-  uint16_t udpLength = m_payloadSize + GetSerializedSize();
-
-  buf.AddAtStart(12);
-  it = buf.Begin();
+  m_source = source;
+  m_destination = destination;
+  m_protocol = protocol;
+}
+uint16_t
+UdpHeader::CalculateHeaderChecksum (uint16_t size) const
+{
+  Buffer buf = Buffer (12);
+  buf.AddAtStart (12);
+  Buffer::Iterator it = buf.Begin ();
 
-  source.Serialize(tmp);
-  it.Write(tmp, 4); /* source IP address */
-  destination.Serialize(tmp);
-  it.Write(tmp, 4); /* destination IP address */
-  it.WriteU8(0); /* protocol */
-  it.WriteU8(protocol); /* protocol */
-  it.WriteU8(udpLength >> 8); /* length */
-  it.WriteU8(udpLength & 0xff); /* length */
+  WriteTo (it, m_source);
+  WriteTo (it, m_destination);
+  it.WriteU8 (0); /* protocol */
+  it.WriteU8 (m_protocol); /* protocol */
+  it.WriteU8 (size >> 8); /* length */
+  it.WriteU8 (size & 0xff); /* length */
 
-  it = buf.Begin();
+  it = buf.Begin ();
   /* we don't CompleteChecksum ( ~ ) now */
-  m_initialChecksum = ~(it.CalculateIpChecksum(12));
+  return ~(it.CalculateIpChecksum (12));
 }
 
 bool
@@ -142,17 +137,17 @@
 UdpHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
-  uint16_t udpLength = m_payloadSize + GetSerializedSize();
 
   i.WriteHtonU16 (m_sourcePort);
   i.WriteHtonU16 (m_destinationPort);
-  i.WriteHtonU16 (udpLength);
+  i.WriteHtonU16 (start.GetSize ());
   i.WriteU16 (0);
 
   if (m_calcChecksum)
     {
+      uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
       i = start;
-      uint16_t checksum = i.CalculateIpChecksum(udpLength, m_initialChecksum);
+      uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum);
 
       i = start;
       i.Next(6);
@@ -166,12 +161,13 @@
   m_sourcePort = i.ReadNtohU16 ();
   m_destinationPort = i.ReadNtohU16 ();
   m_payloadSize = i.ReadNtohU16 () - GetSerializedSize ();
-  m_checksum = i.ReadU16();
+  i.Next (2);
 
   if(m_calcChecksum)
   {
+      uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ());
       i = start;
-      uint16_t checksum = i.CalculateIpChecksum(m_payloadSize + GetSerializedSize(), m_initialChecksum);
+      uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum);
 
       m_goodChecksum = (checksum == 0);
   }
--- a/src/internet-stack/udp-header.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/internet-stack/udp-header.h	Fri Jul 11 18:15:52 2008 +0100
@@ -66,10 +66,6 @@
    * \return the destination port for this UdpHeader
    */
   uint16_t GetDestinationPort (void) const;
-  /**
-   * \param size The payload size in bytes
-   */
-  void SetPayloadSize (uint16_t size);
 
   /**
    * \param source the ip source to use in the underlying
@@ -100,12 +96,14 @@
   bool IsChecksumOk (void) const;
 
 private:
+  uint16_t CalculateHeaderChecksum (uint16_t size) const;
   uint16_t m_sourcePort;
   uint16_t m_destinationPort;
   uint16_t m_payloadSize;
-  uint16_t m_initialChecksum;
-  uint16_t m_checksum;
 
+  Ipv4Address m_source;
+  Ipv4Address m_destination;
+  uint8_t m_protocol;
   bool m_calcChecksum;
   bool m_goodChecksum;
 };
--- a/src/internet-stack/udp-l4-protocol.cc	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/internet-stack/udp-l4-protocol.cc	Fri Jul 11 18:15:52 2008 +0100
@@ -163,7 +163,6 @@
     udpHeader.EnableChecksums();
   }
 
-  udpHeader.SetPayloadSize (packet->GetSize () - udpHeader.GetSerializedSize ());
   udpHeader.InitializeChecksum (source, destination, PROT_NUMBER);
 
   packet->RemoveHeader (udpHeader);
@@ -195,13 +194,12 @@
   if(m_calcChecksum)
   {
     udpHeader.EnableChecksums();
+    udpHeader.InitializeChecksum (saddr,
+                                  daddr,
+                                  PROT_NUMBER);
   }
   udpHeader.SetDestinationPort (dport);
   udpHeader.SetSourcePort (sport);
-  udpHeader.SetPayloadSize (packet->GetSize ());
-  udpHeader.InitializeChecksum (saddr,
-                                daddr,
-                                PROT_NUMBER);
 
   packet->AddHeader (udpHeader);
 
--- a/src/node/tcp-socket-factory.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/node/tcp-socket-factory.h	Fri Jul 11 18:15:52 2008 +0100
@@ -48,8 +48,6 @@
 public:
   static TypeId GetTypeId (void);
 
-  virtual Ptr<Socket> CreateSocket (void) = 0;
-
 };
 
 } // namespace ns3
--- a/src/node/udp-socket-factory.h	Wed Jul 09 18:50:28 2008 +0100
+++ b/src/node/udp-socket-factory.h	Fri Jul 11 18:15:52 2008 +0100
@@ -42,14 +42,6 @@
 public:
   static TypeId GetTypeId (void);
 
-  /**
-   * \return smart pointer to Socket
-   * 
-   * API for creating socket instances; must be implemented by UDP 
-   * implementations..
-   */
-  virtual Ptr<Socket> CreateSocket (void) = 0;
-
 };
 
 } // namespace ns3
--- a/wscript	Wed Jul 09 18:50:28 2008 +0100
+++ b/wscript	Fri Jul 11 18:15:52 2008 +0100
@@ -197,7 +197,7 @@
     
     if (os.path.basename(conf.env['CXX']).startswith("g++")
         and 'CXXFLAGS' not in os.environ):
-        variant_env.append_value('CXXFLAGS', ['-Werror'])
+        variant_env.append_value('CXXFLAGS', ['-Werror', '-Wno-error=deprecated-declarations'])
 
     if 'debug' in Params.g_options.debug_level.lower():
         variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')