Add Mathieu's super object container; add Rx trace on SerialNetDevice
authorTom Henderson <tomh@tomh.org>
Mon, 19 Mar 2007 07:02:14 -0700
changeset 352 8fb57ba7b707
parent 351 3589721585e7
child 353 b8656730c209
Add Mathieu's super object container; add Rx trace on SerialNetDevice
SConstruct
samples/ns-2/simple.cc
src/core/object-container.cc
src/core/object-container.h
src/devices/serial/serial-net-device.cc
src/devices/serial/serial-net-device.h
src/devices/serial/serial-topology.cc
--- a/SConstruct	Mon Mar 19 00:40:44 2007 -0700
+++ b/SConstruct	Mon Mar 19 07:02:14 2007 -0700
@@ -24,6 +24,7 @@
     'test.cc',
     'random-variable.cc',
     'rng-stream.cc',
+    'object-container.cc',
     ])
 env = Environment()
 if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin':
@@ -48,7 +49,8 @@
     'fatal-error.h',
     'test.h',
     'random-variable.h',
-    'rng-stream.h'
+    'rng-stream.h',
+    'object-container.h'
     ])
 
 def config_core (env, config):
--- a/samples/ns-2/simple.cc	Mon Mar 19 00:40:44 2007 -0700
+++ b/samples/ns-2/simple.cc	Mon Mar 19 07:02:14 2007 -0700
@@ -37,6 +37,7 @@
 // - Tracing of queues and packet receptions to file "out.tr"
 
 #include <iostream>
+#include <fstream>
 #include <string>
 #include <cassert>
 
@@ -63,109 +64,85 @@
 #include "ns3/udp-header.h"
 #include "ns3/node-list.h"
 #include "ns3/trace-root.h"
-
+#include "ns3/object-container.h"
 #include "ns3/serial-topology.h"
 
 using namespace ns3;
 
-class Tracer : public TraceWriter{
+class AsciiTrace 
+{
 public:
-  Tracer ()
-  {
-  };
-
-  Tracer (std::string const &filename) 
-  {
-    Open(filename);
-  };
-
-  Tracer (char const *filename) : m_tracer(filename)
-  {
-    Open(filename);
-  };
-
-  ~Tracer () {};
+  AsciiTrace (std::string filename);
+  ~AsciiTrace ();
+  void TraceAllQueues (void);
+  void TraceAllNetDeviceRx (void);
+private:
+  void LogDevQueue (TraceContext const &context, const Packet &p);
+  void LogDevRx (TraceContext const &context, Packet &p);
+  std::ofstream m_os;
+};
 
-  void LogNodeInterface (TraceContext const &context)
-  {
-    NodeList::NodeIndex nodeIndex;
-    context.Get (nodeIndex);
-    m_filestr << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
-    Ipv4::InterfaceIndex interfaceIndex;
-    context.Get (interfaceIndex);
-    m_filestr << "interface=" << interfaceIndex << " ";
-  }
-
-
-  void LogEnqueue (TraceContext const &context, const Packet &p)
-  {
-    m_filestr << "+ " << Simulator::Now().GetSeconds() << " ";
-    LogNodeInterface (context);
-    m_filestr << "pkt-uid=" << p.GetUid () << " ";
-    //PrintLlcPacket (p, m_filestr);
-    m_filestr << std::endl;
-  }
+AsciiTrace::AsciiTrace (std::string filename)
+{
+  m_os.open (filename.c_str ());
+}
+AsciiTrace::~AsciiTrace ()
+{
+  m_os.close ();
+}
+void
+AsciiTrace::TraceAllQueues (void)
+{
+  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*",
+                      MakeCallback (&AsciiTrace::LogDevQueue, this));
+}
+void
+AsciiTrace::TraceAllNetDeviceRx (void)
+{
+  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx",
+                      MakeCallback (&AsciiTrace::LogDevRx, this));
+}
 
-  void LogDequeue (TraceContext const &context, const Packet &p)
-  {
-    m_filestr << "- " << Simulator::Now().GetSeconds() << " ";
-    LogNodeInterface (context);
-    m_filestr << "pkt-uid=" << p.GetUid () << " ";
-    //PrintLlcPacket (p, m_filestr);
-    m_filestr << std::endl;
-  }
-  void LogDrop (TraceContext const &context, const Packet &p)
-  {
-    m_filestr << "d " << Simulator::Now().GetSeconds() << " ";
-    LogNodeInterface (context);
-    m_filestr << "pkt-uid=" << p.GetUid () << " ";
-    //PrintLlcPacket (p, m_filestr);
-    m_filestr << std::endl;
-  }
-
-  void PrintLlcPacket (Packet p, std::ostream &os)
-  {
-    LlcSnapHeader llc;
-    p.Peek (llc);
-    p.Remove (llc);
-    switch (llc.GetType ())
-      {
-      case 0x0800: {
-        Ipv4Header ipv4;
-        p.Peek (ipv4);
-        p.Remove (ipv4);
-        if (ipv4.GetProtocol () == 17)
-          {
-            UdpHeader udp;
-            p.Peek (udp);
-            p.Remove (udp);
-            os << "udp payload=" << p.GetSize () 
-               << " from="<< ipv4.GetSource () << ":" << udp.GetSource ()
-               << " to="<< ipv4.GetDestination () << ":" << udp.GetDestination ();
-          }
-      } break;
-      case 0x0806: {
-        ArpHeader arp;
-        p.Peek (arp);
-        p.Remove (arp);
-        os << "arp ";
-        if (arp.IsRequest ())
-          {
-            os << "request from=" << arp.GetSourceIpv4Address ()
-               << ", for=" << arp.GetDestinationIpv4Address ();
-          }
-        else
-          {
-            os << "reply from=" << arp.GetSourceIpv4Address ()
-               << ", for=" << arp.GetDestinationIpv4Address ();
-          }
-      } break;
-      }
-  }
-
-protected:
-  TraceWriter m_tracer;
-};
+void 
+AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &p)
+{
+  enum Queue::TraceType type;
+  context.Get (type);
+  switch (type) 
+    {
+    case Queue::ENQUEUE:
+      m_os << "+ ";
+      break;
+    case Queue::DEQUEUE:
+      m_os << "- ";
+      break;
+    case Queue::DROP:
+      m_os << "d ";
+      break;
+    }
+  m_os << Simulator::Now ().GetSeconds () << " ";
+  NodeList::NodeIndex nodeIndex;
+  context.Get (nodeIndex);
+  m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
+  Ipv4::InterfaceIndex interfaceIndex;
+  context.Get (interfaceIndex);
+  m_os << "interface=" << interfaceIndex << " ";
+  m_os << "pkt-uid=" << p.GetUid () << " ";
+  m_os << std::endl;
+}
+void 
+AsciiTrace::LogDevRx (TraceContext const &context, Packet &p)
+{
+  m_os << "r " << Simulator::Now ().GetSeconds () << " ";
+  NodeList::NodeIndex nodeIndex;
+  context.Get (nodeIndex);
+  m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
+  Ipv4::InterfaceIndex interfaceIndex;
+  context.Get (interfaceIndex);
+  m_os << "interface=" << interfaceIndex << " ";
+  m_os << "pkt-uid=" << p.GetUid () << " ";
+  m_os << std::endl;  
+}
 
 
 static void
@@ -230,6 +207,8 @@
   DebugComponentEnable("SerialPhy");
 #endif
 
+  ObjectContainer container;
+
   // ** Here, some kind of factory or topology object will instantiates 
   // ** four identical nodes; for now, we just explicitly create them
   InternetNode *n0 = new InternetNode();
@@ -237,6 +216,11 @@
   InternetNode *n2 = new InternetNode();
   InternetNode *n3 = new InternetNode();
 
+  container.Acquire (n0);
+  container.Acquire (n1);
+  container.Acquire (n2);
+  container.Acquire (n3);
+
   NodeList::Add (n0);
   NodeList::Add (n1);
   NodeList::Add (n2);
@@ -247,17 +231,20 @@
   n2->SetName(std::string("Node 2"));
   n3->SetName(std::string("Node 3"));
   
-  SerialChannel* ch1 = SerialTopology::AddSerialLink (
+  SerialChannel* ch1;
+  ch1 = SerialTopology::AddSerialLink (
       n0, Ipv4Address("10.1.1.1"), 
       n2, Ipv4Address("10.1.1.2"), 
       5000000, MilliSeconds(2));
   
-  SerialChannel* ch2 = SerialTopology::AddSerialLink (
+  SerialChannel* ch2;
+  ch2 = SerialTopology::AddSerialLink (
       n1, Ipv4Address("10.1.2.1"), 
       n2, Ipv4Address("10.1.2.2"), 
       5000000, MilliSeconds(2));
 
-  SerialChannel* ch3 = SerialTopology::AddSerialLink (
+  SerialChannel* ch3;
+  ch3 = SerialTopology::AddSerialLink (
       n2, Ipv4Address("10.1.3.1"), 
       n3, Ipv4Address("10.1.3.2"), 
       1500000, MilliSeconds(10));
@@ -269,6 +256,11 @@
   DatagramSocket *sink1 = new DatagramSocket(n1);
   sink1->Bind (80);
 
+  container.Acquire (source0);
+  container.Acquire (source3);
+  container.Acquire (sink3);
+  container.Acquire (sink1);
+
   source3->SetDefaultDestination (Ipv4Address ("10.1.2.1"), 80);
   source0->SetDefaultDestination (Ipv4Address ("10.1.3.2"), 80);
 
@@ -276,18 +268,9 @@
   n0->GetIpv4()->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
   n3->GetIpv4()->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
 
-  Tracer tracer("out.tr");
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/enqueue",
-                      MakeCallback (&Tracer::LogEnqueue, &tracer));
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/dequeue",
-                      MakeCallback (&Tracer::LogDequeue, &tracer));
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/drop",
-                      MakeCallback (&Tracer::LogDrop, &tracer));
-#if 0
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/receive",
-                      MakeCallback (&Tracer::LogReceive, &tracer));
-#endif
-
+  AsciiTrace trace ("out.tr");
+  trace.TraceAllQueues ();
+  trace.TraceAllNetDeviceRx ();
 
   PrintTraffic (sink3);
   GenerateTraffic (source0, 100);
@@ -301,17 +284,6 @@
     
   // The below deletes will be managed by future topology objects
   // or containers or smart pointers
-  delete n0;
-  delete n1;
-  delete n2;
-  delete n3;
-  delete ch1;
-  delete ch2;
-  delete ch3;
-  delete source3;
-  delete source0;
-  delete sink3;
-  delete sink1;
 
   Simulator::Destroy ();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/object-container.cc	Mon Mar 19 07:02:14 2007 -0700
@@ -0,0 +1,201 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * 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
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "object-container.h"
+
+namespace ns3 {
+
+ObjectContainer::DeleterList ObjectContainer::m_deleterList;
+
+ObjectContainer::~ObjectContainer ()
+{
+  Cleanup ();
+}
+
+void
+ObjectContainer::Cleanup (void)
+{
+  for (List::iterator i = m_list.begin (); i != m_list.end (); i++)
+    {
+      uint32_t uid = i->first;
+      std::vector<void *> *vec = i->second;
+      ObjectDeleter deleter = LookupObjectDeleter (uid);
+      for (std::vector<void *>::iterator j = vec->begin (); 
+	   j != vec->end (); j++) 
+	{
+	  (deleter) (*j); 
+	}
+      delete vec;
+    }
+  m_list.erase (m_list.begin (), m_list.end ());
+}
+
+uint32_t 
+ObjectContainer::GetGlobalUid (void) const
+{
+  static uint32_t globalUid = 0;
+  globalUid ++;
+  return globalUid;
+}
+
+uint32_t 
+ObjectContainer::RegisterUid (uint32_t uid, ObjectDeleter deleter) const
+{
+  for (DeleterList::iterator i = m_deleterList.begin ();
+       i != m_deleterList.end (); i++)
+    {
+      NS_ASSERT (i->first != uid);
+    }
+  m_deleterList.push_back (std::make_pair (uid, deleter));
+  return uid;
+}
+
+ObjectContainer::ObjectDeleter 
+ObjectContainer::LookupObjectDeleter (uint32_t uid) const
+{
+  for (DeleterList::iterator i = m_deleterList.begin ();
+       i != m_deleterList.end (); i++)
+    {
+      if (i->first == uid)
+	{
+	  return i->second;
+	}
+    }
+  NS_FATAL_ERROR ("unknown deleter requested.");
+  return 0;
+}
+
+}//namespace ns3
+
+
+#ifdef RUN_SELF_TESTS
+
+#include "test.h"
+namespace ns3 {
+  
+class A 
+{
+public:
+  A () {}
+  ~A () {}
+};
+
+class WithCopy
+{
+public:
+  WithCopy () {}
+  ~WithCopy () {}
+  WithCopy *Copy (void) const {return new WithCopy ();}
+};
+
+class B
+{
+public:
+  B () {}
+  ~B () {}
+};
+
+class Base
+{
+public:
+  Base () {}
+  virtual ~Base () {}
+};
+
+class DerivedA
+{
+public:
+  DerivedA () {}
+  virtual ~DerivedA () {}
+};
+
+class DerivedB
+{
+public:
+  DerivedB () {}
+  virtual ~DerivedB () {}
+};
+
+
+class ObjectContainerTest : public Test
+{
+public:
+  ObjectContainerTest ();
+  virtual ~ObjectContainerTest ();
+
+  virtual bool RunTests (void);
+};
+
+ObjectContainerTest::ObjectContainerTest ()
+  : Test ("ObjectContainer")
+{}
+
+ObjectContainerTest::~ObjectContainerTest ()
+{}
+
+bool
+ObjectContainerTest::RunTests (void)
+{
+  bool ok = true;
+
+  ObjectContainer container;
+  A *a = new A ();
+  A *firstA = a;
+  container.Acquire (a);
+  a = new A ();
+  container.Acquire (a);
+  a = new A ();
+  container.Acquire (a);
+  B *b = new B ();
+  container.Acquire (b);
+  a = new A ();
+  container.Acquire (a);
+  b = new B ();
+  container.Acquire (b);
+
+  container.Remove (firstA);
+  delete firstA;
+
+  Base *base = new Base ();
+  container.Acquire (base);
+  DerivedA *derivedA = new DerivedA ();
+  container.Acquire (derivedA);
+  DerivedB *derivedB = new DerivedB ();
+  container.Acquire (derivedB);
+  base = new Base ();
+  container.Acquire (base);
+  derivedB = new DerivedB ();
+  container.Acquire (derivedB);
+
+
+  // the following cannot work because no copy method defined.
+  //container.Add (A ());
+  container.Add (WithCopy ());
+
+  container.Cleanup ();
+  
+  return ok;
+}
+
+static ObjectContainerTest g_objectContainerTest;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/object-container.h	Mon Mar 19 07:02:14 2007 -0700
@@ -0,0 +1,165 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * 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
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef OBJECT_CONTAINER_H
+#define OBJECT_CONTAINER_H
+
+#include <list>
+#include <vector>
+#include <stdint.h>
+#include "fatal-error.h"
+
+namespace ns3 {
+
+
+class ObjectContainer 
+{
+public:
+  ~ObjectContainer ();
+  void Cleanup (void);
+
+  template <typename T>
+  void Acquire (T *object);
+
+  template <typename T>
+  T *Add (T const &object);
+
+  template <typename T>
+  void Remove (T *object);
+
+private:
+  typedef void (*ObjectDeleter) (void *);
+  typedef std::list<std::pair<uint32_t,std::vector<void *> *> > List;
+  typedef std::list<std::pair<uint32_t,ObjectDeleter> > DeleterList;
+  template <typename T>
+  static void DeleteObject (void *ptr);
+  template <typename T>
+  uint32_t GetUid (void) const;
+
+  template <typename T>
+  std::vector<T *> *GetVector (void) const;
+
+  uint32_t GetGlobalUid (void) const;
+  uint32_t RegisterUid (uint32_t uid, ObjectDeleter deleter) const;
+  ObjectContainer::ObjectDeleter LookupObjectDeleter (uint32_t uid) const;
+  List m_list;
+  static DeleterList m_deleterList;
+};
+
+}; // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+ObjectContainer::Acquire (T *object)
+{
+  uint32_t uid = GetUid<T> ();
+  for (List::iterator i = m_list.begin (); i != m_list.end (); i++)
+    {
+      if (i->first == uid)
+	{
+	  i->second->push_back (object);
+	  return;
+	}
+    }
+  std::vector<void *> * vec = new std::vector<void *> ();
+  vec->push_back (object);
+  m_list.push_back (std::make_pair (uid, vec));
+}
+
+template <typename T>
+T *
+ObjectContainer::Add (T const &object)
+{
+  T *copy = object.Copy ();
+  Acquire (copy);
+  return copy;
+}
+
+
+template <typename T>
+void
+ObjectContainer::Remove (T *object)
+{
+  uint32_t uid = GetUid<T> ();
+  for (List::iterator i = m_list.begin (); i != m_list.end (); i++)
+    {
+      if (i->first == uid)
+	{	  
+	  for (std::vector<void *>::iterator j = i->second->begin ();
+	       j != i->second->end (); j++)
+	    {
+	      if ((*j) == object)
+		{
+		  i->second->erase (j);
+		  return;
+		}
+	    }
+	  goto error;
+	}
+    }
+ error:
+  NS_FATAL_ERROR ("tried to remove non-existant object from object container");
+}
+
+template <typename T>
+std::vector<T *> *
+ObjectContainer::GetVector (void) const
+{
+  uint32_t uid = GetUid<T> ();
+  for (List::const_iterator i = m_list.begin (); i != m_list.end (); i++)
+    {
+      if (i->first == uid)
+	{
+	  std::vector<void *> *vec = i->second;
+	  std::vector<T *> *retval = (std::vector<T *> *)vec;
+	  return retval;
+	}
+    }
+  NS_FATAL_ERROR ("no object registered for requested type.");
+  // quiet compiler
+  return 0;
+}
+
+
+
+
+template <typename T>
+void
+ObjectContainer::DeleteObject (void *ptr)
+{
+  T *object = (T*) ptr;
+  delete object;
+}
+
+template <typename T>
+uint32_t
+ObjectContainer::GetUid (void) const
+{
+  static uint32_t uid = RegisterUid (GetGlobalUid (), 
+				     &ObjectContainer::DeleteObject<T>);
+  return uid;
+}
+
+}//namespace ns3
+
+
+#endif /* OBJECT_CONTAINER_H */
--- a/src/devices/serial/serial-net-device.cc	Mon Mar 19 00:40:44 2007 -0700
+++ b/src/devices/serial/serial-net-device.cc	Mon Mar 19 07:02:14 2007 -0700
@@ -83,6 +83,9 @@
   resolver->Add ("queue", 
                  MakeCallback (&Queue::CreateTraceResolver, m_queue),
                  SerialNetDevice::QUEUE);
+  resolver->Add ("rx",
+                 m_rxTrace,
+                 SerialNetDevice::RX);
   return resolver;
 }
 
@@ -119,6 +122,7 @@
   // ignore return value for now.
   NS_DEBUG ("SerialNetDevice::Receive (" << &p << ")");
 
+  m_rxTrace (p);
   ForwardUp (p);
 }
 
--- a/src/devices/serial/serial-net-device.h	Mon Mar 19 00:40:44 2007 -0700
+++ b/src/devices/serial/serial-net-device.h	Mon Mar 19 07:02:14 2007 -0700
@@ -27,6 +27,7 @@
 #include "ns3/net-device.h"
 #include "ns3/callback.h"
 #include "ns3/packet.h"
+#include "ns3/callback-trace-source.h"
 
 namespace ns3 {
 
@@ -38,6 +39,7 @@
 public:
   enum TraceType {
     QUEUE,
+    RX,
   };
   SerialNetDevice(Node* node);
   virtual ~SerialNetDevice();
@@ -65,7 +67,7 @@
   SerialPhy* m_phy;
   SerialChannel* m_channel;
   Queue* m_queue;
-
+  CallbackTraceSource<Packet &> m_rxTrace;
 };
 
 }; // namespace ns3
--- a/src/devices/serial/serial-topology.cc	Mon Mar 19 00:40:44 2007 -0700
+++ b/src/devices/serial/serial-topology.cc	Mon Mar 19 07:02:14 2007 -0700
@@ -23,6 +23,7 @@
 // George F. Riley, Georgia Tech, Spring 2007
 
 #include "ns3/debug.h"
+#include "ns3/assert.h"
 
 #include "ns3/nstime.h"
 
@@ -54,7 +55,7 @@
   // Duplex link is assumed to be subnetted as a /30
   // May run this unnumbered in the future?
   Ipv4Mask netmask("255.255.255.252");
-  assert(netmask.IsMatch(addra,addrb));
+  NS_ASSERT (netmask.IsMatch(addra,addrb));
 
   DropTailQueue* dtqa = new DropTailQueue();