process -> dce
authorMathieu Lacage <mathieu.lacage@sophia.inria.fr>
Tue, 14 Sep 2010 12:41:32 +0200
changeset 0 0a55bed4c895
child 1 96d7044fd324
process -> dce
example/memory-usage.cc
example/process-empty.cc
example/process-iperf.cc
example/process-linux.cc
example/process-netlink.cc
example/process-ring.cc
example/process-tcp-client.cc
example/process-tcp-loopback.cc
example/process-tcp-server.cc
example/process-udp-client.cc
example/process-udp-perf.cc
example/process-udp-server.cc
example/process.cc
example/ring-udp-perf.cc
example/run-ring-udp-perf.sh
example/udp-perf.cc
example/uss-for-pid.py
example/wscript
helper/dce-application-helper.cc
helper/dce-application-helper.h
helper/dce-manager-helper.cc
helper/dce-manager-helper.h
helper/wscript
model/alloc.cc
model/alloc.h
model/arpa/simu-inet.h
model/cmsg.cc
model/cmsg.h
model/cooja-loader-factory.cc
model/cooja-loader-factory.h
model/copy-loader-factory.cc
model/copy-loader-factory.h
model/dce-application.cc
model/dce-application.h
model/dce-manager-test.cc
model/dce-manager.cc
model/dce-manager.h
model/dlm-loader-factory.cc
model/dlm-loader-factory.h
model/elf-cache.cc
model/elf-cache.h
model/elf-dependencies.cc
model/elf-dependencies.h
model/fiber-manager.cc
model/fiber-manager.h
model/libc-global-variables.c
model/libc-globals.h
model/libc-ns3.version
model/libc-simu.c
model/libc-simu.h
model/libc.c
model/libc.h
model/libpthread-ns3.version
model/linux-socket-fd-factory.cc
model/linux-socket-fd-factory.h
model/linux-socket-fd.cc
model/linux-socket-fd.h
model/loader-factory.cc
model/loader-factory.h
model/net/simu-if.h
model/netlink/TODO
model/netlink/netlink-attribute.cc
model/netlink/netlink-attribute.h
model/netlink/netlink-message-route.cc
model/netlink/netlink-message-route.h
model/netlink/netlink-message.cc
model/netlink/netlink-message.h
model/netlink/netlink-socket-address.cc
model/netlink/netlink-socket-address.h
model/netlink/netlink-socket-factory.cc
model/netlink/netlink-socket-factory.h
model/netlink/netlink-socket-test.cc
model/netlink/netlink-socket.cc
model/netlink/netlink-socket.h
model/ns3-socket-fd-factory.cc
model/ns3-socket-fd-factory.h
model/process.h
model/pthread-fiber-manager.cc
model/pthread-fiber-manager.h
model/readversiondef.c
model/rr-task-scheduler.cc
model/rr-task-scheduler.h
model/simu-alloc.cc
model/simu-clock.h
model/simu-cxa.cc
model/simu-cxa.h
model/simu-debug.cc
model/simu-env.cc
model/simu-errno.h
model/simu-fcntl.h
model/simu-fd.cc
model/simu-global-variables.cc
model/simu-global-variables.h
model/simu-netdb.cc
model/simu-netdb.h
model/simu-poll.h
model/simu-pthread-cond.cc
model/simu-pthread-mutex.cc
model/simu-pthread.cc
model/simu-pthread.h
model/simu-random.h
model/simu-sched.h
model/simu-semaphore.cc
model/simu-semaphore.h
model/simu-signal.cc
model/simu-signal.h
model/simu-stat.cc
model/simu-stdarg.h
model/simu-stdio.cc
model/simu-stdio.h
model/simu-stdlib.cc
model/simu-stdlib.h
model/simu-string.cc
model/simu-string.h
model/simu-time.h
model/simu-timerfd.cc
model/simu-unistd.h
model/simu.cc
model/socket-fd-factory.cc
model/socket-fd-factory.h
model/sys/simu-ioctl.h
model/sys/simu-mman.h
model/sys/simu-select.h
model/sys/simu-socket.h
model/sys/simu-stat.h
model/sys/simu-time.h
model/sys/simu-timerfd.h
model/system-wrappers.cc
model/system-wrappers.h
model/task-manager.cc
model/task-manager.h
model/task-scheduler.cc
model/task-scheduler.h
model/trampoline-manager.cc
model/trampoline-manager.h
model/ucontext-fiber-manager.cc
model/ucontext-fiber-manager.h
model/unix-datagram-socket-fd.cc
model/unix-datagram-socket-fd.h
model/unix-fd.cc
model/unix-fd.h
model/unix-file-fd.cc
model/unix-file-fd.h
model/unix-socket-fd.cc
model/unix-socket-fd.h
model/unix-stream-socket-fd.cc
model/unix-stream-socket-fd.h
model/unix-timer-fd.cc
model/unix-timer-fd.h
model/utils.cc
model/utils.h
model/waiter.cc
model/waiter.h
model/wscript
test/test-cond.cc
test/test-empty.cc
test/test-env.cc
test/test-fd-simple.cc
test/test-macros.cc
test/test-macros.h
test/test-malloc-2.cc
test/test-malloc.cc
test/test-mutex.cc
test/test-nanosleep.cc
test/test-netdb.cc
test/test-once.cc
test/test-pthread-key.cc
test/test-pthread.cc
test/test-random.cc
test/test-select.cc
test/test-sem.cc
test/test-sleep.cc
test/test-stdio.cc
test/test-stdlib.cc
test/test-strerror.cc
test/test-string.cc
test/test-timer-fd.cc
test/wscript
wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/memory-usage.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,98 @@
+#include "memory-usage.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <algorithm>
+#include <sstream>
+#include <string>
+
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE("MemoryUsage");
+
+static long AsLong (std::string str)
+{
+  std::istringstream iss;
+  iss.str (str);
+  long l;
+  iss >> l;
+  return l;
+}
+
+long GetCurrentMemoryUsage (void)
+{
+  int pipefd[2];
+  int retval = ::pipe (pipefd);
+  if (retval == -1)
+    {
+      NS_LOG_ERROR ("Cannot create pipe: " << ::strerror (errno));
+      return 0;
+    }
+  pid_t pid = ::fork ();
+  if (pid == 0)
+    {
+      // child.
+      NS_LOG_DEBUG ("Child");
+      ::close (pipefd[0]);
+      int tmp;
+      tmp = dup2 (pipefd[1], 1);
+      if (tmp == -1)
+	{
+	  NS_LOG_ERROR ("Cannot redirect stdout");
+	  ::exit (0);
+	}
+      retval = ::execl ("/usr/bin/smem", "smem", "-c", "pid uss", (char *)NULL);
+      if (retval == -1)
+	{
+	  NS_LOG_ERROR ("Cannot execl smem: " << ::strerror (errno));
+	}
+      ::close (pipefd[1]);
+      ::_exit (EXIT_SUCCESS);
+    }
+  else
+    {
+      // parent.
+      NS_LOG_DEBUG ("Parent");
+      ::close (pipefd[1]);
+      std::string output;
+      uint8_t c;
+      ssize_t bytesRead = ::read (pipefd[0], &c, 1);
+      while (bytesRead == 1)
+	{
+	  output.push_back (c);
+	  bytesRead = ::read (pipefd[0], &c, 1);
+	}
+      waitpid (pid, 0, 0);
+      ::close (pipefd[0]);
+
+      pid = getpid ();
+      std::istringstream iss;
+      iss.str (output);
+      while (!iss.eof ())
+	{
+	  std::string line;
+	  std::getline (iss, line);
+	  std::string::size_type cur = 0, next = 0;
+	  cur = line.find_first_not_of (" \t", cur);
+	  next = line.find_first_of (" \t", cur);
+	  std::string line_pid = line.substr(cur, next-cur);
+	  cur = next+1;
+	  cur = line.find_first_not_of (" \t", cur);
+	  next = line.find_first_of (" \t", cur);
+	  std::string line_uss = line.substr(cur, next-cur);
+	  if (AsLong (line_pid) == pid)
+	    {
+	      return AsLong (line_uss);
+	    }
+	}
+    }
+  return 0;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-empty.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,128 @@
+#include "ns3/helper-module.h"
+#include "ns3/dce-application-helper.h"
+#include "ns3/dce-manager-helper.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include "ns3/node-module.h"
+#include <fstream>
+
+using namespace ns3;
+
+static std::string GetPeakMemoryUsed (void)
+{
+  std::ifstream is;
+  is.open ("/proc/self/status");
+  while (!is.eof ())
+    {
+      std::string line;
+      getline (is, line);
+      std::string::size_type i = line.find ("VmPeak");
+      if (i == 0)
+	{
+	  is.close();
+	  return line;
+	}
+    }
+  is.close ();
+  return "";
+}
+
+
+static std::string Ipv4AddressToString (Ipv4Address ad)
+{
+  std::ostringstream oss;
+  ad.Print (oss);
+  return oss.str ();
+}
+
+
+int main (int argc, char *argv[])
+{
+  Config::SetDefault ("ns3::Ipv4L3Protocol::DefaultTtl", UintegerValue (255));
+  std::string delay = "1ns";
+  std::string rate = "5Mbps";
+  uint32_t nHops = 1;
+  CommandLine cmd;
+  cmd.AddValue ("Delay", "link delay", delay);
+  cmd.AddValue ("Bandwidth", "link bandwidth", rate);
+  cmd.AddValue ("nHops", "number of hops between source and destination", nHops);
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (nHops+1);
+
+  PointToPointHelper p2p;
+  p2p.SetDeviceAttribute ("DataRate", StringValue (rate));
+  p2p.SetChannelAttribute ("Delay", StringValue (delay));
+  std::vector<NetDeviceContainer> devs;
+  for (uint32_t i = 0; i < nHops; i++)
+    {
+      NodeContainer linkNodes;
+      linkNodes.Add (nodes.Get (i));
+      linkNodes.Add (nodes.Get (i+1));
+      NetDeviceContainer dev = p2p.Install (linkNodes);
+      devs.push_back (dev);
+    }
+#if 0
+  Ipv4NixVectorHelper nixRouting; 
+  Ipv4StaticRoutingHelper staticRouting;
+  Ipv4ListRoutingHelper list; 
+  list.Add (staticRouting, 0); 
+  list.Add (nixRouting, 10);
+#endif
+  // add an ip stack
+  InternetStackHelper stack; 
+  //stack.SetRoutingHelper (list);
+  //stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
+  stack.Install (nodes);
+
+  // start the ping binaries.
+
+  // ip address assignment
+  Ipv4AddressHelper ipv4;
+  std::vector<Ipv4InterfaceContainer> interfaces;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  for (std::vector<NetDeviceContainer>::const_iterator i = devs.begin (); i != devs.end (); ++i)
+    {
+      Ipv4InterfaceContainer interface = ipv4.Assign (*i);
+      interfaces.push_back (interface);
+      ipv4.NewNetwork ();
+    }
+
+  // setup ip routes
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+
+  // start the ping binaries.
+  DceManagerHelper processManager;
+  processManager.Install (nodes);
+
+  DceApplicationHelper process;
+  process.SetStackSize (1<<16);
+  ApplicationContainer apps;
+
+  Ptr<Node> serverNode = nodes.Get (nHops);
+  Ipv4Address serverAddress = interfaces[nHops-1].GetAddress (1, 0);
+
+  process.SetBinary ("build/debug/ping");
+  process.AddArgument ("-c");
+  process.AddArgument ("1");
+  process.AddArgument (Ipv4AddressToString (serverAddress));
+
+  for (uint32_t i = 0; i < 1; i++)
+    {
+      Ptr<Node> clientNode = nodes.Get (0);
+      apps = process.Install (clientNode);
+      apps.Start (Seconds (2.0));
+    }
+
+
+  //p2p.EnablePcapAll ("process-iperf");
+  std::cerr << GetPeakMemoryUsed () << std::endl;
+  //Simulator::Stop (Seconds (0.0));
+  Simulator::Run ();
+  std::cerr << GetPeakMemoryUsed () << std::endl;
+  Simulator::Destroy ();
+
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-iperf.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,104 @@
+#include "ns3/helper-module.h"
+#include "ns3/dce-application-helper.h"
+#include "ns3/dce-manager-helper.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include "ns3/node-module.h"
+
+using namespace ns3;
+
+static std::string Ipv4AddressToString (Ipv4Address ad)
+{
+  std::ostringstream oss;
+  ad.Print (oss);
+  return oss.str ();
+}
+
+int main (int argc, char *argv[])
+{
+  Config::SetDefault ("ns3::Ipv4L3Protocol::DefaultTtl", UintegerValue (255));
+  std::string delay = "1ns";
+  std::string rate = "5Mbps";
+  uint32_t nHops = 1;
+  CommandLine cmd;
+  cmd.AddValue ("Delay", "link delay", delay);
+  cmd.AddValue ("Bandwidth", "link bandwidth", rate);
+  cmd.AddValue ("nHops", "number of hops between source and destination", nHops);
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (nHops+1);
+
+  PointToPointHelper p2p;
+  p2p.SetDeviceAttribute ("DataRate", StringValue (rate));
+  p2p.SetChannelAttribute ("Delay", StringValue (delay));
+  std::vector<NetDeviceContainer> devs;
+  for (uint32_t i = 0; i < nHops; i++)
+    {
+      NodeContainer linkNodes;
+      linkNodes.Add (nodes.Get (i));
+      linkNodes.Add (nodes.Get (i+1));
+      NetDeviceContainer dev = p2p.Install (linkNodes);
+      devs.push_back (dev);
+    }
+
+  // add an ip stack
+  InternetStackHelper stack;
+  //stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
+  stack.Install (nodes);
+
+  // ip address assignment
+  Ipv4AddressHelper ipv4;
+  std::vector<Ipv4InterfaceContainer> interfaces;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  for (std::vector<NetDeviceContainer>::const_iterator i = devs.begin (); i != devs.end (); ++i)
+    {
+      Ipv4InterfaceContainer interface = ipv4.Assign (*i);
+      interfaces.push_back (interface);
+      ipv4.NewNetwork ();
+    }
+
+  // setup ip routes
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+
+
+  // start the ping binaries.
+  DceManagerHelper processManager;
+  processManager.Install (nodes);
+  DceApplicationHelper process;
+  process.SetStackSize (1<<16);
+  ApplicationContainer apps;
+
+  Ptr<Node> serverNode = nodes.Get (nHops);
+  Ptr<Node> clientNode = nodes.Get (0);
+  Ipv4Address serverAddress = interfaces[nHops-1].GetAddress (1, 0);
+
+  process.SetBinary ("build/debug/iperf");
+  process.AddArgument ("-s");
+  process.AddArgument ("-x");
+  process.AddArgument ("CDMSV");
+  //process.AddArgument ("-u");
+  apps = process.Install (serverNode);
+  apps.Start (Seconds (1.0));
+
+  process.SetBinary ("build/debug/iperf");
+  process.ResetArguments ();
+  //process.AddArgument ("-u");
+  process.AddArgument ("-c");
+  process.AddArgument (Ipv4AddressToString (serverAddress));
+  process.AddArgument ("-y");
+  process.AddArgument ("C");
+  process.AddArgument ("-i");
+  process.AddArgument ("1");
+  apps = process.Install (clientNode);
+  apps.Start (Seconds (2.0));
+
+  //PointToPointHelper::EnablePcapAll ("process-iperf");
+
+  Simulator::Stop (Seconds (10.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-linux.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,139 @@
+#include "ns3/helper-module.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include <fstream>
+
+using namespace ns3;
+
+#define noCSMA 1
+#define noP2P 1
+#define WIFI 1
+#define TCP 1
+#define UDP 1
+
+static void RunIp (Ptr<Node> node, Time at, std::string str)
+{
+  DceApplicationHelper process;
+  ApplicationContainer apps;
+  process.SetBinary ("./ip");
+  process.SetStackSize (1<<16);
+  process.ResetArguments();
+  process.ParseArguments(str.c_str ());
+  apps = process.Install (node);
+  apps.Start (at);
+}
+
+static void AddAddress (Ptr<Node> node, Time at, const char *name, const char *address)
+{
+  std::ostringstream oss;
+  oss << "-f inet addr add " << address << " dev " << name;
+  RunIp (node, at, oss.str ());
+}
+
+
+int main (int argc, char *argv[])
+{
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (2);
+
+  NetDeviceContainer devices;
+#if defined(CSMA)
+  CsmaHelper csma;
+  csma.SetChannelAttribute ("DataRate", StringValue ("5Mbps"));
+  csma.SetChannelAttribute ("Delay", StringValue ("2ms"));
+  devices = csma.Install (nodes);
+#elif defined(P2P)
+  PointToPointHelper p2p;
+  p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
+  p2p.SetChannelAttribute ("Delay", StringValue ("2ms"));
+  devices = p2p.Install (nodes);
+#elif defined(WIFI)
+  MobilityHelper mobility;
+  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+  positionAlloc->Add (Vector (0.0, 0.0, 0.0));
+  positionAlloc->Add (Vector (5.0, 0.0, 0.0));
+  mobility.SetPositionAllocator (positionAlloc);
+  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
+  mobility.Install (nodes);
+
+  WifiHelper wifi = WifiHelper::Default ();
+  YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();
+  YansWifiChannelHelper phyChannel = YansWifiChannelHelper::Default ();
+  NqosWifiMacHelper mac;
+  phy.SetChannel (phyChannel.Create ());
+  mac.SetType ("ns3::AdhocWifiMac");
+  wifi.SetStandard (WIFI_PHY_STANDARD_80211a);
+  devices = wifi.Install (phy, mac, nodes);
+#endif
+
+  DceManagerHelper processManager;
+  processManager.SetLoader ("ns3::DlmLoaderFactory");
+  processManager.SetNetworkStack("ns3::LinuxSocketFdFactory",
+				 "Library", StringValue ("libnet-next-2.6.so"));
+  processManager.Install (nodes);
+
+  AddAddress (nodes.Get (0), Seconds (0.1), "sim0", "10.0.0.2/8");
+  RunIp (nodes.Get (0), Seconds (0.11), "link set sim0 up");
+
+  AddAddress (nodes.Get (1), Seconds (0.1), "sim0", "10.0.0.3/8");
+  RunIp (nodes.Get (1), Seconds (0.11), "link set sim0 up");
+
+  RunIp (nodes.Get (0), Seconds (0.2), "link show");
+  RunIp (nodes.Get (0), Seconds (0.3), "route show table all");
+  RunIp (nodes.Get (0), Seconds (0.4), "addr list");
+  RunIp (nodes.Get (1), Seconds (0.2), "link show");
+  RunIp (nodes.Get (1), Seconds (0.3), "route show table all");
+  RunIp (nodes.Get (1), Seconds (0.4), "addr list");
+
+  {
+    DceApplicationHelper process;
+    ApplicationContainer apps;
+
+#if defined(TCP)
+    process.SetBinary ("process-tcp-server");
+    process.ResetArguments ();
+    process.SetStackSize (1<<16);
+    apps = process.Install (nodes.Get (0));
+    apps.Start (Seconds (1.0));
+
+    process.SetBinary ("process-tcp-client");
+    process.ResetArguments ();
+    process.ParseArguments ("10.0.0.2");
+    apps = process.Install (nodes.Get (1));
+    apps.Start (Seconds (1.5));
+#elif defined(UDP)
+    process.SetBinary ("process-udp-server");
+    process.ResetArguments ();
+    process.SetStackSize (1<<16);
+    apps = process.Install (nodes.Get (0));
+    apps.Start (Seconds (1.0));
+
+    process.SetBinary ("process-udp-client");
+    process.ResetArguments ();
+    process.ParseArguments ("10.0.0.2");
+    apps = process.Install (nodes.Get (1));
+    apps.Start (Seconds (1.5));
+#endif
+  }
+
+#if defined(CSMA)
+  csma.EnablePcapAll ("process-linux");
+#elif defined(P2)
+  p2p.EnablePcapAll ("process-linux");
+#elif defined(WIFI)
+  phy.EnablePcapAll ("process-linux");
+#endif
+  //std::ofstream ascii;
+  //ascii.open ("process.tr");
+  //PointToPointHelper::EnableAsciiAll (ascii);
+
+
+  Simulator::Stop (Seconds (20.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-netlink.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,74 @@
+#include "ns3/helper-module.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include <fstream>
+
+using namespace ns3;
+
+int main (int argc, char *argv[])
+{
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (1);
+
+  DceManagerHelper processManager;
+  processManager.SetNetworkStack("ns3::LinuxSocketFdFactory",
+				 "Library", StringValue ("libnet-next-2.6.so"));
+  //processManager.SetLoader("ns3::CopyLoaderFactory");
+  processManager.Install (nodes);
+
+  DceApplicationHelper process;
+  ApplicationContainer apps;
+  process.SetBinary ("build/debug/ip");
+  process.SetStackSize (1<<16);
+#if 0
+  process.ParseArguments("link show");
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (1.0));
+#endif
+#if 1
+  process.ResetArguments();
+  process.ParseArguments("-f inet addr add local 127.0.0.1/8 scope host dev lo");
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (2.0));
+  process.ResetArguments();
+  process.ParseArguments("link set lo up");
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (3.0));
+  process.ResetArguments();
+  process.ParseArguments("route list table all");
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (3.1));
+#endif
+
+  process.ResetArguments();
+  process.ParseArguments("addr show dev lo");
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (3.0));
+
+#if 0
+  process.SetBinary ("build/debug/examples/process/process-udp-server");
+  process.ResetArguments();
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (4.0));
+
+  process.SetBinary ("build/debug/examples/process/process-udp-client");
+  process.ResetArguments();
+  process.AddArgument ("127.0.0.1");
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (4.5));
+#else
+  process.SetBinary ("build/debug/examples/process/process-tcp-loopback");
+  process.ResetArguments();
+  apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (4.0));
+#endif
+
+  Simulator::Stop (Seconds(1000100.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-ring.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,163 @@
+#include "ns3/helper-module.h"
+#include "ns3/dce-application-helper.h"
+#include "ns3/dce-manager-helper.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include "ns3/node-module.h"
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fstream>
+#include <string>
+
+
+using namespace ns3;
+
+static std::string Ipv4AddressToString (Ipv4Address ad)
+{
+  std::ostringstream oss;
+  ad.Print (oss);
+  return oss.str ();
+}
+
+static unsigned long GetUss (void)
+{
+  pid_t pid = getpid ();
+  std::ostringstream oss;
+  oss << "examples/process/uss-for-pid.py " << pid;
+  FILE *file = popen (oss.str ().c_str (), "r");
+  unsigned long uss;
+  fscanf (file, "%lu", &uss);
+  fclose (file);
+  return uss;
+}
+#if 0
+static unsigned long GetNPhysicalPages (void)
+{
+  return 0;
+}
+#endif
+static unsigned long GetUnsharedSize (void)
+{
+  struct rusage usage;
+  int status;
+  status = getrusage (RUSAGE_SELF, &usage);
+  NS_ASSERT (status == 0);
+  return usage.ru_idrss + usage.ru_isrss;
+}
+
+static std::string GetPeakMemoryUsed (void)
+{
+  std::ifstream is;
+  is.open ("/proc/self/status");
+  while (!is.eof ())
+    {
+      std::string line;
+      std::getline (is, line);
+      std::string::size_type i = line.find ("VmPeak");
+      if (i == 0)
+	{
+	  is.close();
+	  return line;
+	}
+    }
+  is.close ();
+  return "";
+}
+
+static void PrintMemory (void)
+{
+  std::cerr << "uss=" << GetUss () << std::endl;
+  std::cerr << "peak=" << GetPeakMemoryUsed () << std::endl;
+  std::cerr << "unshared=" << GetUnsharedSize () << std::endl;
+}
+
+
+int main (int argc, char *argv[])
+{
+  Config::SetDefault ("ns3::Ipv4L3Protocol::DefaultTtl", UintegerValue (255));
+  std::string delay = "1ns";
+  std::string rate = "5Mbps";
+  uint32_t size = 1;
+  CommandLine cmd;
+  cmd.AddValue ("Delay", "link delay", delay);
+  cmd.AddValue ("Bandwidth", "link bandwidth", rate);
+  cmd.AddValue ("Size", "number of nodes in ring", size);
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (size);
+
+  Ipv4StaticRoutingHelper staticHelper;
+  InternetStackHelper stack;
+  stack.SetRoutingHelper (staticHelper);
+  stack.Install (nodes);
+
+  DceManagerHelper processManager;
+  processManager.Install (nodes);
+
+  PointToPointHelper p2p;
+  p2p.SetDeviceAttribute ("DataRate", StringValue (rate));
+  p2p.SetChannelAttribute ("Delay", StringValue (delay));
+  std::vector<NetDeviceContainer> devs;
+  for (uint32_t i = 0; i < size; i++)
+    {
+      NodeContainer linkNodes;
+      linkNodes.Add (nodes.Get (i));
+      linkNodes.Add (nodes.Get ((i+1)%size));
+      NetDeviceContainer dev = p2p.Install (linkNodes);
+      devs.push_back (dev);
+    }
+  
+  std::vector<std::pair<Ptr<Node>, Ipv4Address> > pairs;
+
+  Ipv4AddressHelper addressAlloc;
+  Ipv4Mask mask = Ipv4Mask ("255.255.0.0");
+  addressAlloc.SetBase ("10.1.0.0", mask);
+  for (uint32_t i = 0; i < size; i++)
+    {
+      Ptr<Node> node = nodes.Get (i);
+      Ptr<Node> nextNode = nodes.Get ((i+1)%size);
+      Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
+      Ptr<Ipv4> nextIpv4 = nextNode->GetObject<Ipv4> ();
+      Ptr<NetDevice> dev = node->GetDevice (2);
+      Ptr<NetDevice> nextDev = nextNode->GetDevice (1);
+      Ipv4Address ip = addressAlloc.NewAddress ();
+      Ipv4Address nextIp = addressAlloc.NewAddress ();
+      uint32_t interf = ipv4->AddInterface (dev);
+      uint32_t nextInterf = nextIpv4->AddInterface (nextDev);
+      ipv4->AddAddress (interf, Ipv4InterfaceAddress (ip, mask));
+      nextIpv4->AddAddress (nextInterf, Ipv4InterfaceAddress (nextIp, mask));
+      ipv4->SetUp (interf);
+      nextIpv4->SetUp (nextInterf);
+
+      Ptr<Ipv4StaticRouting> routing = DynamicCast<Ipv4StaticRouting> (ipv4->GetRoutingProtocol ());
+      routing->SetDefaultRoute (nextIp, interf, 0);
+
+      pairs.push_back (std::make_pair (nextNode, ip));
+    }
+
+  for (uint32_t i = 0; i < pairs.size (); i++)
+    {
+      std::pair<Ptr<Node>,Ipv4Address> pair = pairs[i];
+      DceApplicationHelper process;
+      process.SetStackSize (1<<16);
+      process.SetBinary ("build/debug/ping");
+      process.AddArgument ("-c");
+      process.AddArgument ("1");
+      process.AddArgument (Ipv4AddressToString (pair.second));
+      ApplicationContainer apps;
+      apps = process.Install (pair.first);
+      apps.Start (Seconds (2.0));
+    }
+
+  //p2p.EnablePcapAll ("process-ring");
+
+  PrintMemory ();
+  Simulator::Schedule (Seconds (2.00001), &PrintMemory);
+
+  Simulator::Run ();
+
+  Simulator::Destroy ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-tcp-client.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,42 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <iostream>
+
+
+int main (int argc, char *argv[])
+{
+  int sock;
+  sock = socket (PF_INET, SOCK_STREAM, 0);
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (2000);
+
+  struct hostent *host = gethostbyname (argv[1]);
+  memcpy (&addr.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
+
+  int result;
+  result = connect (sock, (const struct sockaddr *) &addr, sizeof (addr));
+
+  uint8_t buf[1024];
+
+  memset (buf, 0x66, 20);
+  memset (buf+20, 0x67, 1004);
+
+  for (uint32_t i = 0; i < 100000; i++)
+    {
+      ssize_t n = 1024;
+      n = write (sock, buf, 1024);
+
+      sleep (1);
+    }
+
+  std::cout << "did write all buffers" << std::endl;
+
+  close (sock);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-tcp-loopback.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,103 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <iostream>
+
+#define SERVER_PORT 2000
+
+static void *client_run (void *ctx)
+{
+  sleep (1);
+  int sock;
+  sock = socket (PF_INET, SOCK_STREAM, 0);
+
+  int result;
+  result = bind (sock, 0, 0);
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (SERVER_PORT);
+
+  struct hostent *host = gethostbyname ("127.0.0.1");
+  memcpy (&addr.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
+
+  result = connect (sock, (const struct sockaddr *) &addr, sizeof (addr));
+
+  uint8_t buf[1024];
+
+  memset (buf, 0x66, 20);
+  memset (buf+20, 0x67, 1004);
+
+  for (uint32_t i = 0; i < 100000; i++)
+    {
+      ssize_t n = 1024;
+      while (n > 0)
+	{
+	  ssize_t written = write (sock, buf, 1024);
+	  std::cout << "write " << written << "bytes" << std::endl;
+	  n -= written;
+	}
+      sleep (1);
+    }
+
+  std::cout << "did write all buffers" << std::endl;
+
+  close (sock);
+
+  return 0;
+}
+
+static void *server_run (void *ctx)
+{
+  int sock;
+  sock = socket (PF_INET, SOCK_STREAM, 0);
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (SERVER_PORT);
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  int status;
+  status = bind (sock, (const struct sockaddr *) &addr, sizeof (addr));
+  status = listen (sock, 1);
+  
+
+  int fd = accept (sock, 0, 0);
+
+  uint8_t buf[10240];
+
+  memset (buf, 0, 10240);
+
+  for (uint32_t i = 0; i < 10000; i++)
+    {
+      ssize_t n = 10240;
+      while (n > 0)
+	{
+	  ssize_t bytes_read = read (fd, buf, 10240);
+	  std::cout << "read " << bytes_read << "bytes" << std::endl;
+	  n -= bytes_read;
+	}
+      sleep (1);
+    }
+
+  std::cout << "did read all buffers" << std::endl;
+
+  close (sock);
+  close (fd);
+
+  return 0;
+}
+
+
+int main (int argc, char *argv[])
+{
+  pthread_t client, server;
+  pthread_create (&client, 0, &client_run, 0);
+  pthread_create (&server, 0, &server_run, 0);
+  pthread_join (client, 0);
+  pthread_join (server, 0);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-tcp-server.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,48 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <iostream>
+
+#define SERVER_PORT 2000
+
+int main (int argc, char *argv[])
+{
+  int sock;
+  sock = socket (PF_INET, SOCK_STREAM, 0);
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (SERVER_PORT);
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  int status;
+  status = bind (sock, (const struct sockaddr *) &addr, sizeof (addr));
+  status = listen (sock, 1);
+  
+
+  int fd = accept (sock, 0, 0);
+
+  uint8_t buf[10240];
+
+  memset (buf, 0, 10240);
+
+  for (uint32_t i = 0; i < 10000; i++)
+    {
+      ssize_t n = 10240;
+      while (n > 0)
+	{
+	  ssize_t bytes_read = read (fd, buf, 10240);
+	  n -= bytes_read;
+	}
+      sleep (1);
+    }
+
+  std::cout << "did read all buffers" << std::endl;
+
+  close (sock);
+  close (fd);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-udp-client.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,43 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <iostream>
+
+
+int main (int argc, char *argv[])
+{
+  sleep (2);
+
+  int sock;
+  sock = socket (PF_INET, SOCK_DGRAM, 0);
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (2000);
+
+  struct hostent *host = gethostbyname (argv[1]);
+  memcpy (&addr.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
+
+  int result;
+  result = connect (sock, (const struct sockaddr *) &addr, sizeof (addr));
+
+  uint8_t buf[1024];
+
+  memset (buf, 0x66, 20);
+  memset (buf+20, 0x67, 1004);
+
+  for (uint32_t i = 0; i < 100000; i++)
+    {
+      ssize_t n;
+      n = write (sock, buf, 1024);
+      sleep (1);
+    }
+
+  std::cout << "did write all buffers" << std::endl;
+
+  close (sock);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-udp-perf.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,95 @@
+#include "ns3/helper-module.h"
+#include "ns3/dce-application-helper.h"
+#include "ns3/dce-manager-helper.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include "ns3/node-module.h"
+
+using namespace ns3;
+
+static std::string Ipv4AddressToString (Ipv4Address ad)
+{
+  std::ostringstream oss;
+  ad.Print (oss);
+  return oss.str ();
+}
+
+int main (int argc, char *argv[])
+{
+  Config::SetDefault ("ns3::Ipv4L3Protocol::DefaultTtl", UintegerValue (255));
+  std::string delay = "1ns";
+  std::string rate = "5Mbps";
+  uint32_t nHops = 1;
+  CommandLine cmd;
+  cmd.AddValue ("Delay", "link delay", delay);
+  cmd.AddValue ("Bandwidth", "link bandwidth", rate);
+  cmd.AddValue ("nHops", "number of hops between source and destination", nHops);
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (nHops+1);
+
+  PointToPointHelper p2p;
+  p2p.SetDeviceAttribute ("DataRate", StringValue (rate));
+  p2p.SetChannelAttribute ("Delay", StringValue (delay));
+  std::vector<NetDeviceContainer> devs;
+  for (uint32_t i = 0; i < nHops; i++)
+    {
+      NodeContainer linkNodes;
+      linkNodes.Add (nodes.Get (i));
+      linkNodes.Add (nodes.Get (i+1));
+      NetDeviceContainer dev = p2p.Install (linkNodes);
+      devs.push_back (dev);
+    }
+
+  // add an ip stack
+  InternetStackHelper stack;
+  //stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
+  stack.Install (nodes);
+
+  // ip address assignment
+  Ipv4AddressHelper ipv4;
+  std::vector<Ipv4InterfaceContainer> interfaces;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  for (std::vector<NetDeviceContainer>::const_iterator i = devs.begin (); i != devs.end (); ++i)
+    {
+      Ipv4InterfaceContainer interface = ipv4.Assign (*i);
+      interfaces.push_back (interface);
+      ipv4.NewNetwork ();
+    }
+
+  // setup ip routes
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+
+
+  // start the ping binaries.
+  DceManagerHelper processManager;
+  processManager.Install (nodes);
+  DceApplicationHelper process;
+  process.SetStackSize (1<<16);
+  ApplicationContainer apps;
+
+  Ptr<Node> serverNode = nodes.Get (nHops);
+  Ptr<Node> clientNode = nodes.Get (0);
+  Ipv4Address serverAddress = interfaces[nHops-1].GetAddress (1, 0);
+
+  process.SetBinary ("build/debug/udp-perf");
+  apps = process.Install (serverNode);
+  apps.Start (Seconds (1.0));
+
+  process.SetBinary ("build/debug/udp-perf");
+  process.ResetArguments ();
+  process.AddArgument ("--client");
+  process.AddArgument (Ipv4AddressToString (serverAddress));
+  apps = process.Install (clientNode);
+  apps.Start (Seconds (2.0));
+
+  //PointToPointHelper::EnablePcapAll ("process-iperf");
+
+  Simulator::Stop (Seconds (10.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process-udp-server.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,52 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <errno.h>
+#include <iostream>
+#include <stdlib.h>
+
+
+int main (int argc, char *argv[])
+{
+  int sock;
+  sock = socket (PF_INET, SOCK_DGRAM, 0);
+  if (sock == -1)
+    {
+      std::cout << "error: " << strerror (errno) << std::endl;
+      exit (-1);
+    }
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (2000);
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  int status;
+  status = bind (sock, (const struct sockaddr *) &addr, sizeof (addr));
+  if (status == -1)
+    {
+      std::cout << "error: " << strerror (errno) << std::endl;
+      exit (-1);
+    }
+
+  uint8_t buf[1024];
+
+  for (uint32_t i = 0; i < 100000; i++)
+    {
+      ssize_t n;
+      n = read (sock, buf, 1024);
+      if (n == -1 && errno == EINTR)
+	{
+	  std::cout << "timer interrupted read" << std::endl;
+	  exit (-1);
+	}
+    }
+
+  std::cout << "did read all buffers" << std::endl;
+
+  close (sock);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/process.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,53 @@
+#include "ns3/helper-module.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include <fstream>
+
+using namespace ns3;
+
+int main (int argc, char *argv[])
+{
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (2);
+
+  PointToPointHelper p2p;
+  p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
+  p2p.SetChannelAttribute ("Delay", StringValue ("2ms"));
+  NetDeviceContainer devices = p2p.Install (nodes);
+
+  InternetStackHelper stack;
+  stack.Install (nodes);
+
+  Ipv4AddressHelper ipv4;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer addresses = ipv4.Assign (devices);
+
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+
+  DceManagerHelper processManager;
+  processManager.Install (nodes);
+
+  DceApplicationHelper process;
+  process.SetBinary ("process-udp-server");
+  process.SetStackSize (1<<16);
+  ApplicationContainer apps = process.Install (nodes.Get (0));
+  apps.Start (Seconds (1.0));
+
+  process.SetBinary ("process-udp-client");
+  process.AddArgument ("10.1.1.1");
+  apps = process.Install (nodes.Get (1));
+  apps.Start (Seconds (1.5));
+
+  p2p.EnablePcapAll ("process");
+  //std::ofstream ascii;
+  //ascii.open ("process.tr");
+  //PointToPointHelper::EnableAsciiAll (ascii);
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/ring-udp-perf.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,361 @@
+#include "memory-usage.h"
+#include "ns3/helper-module.h"
+#include "ns3/dce-application-helper.h"
+#include "ns3/dce-manager-helper.h"
+#include "ns3/simulator-module.h"
+#include "ns3/core-module.h"
+#include "ns3/node-module.h"
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fstream>
+#include <string>
+
+
+using namespace ns3;
+
+#define PORT 8080
+
+static std::string Ipv4AddressToString (Ipv4Address ad)
+{
+  std::ostringstream oss;
+  ad.Print (oss);
+  return oss.str ();
+}
+
+void IpRcv (void)
+{
+  std::cout << "ip_rcv " << std::endl;
+}
+void IpRcvFinish (void)
+{
+  std::cout << "ip_rcv_finish " << std::endl;
+}
+
+long g_memory;
+
+static void PrintMemory (long start)
+{
+  long now = GetCurrentMemoryUsage ();
+  g_memory = now - start;
+}
+
+static Time RunIp (Ptr<Node> node, Time at, std::string str)
+{
+  DceApplicationHelper process;
+  ApplicationContainer apps;
+  process.SetBinary ("./ip");
+  process.SetStackSize (1<<16);
+  process.ResetArguments();
+  process.ParseArguments(str.c_str ());
+  apps = process.Install (node);
+  apps.Start (at);
+  return at + TimeStep (1);
+}
+
+static Time AddAddress (Ptr<Node> node, Time at, std::string name, std::string address)
+{
+  at = RunIp (node, at, "-f inet addr add " + address + " dev " + name);
+  return RunIp (node, at, "link set " + name + " up");
+}
+
+void
+SetupIpStacks (std::string linuxStack, std::string loader, NodeContainer nodes)
+{
+  DceManagerHelper processManager;
+  processManager.SetLoader (loader);
+  if (linuxStack == "")
+    {
+      Ipv4StaticRoutingHelper staticHelper;
+      InternetStackHelper stack;
+      stack.SetRoutingHelper (staticHelper);
+      stack.Install (nodes);
+    }
+  else
+    {
+      processManager.SetNetworkStack("ns3::LinuxSocketFdFactory",
+				     "Library", StringValue (linuxStack));
+    }
+  processManager.Install (nodes);
+  if (linuxStack != "")
+    {
+      for (uint32_t i = 0; i < nodes.GetN (); i++)
+	{
+	  Ptr<Node> n = nodes.Get (i);
+	  RunIp (n, Seconds (0.0), "link set lo up");
+	}
+    }
+}
+
+static std::string Device (Ptr<NetDevice> dev)
+{
+  std::ostringstream oss;
+  oss << "sim" << dev->GetIfIndex ();
+  return oss.str ();
+}
+
+static std::vector<std::pair<Ptr<Node>, Ipv4Address> >
+SetupIpAddresses (std::string linuxStack, NodeContainer nodes, std::vector<NetDeviceContainer> devs)
+{
+  Time start = Seconds (0.1);
+  Time increment = TimeStep (1);
+  std::vector<std::pair<Ptr<Node>, Ipv4Address> > pairs;
+  Ipv4AddressHelper addressAlloc;
+  Ipv4Mask mask = Ipv4Mask ("255.255.255.0"); 
+  addressAlloc.SetBase ("10.1.0.0", mask);
+  for (uint32_t i = 0; i < devs.size (); i++)
+    {
+      addressAlloc.NewNetwork ();
+      Ipv4Address ipA = addressAlloc.NewAddress ();
+      Ipv4Address ipB = addressAlloc.NewAddress ();
+      Ptr<NetDevice> devA = devs[i].Get (0);
+      Ptr<NetDevice> devB = devs[i].Get (1);
+      Ptr<Node> a = devA->GetNode ();
+      Ptr<Node> b = devB->GetNode ();
+      if (linuxStack == "")
+	{
+	  Ptr<Ipv4> ipv4A = a->GetObject<Ipv4> ();
+	  Ptr<Ipv4> ipv4B = b->GetObject<Ipv4> ();
+	  uint32_t interfA = ipv4A->AddInterface (devA);
+	  uint32_t interfB = ipv4B->AddInterface (devB);
+	  ipv4A->AddAddress (interfA, Ipv4InterfaceAddress (ipA, mask));
+	  ipv4B->AddAddress (interfB, Ipv4InterfaceAddress (ipB, mask));
+	  ipv4A->SetUp (interfA);
+	  ipv4B->SetUp (interfB);
+
+	  Ptr<Ipv4StaticRouting> routing = DynamicCast<Ipv4StaticRouting> (ipv4A->GetRoutingProtocol ());
+	  routing->SetDefaultRoute (ipB, interfA, 0);
+	}
+      else
+	{
+	  start = AddAddress (a, start, Device(devA), Ipv4AddressToString (ipA) + "/24");
+	  start = AddAddress (b, start, Device(devB), Ipv4AddressToString (ipB) + "/24");
+	  start = RunIp (a, start, "route add default via " + Ipv4AddressToString (ipB) + " dev " + Device (devA));
+	}
+      pairs.push_back (std::make_pair (a, ipA));
+      if (i == devs.size () - 1)
+	{
+	  pairs.push_back (std::make_pair (b, ipB));
+	}
+    }
+  return pairs;
+}
+
+
+uint16_t g_serverPid;
+
+static void ServerStarted (uint16_t pid)
+{
+  g_serverPid = pid;
+}
+
+double g_sinkRxBytes = 0;
+
+static void SinkReceivedBytes (Ptr<const Packet> p, const Address & from)
+{
+  g_sinkRxBytes += p->GetSize ();
+}
+
+
+std::string AsString (uint32_t i)
+{
+  std::ostringstream oss;
+  oss << i;
+  return oss.str ();
+}
+
+long AsNumber (std::string s)
+{
+  std::istringstream iss;
+  iss.str (s);
+  long v;
+  iss >> v;
+  return v;
+}
+
+static long ReadTotalBytesReceived (uint32_t node)
+{
+  std::ifstream is;
+  std::string filename = "files-" + AsString (node) + "/var/log/" + AsString (g_serverPid) + "/stdout";
+  is.open (filename.c_str (), std::ios_base::in);
+  std::string line, prev;
+  while (!is.eof ())
+    {
+      prev = line;
+      getline (is, line);
+    }
+  // now, parse the last line.
+  std::string::size_type i = prev.rfind (" ");
+  NS_ASSERT (i != std::string::npos);
+  std::string bytes = prev.substr (i+1, prev.size ()-(i+1));
+  is.close ();
+  return AsNumber (bytes);
+}
+
+int main (int argc, char *argv[])
+{
+  //HookManager hooks;
+  //hooks.AddHookBySourceAndFunction ("ip-input.c", "ip_rcv", &IpRcv); 
+  //hooks.AddHookBySourceAndFunction ("ip-input.c", "ip_rcv_finish", &IpRcvFinish); 
+  //hooks.AddHookBySourceAndFunction ("ip-output.c", "ip_local_out", &IpLocalOut); 
+  //hooks.AddHookBySourceAndFunction ("ip-output.c", "nf_hook_slow", &IpLocalOut); 
+  //hooks.AddHookBySourceAndFunction ("af_inet.c", "inet_sendmsg", &IpLocalOut); 
+  // udp_sendmsg udp.c
+  // ip_route_output_flow
+  // ip_output
+  // ip_finish_output
+  // ip_finish_output2
+  // neigh_resolve_output
+  // send_arp
+  // arp_xmit
+  // arp_mangle
+  // dev_hard_start_xmit
+  // ip_append_data
+  // udp_push_pending_frames
+  // ip_push_pending_frames
+  // udp_flush_pending_frames
+  // ip_local_out
+  // ipv4_conntrack_defrag
+  // ipv4_conntrack_local
+  // ipv4_confirm
+  // dst_output
+  // netif_rx
+  // net_rx_action
+  // process_backlog
+  // __netif_receive_skb
+  // ipv6_rcv
+  // arp_rcv
+  // ip_rcv
+  // arp_process
+
+  long memoryAtStart = GetCurrentMemoryUsage ();
+  SystemWallClockMs clock;
+
+  clock.Start ();
+
+  Config::SetDefault ("ns3::Ipv4L3Protocol::DefaultTtl", UintegerValue (255));
+  std::string delay = "1ns";
+  std::string rate = "5Mbps";
+  std::string packetSize = "1000";
+  std::string packetRate = "1000000";
+  std::string linuxStack = "";
+  std::string ns3App = "false";
+  std::string loader = "ns3::DlmLoaderFactory";
+  Time duration = Seconds (10);
+  std::string pcap = "no";
+  uint32_t size = 1;
+  CommandLine cmd;
+  cmd.AddValue ("Duration", "simulation duration", duration);
+  cmd.AddValue ("Pcap", "enable pcap: yes or no", pcap);
+  cmd.AddValue ("Delay", "link delay", delay);
+  cmd.AddValue ("LinkBandwidth", "link bandwidth", rate);
+  cmd.AddValue ("Size", "number of nodes in ring", size);
+  cmd.AddValue ("TxPacketSize", "size of packets sent (bytes)", packetSize);
+  cmd.AddValue ("TxBandwidth", "rate at which packets are sent (in bytes per second)", packetRate);
+  cmd.AddValue ("Ns3App", "Use an ns-3 application or posix one", ns3App);
+  cmd.AddValue ("LinuxPath", "path to linux network stack", linuxStack);
+  cmd.AddValue ("Loader", "type of loader to use", loader);
+  cmd.Parse (argc, argv);
+
+  NodeContainer nodes;
+  nodes.Create (size);
+
+  SetupIpStacks (linuxStack, loader, nodes);
+
+  CsmaHelper csma;
+  csma.SetChannelAttribute ("DataRate", StringValue (rate));
+  csma.SetChannelAttribute ("Delay", StringValue (delay));
+  std::vector<NetDeviceContainer> devs;
+  for (uint32_t i = 0; i < size-1; i++)
+    {
+      NodeContainer linkNodes;
+      linkNodes.Add (nodes.Get (i));
+      linkNodes.Add (nodes.Get (i+1));
+      NetDeviceContainer dev = csma.Install (linkNodes);
+      devs.push_back (dev);
+    }
+
+  Ptr<Node> clientNode, serverNode;
+  Ipv4Address serverIp;
+  if (size > 1)
+    {
+      std::vector<std::pair<Ptr<Node>, Ipv4Address> > pairs;
+      pairs = SetupIpAddresses (linuxStack, nodes, devs);
+      clientNode = pairs[0].first;
+      serverNode = pairs[pairs.size ()-1].first;
+      serverIp = pairs[pairs.size()-1].second;
+    }
+  else
+    {
+      clientNode = nodes.Get (0);
+      serverNode = nodes.Get (0);
+      serverIp = Ipv4Address ("127.0.0.1");
+    }
+
+  if (ns3App == "false")
+    {
+      DceApplicationHelper process;
+      ApplicationContainer apps;
+      process.SetStackSize (1<<16);
+      process.SetBinary ("udp-perf");
+
+      // setup client
+      process.AddArgument ("--client");
+      process.AddArgument ("--host=" + Ipv4AddressToString (serverIp));
+      process.AddArgument ("--pktsize=" + packetSize);
+      process.AddArgument ("--bandwidth=" + packetRate);
+      apps = process.Install (clientNode);
+      apps.Start (Seconds (4.0));
+
+      // setup server
+      process.ResetArguments ();
+      apps = process.Install (serverNode);
+      apps.Start (Seconds (4.0));
+      apps.Get (0)->TraceConnectWithoutContext ("ProcessStarted", MakeCallback (&ServerStarted));
+    }
+  else
+    {
+      ApplicationContainer apps;
+      OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (serverIp, PORT));
+      onoff.SetAttribute ("OnTime", StringValue ("Constant:1.0"));
+      onoff.SetAttribute ("OffTime", StringValue ("Constant:0.0"));
+      onoff.SetAttribute ("PacketSize", StringValue (packetSize));
+      onoff.SetAttribute ("DataRate", StringValue (packetRate + "Bps"));
+      apps = onoff.Install (clientNode);
+      apps.Start (Seconds (4.0));
+
+      PacketSinkHelper sink = PacketSinkHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), PORT));
+      apps = sink.Install (serverNode);
+      apps.Start (Seconds (3.9999));
+      apps.Get (0)->TraceConnectWithoutContext ("Rx", MakeCallback (&SinkReceivedBytes));
+    }
+
+  if (pcap == "yes")
+    {
+      csma.EnablePcapAll ("ring-udp-perf");
+    }
+
+  Simulator::Schedule (Seconds (4.00001), &PrintMemory, memoryAtStart);
+
+  Simulator::Stop (duration);
+  Simulator::Run ();
+
+  Simulator::Destroy ();
+
+  clock.End ();
+  double elapsedMs = clock.GetElapsedReal ();
+  double bytes;
+  if (ns3App == "false")
+    {
+      bytes = ReadTotalBytesReceived (size-1);
+    }
+  else
+    {
+      bytes = g_sinkRxBytes;
+    }
+  double pt = packetSize * (elapsedMs * 1000) / bytes;
+
+  std::cout << "packet size(bytes),n nodes,packet time(us),memory(bytes)" << std::endl;
+  std::cout << packetSize << "," << size << "," << pt << "," << g_memory * 1000 << std::endl;
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/run-ring-udp-perf.sh	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,22 @@
+
+nodes="1 2 3 4 8 10 16 20"
+PRGM=./build/optimized/src/process-manager/example/ring-udp-perf
+CONSTANTS="--TxBandwidth=1000000 --LinkBandwidth=2MBps --ns3::TaskManager::FiberManagerType=UcontextFiberManager --Duration=200s"
+args_exp1="--Ns3App=true"
+args_exp2="--Ns3App=false"
+args_exp3="--Ns3App=false --LinuxPath=./libnet-next-2.6.so"
+for node in ${nodes}; do
+    for exp in exp1 exp2 exp3; do
+	echo -n "${node},${exp},";
+        MEM=0;
+        for i in 0 1 2 3 4 5 6 7 8 9; do
+	    tmp=args_${exp}
+	    ARGS=${!tmp}
+	    OUT=`${PRGM} ${CONSTANTS} ${ARGS} --Size=${node} |cut -d ',' -f3,4|tail -1`;
+	    US=`echo $OUT|sed -e 's/,.*//g'`;
+	    MEM=`echo $OUT|sed -e 's/.*,//g'`;
+	    echo -n "${US},";
+	done;
+	echo ${MEM};
+    done;
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/udp-perf.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,264 @@
+#include <sys/timerfd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+
+extern long long int llrintl(long double x);
+extern long int lrintl(long double x);
+static uint64_t current_time (void);
+
+#define CHECK_INT_ARG(arg, name, value)				  \
+  if (strncmp (arg, "--"name"=", strlen ("--"name"=")) == 0)	  \
+    {								  \
+      value = atoi (arg + strlen ("--"name"="));		  \
+    }
+#define CHECK_LLINT_ARG(arg, name, value)				  \
+  if (strncmp (arg, "--"name"=", strlen ("--"name"=")) == 0)	  \
+    {								  \
+      value = atoll (arg + strlen ("--"name"="));		  \
+    }
+#define CHECK_STR_ARG(arg, name, value)				  \
+  if (strncmp (arg, "--"name"=", strlen ("--"name"=")) == 0)	  \
+    {								  \
+      value = arg + strlen ("--"name"=");			  \
+    }
+
+#if 0
+static void set_txbuf_size (int fd, int buffer_size)
+{
+  int msg_size = buffer_size;
+  int status = setsockopt (fd, SOL_SOCKET, SO_SNDBUF, (char*)&msg_size, sizeof (msg_size));
+  if (status == -1)
+    {
+      printf ("Unable to set socket buffer size to %d\n", msg_size);
+      exit (1);
+    }
+}
+#endif
+
+static void run_client (int to_port, const char *to_ip, int pkt_size, 
+			long long bytes_per_second)
+{
+  int fd = socket (AF_INET, SOCK_DGRAM, 0);
+  if (fd == -1)
+    {
+      printf ("Unable to create udp socket\n");
+      exit (1);
+    }
+  int status;
+  status = fcntl(fd, F_GETFL, 0);
+  if (status == -1)
+  {
+	  perror("fcntl");
+	  exit (1);
+  }
+  status = fcntl(fd, F_SETFL, status | O_NONBLOCK);
+  if (status == -1)
+  {
+	  perror("fcntl");
+	  exit (1);
+  }
+  status = fcntl(fd, F_GETFL, 0);
+#if 0
+  set_txbuf_size (fd, 1<<20);
+#endif
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = 0;
+  addr.sin_addr.s_addr = htonl (INADDR_ANY);
+  status = bind (fd, (struct sockaddr*)&addr, sizeof (addr));
+  if (status == -1)
+    {
+      printf ("Unable to bind\n");
+      exit (1);
+    }
+
+  char *buffer = (char*)malloc (pkt_size);
+  memset (buffer, 0, pkt_size);
+
+  int64_t pps = llrintl(1.0L * bytes_per_second / pkt_size);
+  int64_t ns_delay = llrintl(1000000000.0L / pps);
+  if (ns_delay <= 100000)
+    {
+      ns_delay = 100000;
+    }
+  
+  // 10^9ns=1s
+  double packets_per_delay = 1.0L * bytes_per_second * ns_delay /
+	  pkt_size / 1000000000.0L;
+  printf("bw = %lld, psize = %d, pps = %lld, ns_delay = %lld, ppd = %f\n",
+	 (signed long long) bytes_per_second, pkt_size, (signed long long) pps, 
+	 (signed long long) ns_delay, packets_per_delay);
+
+  int timerfd = timerfd_create (CLOCK_MONOTONIC, 0);
+  struct itimerspec timer;
+  timer.it_interval.tv_sec = 0;
+  timer.it_interval.tv_nsec = ns_delay;
+  timer.it_value.tv_sec = 0;
+  timer.it_value.tv_nsec = ns_delay;
+  timerfd_settime (timerfd, 0, &timer, 0);
+
+  struct sockaddr_in to;
+  to.sin_family = AF_INET;
+  to.sin_port = htons (to_port);
+  to.sin_addr.s_addr = inet_addr (to_ip);
+
+  int64_t sent = 0, total_misses = 0, snd_skipped = 0;
+  int expires = 0;
+  uint64_t last_print_time = current_time ();
+  while (true)
+    {
+      uint64_t current = current_time ();
+      if (current > last_print_time + 1000000)
+	{
+	  last_print_time = current;
+	  //printf("Timer misses: %ld, skipped sends: %ld\n", total_misses, snd_skipped);
+	}
+      uint64_t skipped;
+      ssize_t bytes_read;
+      bytes_read = read (timerfd, &skipped, 8);
+      //printf("skipped: %ld\n", skipped);
+      expires += skipped;
+      total_misses += skipped - 1;
+      long i, tosend = lrintl(expires * packets_per_delay) - sent;
+      for (i = 0; i < tosend; i++)
+	{
+	  ssize_t written = sendto (fd, buffer, pkt_size, MSG_DONTWAIT,
+		  (struct sockaddr *)&to, sizeof (to));
+	  if (written == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
+	  {
+		  snd_skipped += tosend - i;
+		  break;
+	  }
+	  if (written == -1)
+	  {
+		  perror("sentto");
+		  exit(1);
+	  }
+	  sent++;
+	}
+    }
+
+  free (buffer);
+
+  status = close (fd);
+  if (status == -1)
+    {
+      printf ("Unable to close file descriptor %d\n", fd);
+      exit (1);
+    }
+
+}
+
+static uint64_t current_time (void)
+{
+  struct timeval tv;
+  int status = gettimeofday (&tv, 0);
+  if (status == -1)
+    {
+      printf ("Unable to get current time\n");
+      exit (1);
+    }
+  uint64_t current_time = tv.tv_sec;
+  current_time *= 1000000;
+  current_time += tv.tv_usec;
+  return current_time;
+}
+
+static void run_server (int port)
+{
+  int fd = socket (AF_INET, SOCK_DGRAM, 0);
+  if (fd == -1)
+    {
+      printf ("Unable to create udp socket\n");
+      exit (1);
+    }
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = htons (port);
+  addr.sin_addr.s_addr = htonl (INADDR_ANY);
+  int status = bind (fd, (struct sockaddr*)&addr, sizeof (addr));
+  if (status == -1)
+    {
+      printf ("Unable to bind to port %d\n", port);
+      exit (1);
+    }
+
+  uint64_t full_total = 0;
+  uint64_t last_print_time = current_time ();
+  int64_t total_received = 0, total_reads = 0;
+  int64_t buffer_size = 1 << 17;
+  char *buffer = (char*)malloc (buffer_size);
+  while (true)
+    {
+      uint64_t current = current_time ();
+      if (current > last_print_time + 1000000)
+	{
+	  last_print_time = current;
+	  printf ("received=%lld bytes, %lld reads (@%lld bytes) %llu\n",
+		  (signed long long) total_received, 
+		  (signed long long) total_reads,
+		  (signed long long) (total_received / total_reads),
+		  (unsigned long long) full_total);
+	  full_total += total_received;
+	  total_received = total_reads = 0;
+	}
+      ssize_t received = recvfrom (fd, buffer, buffer_size, 0, 0, 0);
+      total_reads++;
+      total_received += received;
+    }
+  free (buffer);
+
+  status = close (fd);
+  if (status == -1)
+    {
+      printf ("Unable to close file descriptor %d\n", fd);
+      exit (1);
+    }
+}
+
+int main (int argc, char *argv[])
+{
+  long long bytes_per_second = 1000000;
+  int pkt_size = 1500;
+  int port = 5000;
+  const char *to_ip = "127.0.0.1";
+  bool client = false;
+  char **arg = argv;
+  while (*arg != 0)
+    {
+      CHECK_INT_ARG(*arg, "pktsize", pkt_size);
+      CHECK_LLINT_ARG(*arg, "bandwidth", bytes_per_second);
+      CHECK_INT_ARG(*arg, "port", port);
+      CHECK_STR_ARG(*arg, "host", to_ip);
+      if (strcmp (*arg, "--client") == 0)
+	{
+	  client = true;
+	}
+      arg++;
+    }
+  setlinebuf(stdout);
+  if (client)
+    {
+      run_client (port, to_ip, pkt_size, bytes_per_second);
+    }
+  else
+    {
+      run_server (port);
+    }
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/uss-for-pid.py	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+import subprocess
+import sys
+import re
+
+pid = sys.argv[1]
+
+smem = subprocess.Popen (['smem', '-c', 'pid uss'],
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT,
+                         stdin=subprocess.PIPE)
+(out, err) = smem.communicate ('')
+
+reg = re.compile('([0-9]+)[^0-9]+([0-9]+)')
+for line in out.split('\n'):
+    m = reg.search (line)
+    if m is not None:
+        if m.group(1) == pid:
+            print m.group(2)
+            sys.exit (0)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example/wscript	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,59 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+import os
+
+def build(bld):
+    obj = bld.create_ns3_program('process', ['core', 'simulator', 'point-to-point', 
+                                             'internet-stack', 'process-manager', 
+					     'dce-helper'])
+    obj.source = 'process.cc'
+
+    obj = bld.create_simu_program('process-udp-server')
+    obj.source = ['process-udp-server.cc']
+    obj = bld.create_simu_program('process-udp-client')
+    obj.source = ['process-udp-client.cc']
+
+    obj = bld.create_simu_program('process-tcp-server')
+    obj.source = ['process-tcp-server.cc']
+    obj = bld.create_simu_program('process-tcp-client')
+    obj.source = ['process-tcp-client.cc']
+
+    obj = bld.create_simu_program('process-tcp-loopback')
+    obj.source = ['process-tcp-loopback.cc']
+
+    obj = bld.create_ns3_program('process-iperf', 
+                                 ['core', 'simulator', 'point-to-point', 
+                                  'internet-stack', 'process-manager'])
+    obj.source = 'process-iperf.cc'
+
+    obj = bld.create_ns3_program('process-empty', 
+                                 ['core', 'simulator', 'point-to-point', 
+                                  'internet-stack', 'process-manager'])
+    obj.source = 'process-empty.cc'
+
+    obj = bld.create_ns3_program('process-udp-perf', 
+                                 ['core', 'simulator', 'point-to-point', 
+                                  'internet-stack', 'process-manager'])
+    obj.source = 'process-udp-perf.cc'
+
+    obj = bld.create_ns3_program('process-ring', 
+                                 ['core', 'simulator', 'point-to-point', 
+                                  'internet-stack', 'process-manager'])
+    obj.source = 'process-ring.cc'
+
+    obj = bld.create_ns3_program('process-netlink', 
+                                 ['core', 'simulator', 'point-to-point', 
+                                  'internet-stack', 'process-manager'])
+    obj.source = 'process-netlink.cc'
+
+    obj = bld.create_ns3_program('process-linux', 
+                                 ['core', 'simulator', 'point-to-point', 
+                                  'internet-stack', 'process-manager'])
+    obj.source = 'process-linux.cc'
+
+    obj = bld.create_simu_program('udp-perf')
+    obj.env.append_value('LINKFLAGS', '-lm')
+    obj.source = 'udp-perf.cc'
+
+    obj = bld.create_ns3_program('ring-udp-perf')
+    obj.source = [ 'ring-udp-perf.cc', 'memory-usage.cc']
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/helper/dce-application-helper.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,143 @@
+#include "dce-application-helper.h"
+#include "ns3/dce-application.h"
+#include "ns3/log.h"
+#include <stdarg.h>
+
+NS_LOG_COMPONENT_DEFINE ("DceApplicationHelper");
+
+namespace ns3 {
+
+DceApplicationHelper::DceApplicationHelper ()
+  : m_stackSize (0)
+{}
+void 
+DceApplicationHelper::SetBinary (std::string filename)
+{
+  m_filename = filename;
+}
+void 
+DceApplicationHelper::SetStackSize (uint32_t stackSize)
+{
+  m_stackSize = stackSize;
+}
+void 
+DceApplicationHelper::AddArgument (std::string arg)
+{
+  NS_LOG_FUNCTION (this << arg);
+  m_args.push_back (arg);
+}
+void DceApplicationHelper::AddArguments (std::string a0, std::string a1)
+{
+  AddArgument (a0);
+  AddArgument (a1);
+}
+void 
+DceApplicationHelper::AddArguments (std::string a0, std::string a1, std::string a2)
+{
+  AddArgument (a0);
+  AddArgument (a1);
+  AddArgument (a2);
+}
+void 
+DceApplicationHelper::AddArguments (std::string a0, std::string a1, std::string a2, std::string a3)
+{
+  AddArgument (a0);
+  AddArgument (a1);
+  AddArgument (a2);
+  AddArgument (a3);
+}
+void 
+DceApplicationHelper::AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+			     std::string a4)
+{
+  AddArgument (a0);
+  AddArgument (a1);
+  AddArgument (a2);
+  AddArgument (a3);
+  AddArgument (a4);
+}
+void 
+DceApplicationHelper::AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+			     std::string a4, std::string a5)
+{
+  AddArgument (a0);
+  AddArgument (a1);
+  AddArgument (a2);
+  AddArgument (a3);
+  AddArgument (a4);
+  AddArgument (a5);
+}
+void 
+DceApplicationHelper::AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+		     std::string a4, std::string a5, std::string a6)
+{
+  AddArgument (a0);
+  AddArgument (a1);
+  AddArgument (a2);
+  AddArgument (a3);
+  AddArgument (a4);
+  AddArgument (a5);
+  AddArgument (a6);
+}
+void 
+DceApplicationHelper::AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+			     std::string a4, std::string a5, std::string a6, std::string a7)
+{
+  AddArgument (a0);
+  AddArgument (a1);
+  AddArgument (a2);
+  AddArgument (a3);
+  AddArgument (a4);
+  AddArgument (a5);
+  AddArgument (a6);
+  AddArgument (a7);
+}
+void DceApplicationHelper::ParseArguments (std::string args)
+{
+  std::string::size_type cur = 0, next = 0;
+  cur = args.find_first_not_of (" ", 0); // skip initial spaces
+  next = args.find (" ", cur); // next space
+  while (next != std::string::npos)
+    {
+      AddArgument (args.substr (cur, next - cur));
+      cur = args.find_first_not_of (" ", next); // skip spaces
+      next = args.find (" ", cur); // next space
+    }
+  AddArgument (args.substr (cur, args.size () - cur));
+}
+void
+DceApplicationHelper::ResetArguments (void)
+{
+  m_args.clear ();
+}
+void 
+DceApplicationHelper::AddEnvironment (std::string name, std::string value)
+{
+  m_envs.push_back (std::make_pair (name,value));
+}
+void 
+DceApplicationHelper::ResetEnvironment (void)
+{
+  m_envs.clear ();
+}
+
+ApplicationContainer
+DceApplicationHelper::Install (NodeContainer c)
+{
+  NS_LOG_FUNCTION (this);
+  ApplicationContainer apps;
+  for (NodeContainer::Iterator j = c.Begin (); j != c.End (); ++j)
+    {
+      Ptr<DceApplication> dce = CreateObject<DceApplication> ();
+      dce->SetBinary (m_filename);
+      dce->SetStackSize (m_stackSize);
+      dce->SetArguments (m_args);
+      dce->SetEnvironment (m_envs);
+      (*j)->AddApplication (dce);
+      apps.Add (dce);
+    }
+  return apps;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/helper/dce-application-helper.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,45 @@
+#ifndef DCE_HELPER_H
+#define DCE_HELPER_H
+
+#include <string>
+#include <stdint.h>
+#include <vector>
+#include "ns3/node-container.h"
+#include "ns3/application-container.h"
+
+namespace ns3 {
+
+class DceApplicationHelper
+{
+public:
+  DceApplicationHelper ();
+  void SetBinary (std::string filename);
+  void SetStackSize (uint32_t stackSize);
+  void AddArgument (std::string arg);
+  void AddArguments (std::string a0, std::string a1);
+  void AddArguments (std::string a0, std::string a1, std::string a2);
+  void AddArguments (std::string a0, std::string a1, std::string a2, std::string a3);
+  void AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+		     std::string a4);
+  void AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+		     std::string a4, std::string a5);
+  void AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+		     std::string a4, std::string a5, std::string a6);
+  void AddArguments (std::string a0, std::string a1, std::string a2, std::string a3,
+		     std::string a4, std::string a5, std::string a6, std::string a7);
+  void ParseArguments (std::string args);
+  void ResetArguments (void);
+  void AddEnvironment (std::string name, std::string value);
+  void ResetEnvironment (void);
+  ApplicationContainer Install (NodeContainer c);
+private:
+  bool m_isBinary;
+  std::string m_filename;
+  uint32_t m_stackSize;
+  std::vector<std::string> m_args;
+  std::vector<std::pair<std::string,std::string> > m_envs;
+};
+
+} // namespace ns3
+
+#endif /* DCE_HELPER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/helper/dce-manager-helper.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,73 @@
+#include "dce-manager-helper.h"
+#include "ns3/dce-manager.h"
+#include "ns3/socket-fd-factory.h"
+#include "ns3/task-scheduler.h"
+#include "ns3/task-manager.h"
+#include "ns3/loader-factory.h"
+#include "ns3/random-variable.h"
+#include "ns3/uinteger.h"
+
+namespace ns3 {
+
+UniformVariable g_firstPid;
+
+DceManagerHelper::DceManagerHelper ()
+{
+  m_loaderFactory.SetTypeId ("ns3::DlmLoaderFactory");
+  m_taskManagerFactory.SetTypeId ("ns3::TaskManager");
+  m_schedulerFactory.SetTypeId ("ns3::RrTaskScheduler");
+  m_managerFactory.SetTypeId ("ns3::DceManager");
+  m_networkStackFactory.SetTypeId ("ns3::Ns3SocketFdFactory");
+}
+void 
+DceManagerHelper::SetScheduler (std::string type, 
+				    std::string n0, const AttributeValue &v0,
+				    std::string n1, const AttributeValue &v1)
+{
+  m_schedulerFactory.SetTypeId (type);
+  m_schedulerFactory.Set (n0, v0);
+  m_schedulerFactory.Set (n1, v1);
+}
+void 
+DceManagerHelper::SetTaskManagerAttribute (std::string n0, const AttributeValue &v0)
+{
+  m_taskManagerFactory.Set (n0, v0);
+}
+void 
+DceManagerHelper::SetLoader (std::string type)
+{
+  m_loaderFactory.SetTypeId (type);
+}
+void 
+DceManagerHelper::SetNetworkStack (std::string type,
+				       std::string n0, const AttributeValue &v0)
+{
+  m_networkStackFactory.SetTypeId (type);
+  m_networkStackFactory.Set (n0, v0);
+}
+void 
+DceManagerHelper::SetAttribute (std::string n1, const AttributeValue &v1)
+{
+  m_managerFactory.Set (n1, v1);
+}
+void
+DceManagerHelper::Install (NodeContainer nodes)
+{
+  for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
+    {
+      Ptr<DceManager> manager = m_managerFactory.Create<DceManager> ();
+      Ptr<TaskManager> taskManager = m_taskManagerFactory.Create<TaskManager> ();
+      Ptr<TaskScheduler> scheduler = m_schedulerFactory.Create<TaskScheduler> ();
+      Ptr<LoaderFactory> loader = m_loaderFactory.Create<LoaderFactory> ();
+      Ptr<SocketFdFactory> networkStack = m_networkStackFactory.Create<SocketFdFactory> ();
+      taskManager->SetScheduler (scheduler);
+      manager->SetAttribute ("FirstPid", UintegerValue (g_firstPid.GetInteger (0, 0xffff)));
+      Ptr<Node> node = *i;
+      node->AggregateObject (taskManager);
+      node->AggregateObject (loader);
+      node->AggregateObject (manager);
+      node->AggregateObject (networkStack);
+    }
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/helper/dce-manager-helper.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,34 @@
+#ifndef DCE_MANAGER_HELPER_H
+#define DCE_MANAGER_HELPER_H
+
+#include "ns3/object-factory.h"
+#include "ns3/attribute.h"
+#include "ns3/node-container.h"
+#include <string>
+
+namespace ns3 {
+
+class DceManagerHelper
+{
+public:
+  DceManagerHelper ();
+  void SetScheduler (std::string type, 
+		     std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (),
+		     std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue ());
+  void SetTaskManagerAttribute (std::string n0, const AttributeValue &v0);
+  void SetLoader (std::string type);
+  void SetNetworkStack (std::string type,
+			std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue ());
+  void SetAttribute (std::string n1, const AttributeValue &v1);
+  void Install (NodeContainer nodes);
+private:
+  ObjectFactory m_loaderFactory;
+  ObjectFactory m_schedulerFactory;
+  ObjectFactory m_taskManagerFactory;
+  ObjectFactory m_managerFactory;
+  ObjectFactory m_networkStackFactory;
+};
+
+} // namespace ns3
+
+#endif /* DCE_MANAGER_HELPER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/helper/wscript	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,17 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    helper = bld.create_ns3_module('dce-helper', ['internet-stack', 'wifi', 'point-to-point', 'csma', 'olsr', 
+                                                  'global-routing', 'onoff', 'packet-sink', 'udp-echo',
+                                                  'dce', 'spectrum', 'helper'])
+    helper.source = [
+        'dce-manager-helper.cc',
+        'dce-application-helper.cc',
+        ]
+
+    headers = bld.new_task_gen('ns3header')
+    headers.module = 'helper'
+    headers.source = [
+        'dce-manager-helper.h',
+        'dce-application-helper.h',
+        ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/alloc.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,225 @@
+#include "alloc.h"
+#include <string.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include "ns3/assert.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("Alloc");
+
+#ifdef HAVE_VALGRIND_H
+# include "valgrind/valgrind.h"
+# include "valgrind/memcheck.h"
+# define REPORT_MALLOC(buffer, size) \
+  VALGRIND_MALLOCLIKE_BLOCK (buffer,size, 0, 0)
+# define REPORT_FREE(buffer) \
+  VALGRIND_FREELIKE_BLOCK (buffer, 0)
+# define MARK_DEFINED(buffer, size)				\
+  VALGRIND_MAKE_MEM_DEFINED(buffer, size)
+# define MARK_UNDEFINED(buffer, size)			\
+  VALGRIND_MAKE_MEM_UNDEFINED(buffer, size)
+#else
+# define REPORT_MALLOC(buffer, size)
+# define REPORT_FREE(buffer)
+# define MARK_DEFINED(buffer, size)
+# define MARK_UNDEFINED(buffer, size)
+#endif
+
+Alloc::~Alloc ()
+{}
+
+StupidAlloc::StupidAlloc ()
+{
+  NS_LOG_FUNCTION (this);
+}
+StupidAlloc::~StupidAlloc ()
+{
+  NS_LOG_FUNCTION (this);
+  for (std::list<uint8_t *>::iterator i = m_alloced.begin (); i != m_alloced.end (); ++i)
+    {
+      ::free (*i);
+    }
+}
+uint8_t *
+StupidAlloc::Malloc (uint32_t size)
+{
+  NS_LOG_FUNCTION (this << size);
+  uint8_t *buffer = (uint8_t*)::malloc (size);
+  m_alloced.push_back (buffer);
+  return buffer;
+}
+void 
+StupidAlloc::Free (uint8_t *buffer, uint32_t size)
+{
+  NS_LOG_FUNCTION (this << (void*)buffer << size);
+  ::free ((uint8_t*)buffer);
+  m_alloced.remove (buffer);
+}
+uint8_t *
+StupidAlloc::Realloc(uint8_t *oldBuffer, uint32_t oldSize, uint32_t newSize)
+{
+  NS_LOG_FUNCTION (this << (void*)oldBuffer << oldSize << newSize);
+  uint8_t *newBuffer = (uint8_t*)::realloc ((void*)oldBuffer, newSize);
+  if (newBuffer != oldBuffer)
+    {
+      m_alloced.remove (oldBuffer);
+      m_alloced.push_back (newBuffer);
+    }
+  return newBuffer;
+}
+
+KingsleyAlloc::KingsleyAlloc ()
+  : m_defaultMmapSize (1<<15)
+{
+  NS_LOG_FUNCTION (this);
+  memset(m_buckets, 0, sizeof(m_buckets));
+}
+KingsleyAlloc::~KingsleyAlloc ()
+{
+  NS_LOG_FUNCTION (this);
+  for (std::list<struct KingsleyAlloc::MmapChunk>::iterator i = m_chunks.begin ();
+       i != m_chunks.end (); ++i)
+    {
+      MmapFree (i->buffer, i->size);
+    }
+  m_chunks.clear ();
+}
+
+void
+KingsleyAlloc::MmapFree (uint8_t *buffer, uint32_t size)
+{
+  NS_LOG_FUNCTION (this << (void*)buffer << size);
+  int status;
+  status = ::munmap (buffer, size);
+  NS_ASSERT_MSG (status == 0, "Unable to release mmaped buffer");
+}
+void
+KingsleyAlloc::MmapAlloc (uint32_t size)
+{
+  NS_LOG_FUNCTION (this << size);
+  struct MmapChunk chunk;
+  chunk.size = size;
+  chunk.brk = 0;
+  chunk.buffer = (uint8_t*)::mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  NS_ASSERT_MSG (chunk.buffer != MAP_FAILED, "Unable to mmap memory buffer");
+  m_chunks.push_front (chunk);
+  NS_LOG_DEBUG ("mmap alloced=" << size << " at=" << (void*)chunk.buffer);
+  MARK_UNDEFINED (chunk.buffer, size);
+}
+
+uint8_t *
+KingsleyAlloc::Brk (uint32_t needed)
+{
+  NS_LOG_FUNCTION (this << needed);
+  for (std::list<struct KingsleyAlloc::MmapChunk>::iterator i = m_chunks.begin ();
+       i != m_chunks.end (); ++i)
+    {
+      NS_ASSERT (i->size >= i->brk);
+      if (i->size - i->brk >= needed)
+	{
+	  uint8_t *buffer = i->buffer + i->brk;
+	  i->brk += needed;
+	  NS_LOG_DEBUG ("brk: needed=" << needed << ", left=" << i->size - i->brk);
+	  return buffer;
+	}
+    }
+  NS_ASSERT_MSG (needed <= m_defaultMmapSize, needed << " " << m_defaultMmapSize);
+  MmapAlloc (m_defaultMmapSize);
+  return Brk (needed);
+}
+uint8_t 
+KingsleyAlloc::SizeToBucket (uint32_t sz)
+{
+  NS_LOG_FUNCTION (this << sz);
+  uint8_t bucket = 0;
+  uint32_t size = sz;
+  size--;
+  while (size > 7)
+    {
+      size >>= 1;
+      bucket++;
+    }
+  NS_ASSERT (bucket < 32);
+  NS_LOG_DEBUG ("size=" << sz << ", bucket=" << (uint32_t)bucket << ", size=" << BucketToSize (bucket));
+  return bucket;
+}
+uint32_t
+KingsleyAlloc::BucketToSize (uint8_t bucket)
+{
+  uint32_t size = (1<<(bucket+3));
+  return size;
+}
+
+uint8_t * 
+KingsleyAlloc::Malloc (uint32_t size)
+{
+  NS_LOG_FUNCTION (this << size);
+  if (size < m_defaultMmapSize)
+    {
+      uint8_t bucket = SizeToBucket (size);
+      if (m_buckets[bucket] == 0)
+	{
+	  struct Available *avail = (struct Available *)Brk (BucketToSize (bucket));
+	  MARK_DEFINED(avail, sizeof(void*));
+	  avail->next = 0;
+	  MARK_UNDEFINED(avail, sizeof(void*));
+	  m_buckets[bucket] = avail;
+	}
+      // fast path.
+      struct Available *avail = m_buckets[bucket];
+      MARK_DEFINED(avail, sizeof(void*));
+      m_buckets[bucket] = avail->next;
+      MARK_UNDEFINED(avail, sizeof(void*));
+      REPORT_MALLOC(avail, size);
+      return (uint8_t*)avail;
+    }
+  else
+    {
+      MmapAlloc (size);
+      uint8_t *buffer = Brk (size);
+      REPORT_MALLOC(buffer, size);
+      return buffer;
+    }
+}
+void 
+KingsleyAlloc::Free (uint8_t *buffer, uint32_t size)
+{
+  NS_LOG_FUNCTION (this << (void*)buffer << size);
+  if (size < m_defaultMmapSize)
+    {
+      // return to bucket list.
+      uint8_t bucket = SizeToBucket (size);
+      struct Available *avail = (struct Available *)buffer;
+      avail->next = m_buckets[bucket];
+      m_buckets[bucket] = avail;
+      REPORT_FREE(buffer);
+    }
+  else
+    {
+      for (std::list<struct KingsleyAlloc::MmapChunk>::iterator i = m_chunks.begin ();
+	   i != m_chunks.end (); ++i)
+	{
+	  if (i->buffer == buffer && i->size == size)
+	    {
+	      REPORT_FREE(buffer);
+	      MmapFree (buffer, size);
+	      return;
+	    }
+	}
+      // this should never happen but it happens in case of a double-free
+      REPORT_FREE(buffer);
+    }
+}
+uint8_t *
+KingsleyAlloc::Realloc(uint8_t *oldBuffer, uint32_t oldSize, uint32_t newSize)
+{
+  NS_LOG_FUNCTION (this << (void*)oldBuffer << oldSize << newSize);
+  if (newSize < oldSize)
+    {
+      return oldBuffer;
+    }
+  uint8_t *newBuffer = Malloc (newSize);
+  memcpy (newBuffer, oldBuffer, oldSize);
+  Free (oldBuffer, oldSize);
+  return newBuffer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/alloc.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,62 @@
+#ifndef ALLOC_H
+#define ALLOC_H
+
+#include <stdint.h>
+#include <list>
+
+class Alloc
+{
+public:
+  virtual ~Alloc () = 0;
+  virtual uint8_t * Malloc (uint32_t size) = 0;
+  virtual void Free (uint8_t *buffer, uint32_t size) = 0;
+  virtual uint8_t *Realloc(uint8_t *oldBuffer, uint32_t oldSize, uint32_t newSize) = 0;
+private:
+};
+
+class StupidAlloc : public Alloc
+{
+public:
+  StupidAlloc ();
+  virtual ~StupidAlloc ();
+
+  virtual uint8_t * Malloc (uint32_t size);
+  virtual void Free (uint8_t *buffer, uint32_t size);
+  virtual uint8_t *Realloc(uint8_t *oldBuffer, uint32_t oldSize, uint32_t newSize);
+private:
+  std::list<uint8_t *> m_alloced;
+};
+
+class KingsleyAlloc : public Alloc
+{
+public:
+  KingsleyAlloc (void);
+  virtual ~KingsleyAlloc ();
+
+  virtual uint8_t * Malloc (uint32_t size);
+  virtual void Free (uint8_t *buffer, uint32_t size);
+  virtual uint8_t *Realloc(uint8_t *oldBuffer, uint32_t oldSize, uint32_t newSize);
+private:
+  struct MmapChunk
+  {
+    uint8_t *buffer;
+    uint32_t size;
+    uint32_t brk;
+  };
+  struct Available
+  {
+    struct Available *next;
+  };
+  void MmapAlloc (uint32_t size);
+  void MmapFree (uint8_t *buffer, uint32_t size);
+  uint8_t *Brk (uint32_t needed);
+  uint8_t SizeToBucket (uint32_t size);
+  uint32_t BucketToSize (uint8_t bucket);
+  
+  std::list<struct KingsleyAlloc::MmapChunk> m_chunks;
+  struct Available *m_buckets[32];
+  uint32_t m_defaultMmapSize;
+};
+
+
+#endif /* ALLOC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/arpa/simu-inet.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,17 @@
+#ifndef SIMU_INET_H
+#define SIMU_INET_H
+
+#include <arpa/inet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *simu_inet_ntop(int af, const void *src,
+			   char *dst, socklen_t cnt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_INET_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/cmsg.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,62 @@
+#include "cmsg.h"
+#include <sys/socket.h>
+#include <string.h>
+
+namespace ns3 {
+
+Cmsg::Cmsg (struct msghdr *msg)
+  : m_msg (msg),
+    m_current ((uint8_t *)msg->msg_control),
+    m_len (msg->msg_controllen)
+{}
+void 
+Cmsg::Add (int level, int type, int len, const uint8_t *buffer)
+{
+  int cmsglen = CMSG_SPACE (len);
+  if (m_len < cmsglen)
+    {
+      m_msg->msg_flags |= MSG_CTRUNC;
+      return;
+    }
+  struct cmsghdr msghdr;
+  msghdr.cmsg_len = cmsglen;
+  msghdr.cmsg_level = level;
+  msghdr.cmsg_type = type;
+  memcpy (m_current, &msghdr, sizeof (struct cmsghdr));  
+  memcpy (CMSG_DATA ((struct cmsghdr*)m_current), buffer, cmsglen-sizeof (struct cmsghdr));
+  m_current += cmsglen;
+  m_len -= cmsglen;
+}
+
+
+int
+Cmsg::GetNext(int *level, int *type, int *len, uint8_t **buffer)
+{
+  struct cmsghdr *cm = NULL;
+
+  if (m_len < (int)CMSG_LEN(0))
+    return -1;
+
+  cm = (struct cmsghdr *)m_current;
+  if (cm->cmsg_len == 0 || (int)cm->cmsg_len > m_len)
+    return -(1);
+
+  *level = cm->cmsg_level;
+  *type = cm->cmsg_type;
+  *len = cm->cmsg_len - CMSG_LEN(0);
+  *buffer = CMSG_DATA(cm);
+
+  m_current += CMSG_ALIGN(cm->cmsg_len);
+  m_len -= CMSG_ALIGN(cm->cmsg_len);
+
+  return 0;
+}
+
+void 
+Cmsg::Finish (void)
+{
+  m_msg->msg_controllen -= m_len;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/cmsg.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#include <stdint.h>
+#include <sys/socket.h>
+
+namespace ns3 {
+
+class Cmsg 
+{
+public:
+  Cmsg (struct msghdr *msg);
+  void Add (int level, int type, int len, const uint8_t *buffer);
+  int GetNext(int *level, int *type, int *len, uint8_t **buffer);
+  void Finish (void);
+private:
+  struct msghdr *m_msg;
+  uint8_t *m_current;
+  int m_len;
+};
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/cooja-loader-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,318 @@
+#define _GNU_SOURCE 1
+#include "cooja-loader-factory.h"
+#include "elf-cache.h"
+#include "elf-dependencies.h"
+#include "ns3/log.h"
+#include <string.h>
+#include <dlfcn.h>
+#include <elf.h>
+#include <link.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <list>
+
+namespace {
+struct Template
+{
+  void *buffer;
+  uint32_t id;
+  uint32_t refcount;
+};
+}
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("CoojaLoaderFactory");
+NS_OBJECT_ENSURE_REGISTERED (CoojaLoaderFactory);
+
+struct SharedCoojaNamespace
+{
+  SharedCoojaNamespace ();
+  ~SharedCoojaNamespace ();
+  ElfCache cache;
+  std::list<struct Template *> templates;
+};
+
+class CoojaLoader : public Loader
+{
+public:
+  CoojaLoader ();
+private:
+  struct Module
+  {
+    void *handle;
+    uint32_t refcount;
+    std::list<struct Module *> deps;
+    void *dataPrivateStart;
+    long load_base;
+    ElfCache::ElfCachedFile cached;
+  };
+
+  virtual ~CoojaLoader ();
+  virtual void NotifyStartExecute (void);
+  virtual void NotifyEndExecute (void);
+  virtual void UnloadAll (void);
+  virtual void *Load (std::string filename, int flag);
+  virtual void Unload (void *module);
+  virtual void *Lookup (void *module, std::string symbol);
+
+  static struct SharedCoojaNamespace *Peek (void);
+  struct CoojaLoader::Module *SearchModule (uint32_t id);
+  struct CoojaLoader::Module *LoadModule (std::string filename, int flag);
+  struct Template *SearchTemplate (uint32_t id);
+  void UnrefTemplate (uint32_t id);
+
+  std::list<struct Module *> m_modules;
+};
+
+SharedCoojaNamespace::SharedCoojaNamespace ()
+  : cache ("elf-cache", 0)
+{}
+
+SharedCoojaNamespace::~SharedCoojaNamespace ()
+{
+  for (std::list<struct Template *>::iterator i = templates.begin ();
+       i != templates.end (); ++i)
+    {
+      struct Template *tmpl = *i;
+      free (tmpl->buffer);
+      delete tmpl;
+    }
+  templates.clear ();
+}
+
+struct SharedCoojaNamespace *
+CoojaLoader::Peek (void)
+{
+  static SharedCoojaNamespace ns;
+  return &ns;
+}
+
+void 
+CoojaLoader::NotifyStartExecute (void)
+{
+  // restore the loader private data sections
+  for (std::list<struct Module *>::const_iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      const struct Module *module = *i;
+      memcpy ((void*)(module->load_base + module->cached.data_p_vaddr),
+	      module->dataPrivateStart,
+	      module->cached.data_p_memsz);
+    }
+}
+void 
+CoojaLoader::NotifyEndExecute (void)
+{
+  // save the loader private data sections
+  for (std::list<struct Module *>::const_iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      const struct Module *module = *i;
+      memcpy (module->dataPrivateStart, 
+	      (void *)(module->load_base + module->cached.data_p_vaddr),
+	      module->cached.data_p_memsz);
+    }
+}
+
+void *
+CoojaLoader::Load (std::string filename, int flag)
+{
+  struct Module *module = LoadModule (filename, flag);
+  
+  // acquire ref for client
+  module->refcount++;
+  return module->handle;
+}
+
+struct CoojaLoader::Module *
+CoojaLoader::SearchModule (uint32_t id)
+{
+  for (std::list<struct Module *>::iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      struct Module *module = *i;
+      if (module->cached.id == id)
+	{
+	  // already in, ignore.
+	  return module;
+	}
+    }
+  return 0;
+}
+
+struct Template *
+CoojaLoader::SearchTemplate (uint32_t id)
+{
+  struct SharedCoojaNamespace *ns = Peek ();  
+  for (std::list<struct Template *>::iterator i = ns->templates.begin ();
+       i != ns->templates.end (); ++i)
+    {
+      if ((*i)->id == id)
+	{
+	  return *i;
+	}
+    }
+  return 0;
+}
+
+struct CoojaLoader::Module *
+CoojaLoader::LoadModule (std::string filename, int flag)
+{
+  NS_LOG_FUNCTION (this << filename << flag);
+  struct SharedCoojaNamespace *ns = Peek ();
+  ElfDependencies deps = ElfDependencies (filename);
+  struct Module *module = 0;
+  for (ElfDependencies::Iterator i = deps.Begin (); i != deps.End (); ++i)
+    {
+      ElfCache::ElfCachedFile cached = ns->cache.Add (i->found);
+      module = SearchModule (cached.id);
+      if (module == 0)
+	{
+	  void *handle = dlopen (cached.cachedFilename.c_str (), RTLD_LAZY | RTLD_DEEPBIND | RTLD_LOCAL);
+	  struct link_map *link_map;
+	  dlinfo (handle, RTLD_DI_LINKMAP, &link_map);
+
+	  module = new Module ();
+	  module->cached = cached;
+	  module->handle = handle;
+	  module->refcount = 0; // will be incremented later in ::Load or as a dep below.
+	  module->dataPrivateStart = malloc (cached.data_p_memsz);
+	  struct Template *tmpl = SearchTemplate (cached.id);
+	  if (tmpl == 0)
+	    {
+	      // save the template
+	      NS_LOG_DEBUG ("create template " << cached.id);
+	      tmpl = new Template ();
+	      tmpl->buffer = malloc (cached.data_p_memsz);
+	      tmpl->id = cached.id;
+	      tmpl->refcount = 1;
+	      ns->templates.push_back (tmpl);
+	      memcpy (tmpl->buffer, (void *)(link_map->l_addr + cached.data_p_vaddr),
+		      cached.data_p_memsz);
+	    }
+	  else
+	    {
+	      NS_LOG_DEBUG ("reuse template " << cached.id);
+	      // restore the current state from the template state
+	      tmpl->refcount++;
+	      memcpy ((void *)(link_map->l_addr + cached.data_p_vaddr), 
+		      tmpl->buffer, cached.data_p_memsz);
+	    }
+	  module->load_base = link_map->l_addr;
+	  for (std::vector<uint32_t>::const_iterator j = cached.deps.begin (); j != cached.deps.end (); ++j)
+	    {
+	      struct Module *dep = SearchModule (*j);
+	      dep->refcount++;
+	      module->deps.push_back (dep);
+	    }
+	  m_modules.push_back (module);
+	}
+    }
+  return module;
+}
+void
+CoojaLoader::UnrefTemplate (uint32_t id)
+{
+  NS_LOG_FUNCTION (this << id);
+  struct SharedCoojaNamespace *ns = Peek ();  
+  for (std::list<struct Template *>::iterator i = ns->templates.begin ();
+       i != ns->templates.end (); ++i)
+    {
+      struct Template *tmpl = *i;
+      if (tmpl->id == id)
+	{
+	  tmpl->refcount--;
+	  if (tmpl->refcount == 0)
+	    {
+	      NS_LOG_DEBUG ("delete template " << id);
+	      free (tmpl->buffer);
+	      delete tmpl;
+	      ns->templates.erase (i);
+	    }
+	  break;
+	}
+    }
+}
+void 
+CoojaLoader::UnloadAll (void)
+{
+  NS_LOG_FUNCTION (this);
+  for (std::list<struct Module *>::const_iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      struct Module *module = *i;
+      dlclose (module->handle);
+      UnrefTemplate (module->cached.id);
+      delete module;
+    }
+  m_modules.clear ();
+}
+void 
+CoojaLoader::Unload (void *handle)
+{
+  NS_LOG_FUNCTION (this << handle);
+  for (std::list<struct Module *>::iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      struct Module *module = *i;
+      if (module->handle == handle)
+	{
+	  module->refcount--;
+	  if (module->refcount == 0)
+	    {
+	      m_modules.erase (i);
+	      for (std::list<struct Module *>::iterator j = module->deps.begin (); 
+		   j != module->deps.end (); ++j)
+		{
+		  struct Module *dep = *j;
+		  Unload (dep->handle);
+		}
+	      // close only after unloading the deps.
+	      UnrefTemplate (module->cached.id);
+	      dlclose (module->handle);
+	      delete module;
+	    }
+	  break;
+	}
+    }
+}
+void *
+CoojaLoader::Lookup (void *module, std::string symbol)
+{
+  NS_LOG_FUNCTION (this << module << symbol);
+  void *p = dlsym (module, symbol.c_str ());
+  return p;
+}
+
+CoojaLoader::CoojaLoader ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+CoojaLoader::~CoojaLoader ()
+{
+  NS_LOG_FUNCTION (this);
+  UnloadAll ();
+}
+
+
+TypeId 
+CoojaLoaderFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::CoojaLoaderFactory")
+    .SetParent<LoaderFactory> ()
+    .AddConstructor<CoojaLoaderFactory> ()
+    ;
+  return tid;
+}
+CoojaLoaderFactory::CoojaLoaderFactory ()
+{}
+CoojaLoaderFactory::~CoojaLoaderFactory ()
+{}
+Loader *
+CoojaLoaderFactory::Create (int argc, char **argv, char **envp)
+{
+  CoojaLoader *loader = new CoojaLoader ();
+  return loader;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/cooja-loader-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#ifndef COOJA_LOADER_FACTORY_H
+#define COOJA_LOADER_FACTORY_H
+
+#include "loader-factory.h"
+
+namespace ns3 {
+
+class CoojaLoaderFactory : public LoaderFactory
+{
+ public:
+  static TypeId GetTypeId (void);
+  CoojaLoaderFactory ();
+  virtual ~CoojaLoaderFactory ();
+  virtual Loader *Create (int argc, char **argv, char **envp);
+};
+
+} // namespace ns3
+
+#endif /* COOJA_LOADER_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/copy-loader-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,182 @@
+#include "copy-loader-factory.h"
+#include "elf-cache.h"
+#include "elf-dependencies.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CopyLoaderFactory");
+
+namespace ns3 {
+
+class CopyLoader : public Loader
+{
+public:
+  CopyLoader (uint32_t uid);
+private:
+  struct Module
+  {
+    void *handle;
+    uint32_t refcount;
+    std::list<struct Module *> deps;
+    void *dataPrivateStart;
+    long load_base;
+    ElfCache::ElfCachedFile cached;
+  };
+
+  virtual ~CopyLoader ();
+  virtual void UnloadAll (void);
+  virtual void *Load (std::string filename, int flag);
+  virtual void Unload (void *module);
+  virtual void *Lookup (void *module, std::string symbol);
+
+  struct CopyLoader::Module *SearchModule (uint32_t id);
+  struct CopyLoader::Module *LoadModule (std::string filename, int flag);
+
+  std::list<struct Module *> m_modules;
+  ElfCache m_cache;
+};
+
+void *
+CopyLoader::Load (std::string filename, int flag)
+{
+  struct Module *module = LoadModule (filename, flag);
+  
+  // acquire ref for client
+  module->refcount++;
+  return module->handle;
+}
+
+struct CopyLoader::Module *
+CopyLoader::SearchModule (uint32_t id)
+{
+  for (std::list<struct Module *>::iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      struct Module *module = *i;
+      if (module->cached.id == id)
+	{
+	  // already in, ignore.
+	  return module;
+	}
+    }
+  return 0;
+}
+
+struct CopyLoader::Module *
+CopyLoader::LoadModule (std::string filename, int flag)
+{
+  NS_LOG_FUNCTION (this << filename << flag);
+  ElfDependencies deps = ElfDependencies (filename);
+  struct Module *module = 0;
+  for (ElfDependencies::Iterator i = deps.Begin (); i != deps.End (); ++i)
+    {
+      ElfCache::ElfCachedFile cached = m_cache.Add (i->found);
+      module = SearchModule (cached.id);
+      if (module == 0)
+	{
+	  void *handle = dlopen (cached.cachedFilename.c_str (), RTLD_LAZY | RTLD_DEEPBIND | RTLD_LOCAL);
+	  module = new Module ();
+	  module->cached = cached;
+	  module->handle = handle;
+	  module->refcount = 0; // will be incremented later in ::Load or as a dep below.
+	  for (std::vector<uint32_t>::const_iterator j = cached.deps.begin (); j != cached.deps.end (); ++j)
+	    {
+	      struct Module *dep = SearchModule (*j);
+	      dep->refcount++;
+	      module->deps.push_back (dep);
+	    }
+	  m_modules.push_back (module);
+	}
+    }
+  return module;
+}
+void 
+CopyLoader::UnloadAll (void)
+{
+  NS_LOG_FUNCTION (this);
+  for (std::list<struct Module *>::const_iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      struct Module *module = *i;
+      dlclose (module->handle);
+      delete module;
+    }
+  m_modules.clear ();
+}
+void 
+CopyLoader::Unload (void *handle)
+{
+  NS_LOG_FUNCTION (this << handle);
+  for (std::list<struct Module *>::iterator i = m_modules.begin (); i != m_modules.end (); ++i)
+    {
+      struct Module *module = *i;
+      if (module->handle == handle)
+	{
+	  module->refcount--;
+	  if (module->refcount == 0)
+	    {
+	      m_modules.erase (i);
+	      for (std::list<struct Module *>::iterator j = module->deps.begin (); 
+		   j != module->deps.end (); ++j)
+		{
+		  struct Module *dep = *j;
+		  Unload (dep->handle);
+		}
+	      // close only after unloading the deps.
+	      dlclose (module->handle);
+	      delete module;
+	    }
+	  break;
+	}
+    }
+}
+void *
+CopyLoader::Lookup (void *module, std::string symbol)
+{
+  NS_LOG_FUNCTION (this << module << symbol);
+  void *p = dlsym (module, symbol.c_str ());
+  return p;
+}
+
+CopyLoader::CopyLoader (uint32_t uid)
+  : m_cache ("elf-cache", uid)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+CopyLoader::~CopyLoader ()
+{
+  NS_LOG_FUNCTION (this);
+  UnloadAll ();
+}
+
+
+NS_OBJECT_ENSURE_REGISTERED(CopyLoaderFactory);
+
+TypeId 
+CopyLoaderFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::CopyLoaderFactory")
+    .SetParent<LoaderFactory> ()
+    .AddConstructor<CopyLoaderFactory> ()
+    ;
+  return tid;
+}
+CopyLoaderFactory::CopyLoaderFactory ()
+{}
+CopyLoaderFactory::~CopyLoaderFactory ()
+{}
+Loader *
+CopyLoaderFactory::Create (int argc, char **argv, char **envp)
+{
+  // note: we ignore argc and co in this implementation.
+  uint32_t uid = AllocateUid ();
+  CopyLoader *loader = new CopyLoader (uid);
+  return loader;
+}
+uint32_t
+CopyLoaderFactory::AllocateUid (void)
+{
+  static uint32_t uid = 0;
+  uid++;
+  return uid;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/copy-loader-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,81 @@
+#ifndef COPY_LOADER_FACTORY_H
+#define COPY_LOADER_FACTORY_H
+
+#include "loader-factory.h"
+
+#include <string>
+#include <list>
+#include <stdint.h>
+
+namespace ns3 {
+
+/**
+ * The goal of the elf loader is two-fold:
+ *   1) it must virtualize the global data of a program when it is 
+ *     loaded in memory (as well as the global data of each of the libraries
+ *     the main binary depends on)
+ *   2) it must allow you to replace the system libc with a new libc
+ *     which forwards all socket calls to per-node simulation sockets.
+ *
+ * In ELF systems, all per-binary global data is accessed as relative offsets
+ * from the base address of the code so, all you need to do to virtualize
+ * the data global data area (that is, achieve 1) of a binary is to load 
+ * it multiple times in memory and, each time, at a different base address. 
+ *
+ * To replace the system libc, you need to make the ELF loader look for a
+ * libc.so.6 in a new location.
+ *
+ * Achieving both of the above could be done by re-implementing a new ELF 
+ * loader or by using a modified version of the glibc ELF loader. The latter
+ * is much harder than it seems and the former would require quite a bit of
+ * platform-specific code so, this class implements another option which is
+ * to trick the normal glibc ELF loader into doing just what we need, that is:
+ *   - allow us to load the same binary multiple times in memory
+ *   - allow us to replace the libc binary.
+ *
+ * By default, when you request to load the same binary twice with dlopen,
+ * the loader is very smart and figures out that the requested file is the same
+ * that is, it has the same inode. So to trick the loader into loading the
+ * file twice (or more), we have to load the same file with a different inode
+ * and the only way to do this is to physically copy the file on the hard disk
+ * before loading it.
+ *
+ * To ensure that we can precisely control which libraries are (re)loaded in 
+ * memory and that we can thus replace the system libc with a simulation libc,
+ * we also modify the copied elf files by changing the set of libraries they 
+ * depend upon. To do this, we have to change the values referenced by the
+ * DT_NEEDED entries of the SHT_DYNAMIC section. Unfortunately, we can't just
+ * add a new string table section, copy the data from the old string table 
+ * section, and add new entries for the new filenames because doing this
+ * would require a lot of ajustement to the elf data structures. So, instead,
+ * we edit in-place the content of the string table pointed to by DT_STRTAB and,
+ * to do this successfully, we need to make sure that the new filenames have
+ * the exact same length in bytes as the old filenames: if they are not the
+ * same length, we would have to adjust the elf data structures quite a bit.
+ *
+ * So, we choose the name of each new file based on a unique 3-letter prefix
+ * which replaces the first 3 letters of the original file. The 3-letter prefix
+ * is an ascii representation of a 3-unit base 60 number which potentially allows
+ * us to load up to 60^3 elf binaries with unique filenames.
+ *
+ * Note that the biggest problem with this loader is that it's not possible to
+ * make it force unloading a library without running its fini functions
+ * which brings a host of problems when ns3::DceManager needs to terminate
+ * a process.
+ */
+class CopyLoaderFactory : public LoaderFactory
+{
+public:
+  static TypeId GetTypeId (void);
+
+  CopyLoaderFactory ();
+  virtual ~CopyLoaderFactory ();
+  virtual Loader *Create (int argc, char **argv, char **envp);
+
+private:
+  static uint32_t AllocateUid (void);
+};
+
+} // namespace ns3
+
+#endif /* COPY_LOADER_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/dce-application.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,90 @@
+#include "dce-application.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/dce-manager.h"
+#include "ns3/trace-source-accessor.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("DceApplication");
+NS_OBJECT_ENSURE_REGISTERED (DceApplication);
+
+TypeId 
+DceApplication::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::DceApplication")
+    .SetParent<Application> ()
+    .AddConstructor<DceApplication> ()
+    .AddTraceSource ("DceStarted", "notify when the dce is started",
+		     MakeTraceSourceAccessor (&DceApplication::m_dceStarted))
+    ;
+  return tid;
+}
+
+DceApplication::DceApplication ()
+  : m_stackSize (0),
+    m_pid (0)
+{}
+DceApplication::~DceApplication ()
+{}
+
+void
+DceApplication::DoDispose (void)
+{
+  NS_LOG_FUNCTION (this);
+  Application::DoDispose ();
+}
+void 
+DceApplication::SetBinary (std::string filename)
+{
+  m_filename = filename;
+}
+void 
+DceApplication::SetStackSize (uint32_t stackSize)
+{
+  m_stackSize = stackSize;
+}
+void 
+DceApplication::SetArguments (std::vector<std::string> args)
+{
+  m_args = args;
+}
+
+void 
+DceApplication::SetEnvironment (std::vector<std::pair<std::string,std::string> > envs)
+{
+  m_envs = envs;
+}
+
+void 
+DceApplication::StartApplication (void)
+{
+  NS_LOG_FUNCTION (this);
+
+  Ptr<Node> node = GetNode ();
+  Ptr<DceManager> manager = node->GetObject<DceManager> ();
+  if (manager == 0)
+    {
+      NS_FATAL_ERROR ("You forgot to aggregate a DceManager to node=" << node->GetId ());
+    }
+  if (m_stackSize != 0)
+    {
+      m_pid = manager->Start (m_filename, m_stackSize, m_args, m_envs);
+    } 
+  else
+    {
+      m_pid = manager->Start (m_filename, m_args, m_envs);
+    }
+  m_dceStarted (m_pid);
+}
+void 
+DceApplication::StopApplication (void)
+{
+  NS_LOG_FUNCTION (this);
+  Ptr<Node> node = GetNode ();
+  Ptr<DceManager> manager = node->GetObject<DceManager> ();
+  manager->Stop (m_pid);
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/dce-application.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,52 @@
+#ifndef DCE_APPLICATION_H
+#define DCE_APPLICATION_H
+
+#include "ns3/application.h"
+#include "ns3/traced-callback.h"
+
+namespace ns3 {
+
+/**
+ * \brief a wrapper around a posix synchronous application.
+ *
+ * The sole purpose of this class is to allow users to manipulate
+ * these posix synchronous applications in their scripts as if they
+ * were normal ns-3 applications and to start them at a specific
+ * time using the normal ApplicationContainer::Start method.
+ *
+ * To implement the Stop method, we send a SIGKILL signal to the
+ * target application. Note that doing this will make it impossible
+ * to deal correctly with the application's memory management. i.e.,
+ * once you call Stop on such an application, valgrind will most
+ * likely start reporting a lot of lost memory. Crashes might ensue.
+ */
+class DceApplication : public Application
+{
+public:
+  static TypeId GetTypeId (void);
+
+  DceApplication ();
+  virtual ~DceApplication ();
+
+  void SetBinary (std::string filename);
+  void SetStackSize (uint32_t stackSize);
+  void SetArguments (std::vector<std::string> args);
+  void SetEnvironment (std::vector<std::pair<std::string,std::string> > envs);
+
+private:
+  // inherited from Application base class.
+  virtual void StartApplication (void);
+  virtual void StopApplication (void);
+  virtual void DoDispose (void);
+
+  std::string m_filename;
+  uint32_t m_stackSize;
+  std::vector<std::string> m_args;
+  std::vector<std::pair<std::string,std::string> > m_envs;
+  uint16_t m_pid;
+  TracedCallback<uint16_t> m_dceStarted;
+};
+
+} // namespace ns3
+
+#endif /* DCE_APPLICATION_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/dce-manager-test.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,120 @@
+#include "ns3/test.h"
+#include "ns3/node.h"
+#include "ns3/simulator.h"
+#include "ns3/uinteger.h"
+#include "dce-manager.h"
+#include "task-manager.h"
+#include "rr-task-scheduler.h"
+#include "dlm-loader-factory.h"
+
+static std::string g_testError;
+
+extern "C" void dce_manager_test_store_test_error (const char *s)
+{
+  g_testError = s;
+}
+
+
+namespace ns3 {
+
+
+
+class DceManagerTestCase : public TestCase
+{
+public:
+  DceManagerTestCase (std::string filename);
+private:
+  virtual bool DoRun (void);
+  Ptr<DceManager> CreateManager (int *pstatus);
+  void StartApplication (Ptr<DceManager> manager, int *pstatus);
+  static void Finished (int *pstatus, uint16_t pid, int status);
+
+  std::string m_filename;
+};
+
+DceManagerTestCase::DceManagerTestCase (std::string filename)
+  : TestCase ("Check that process \"" + filename + "\" completes correctly."),
+    m_filename (filename)
+{}
+void
+DceManagerTestCase::StartApplication (Ptr<DceManager> manager, int *pstatus)
+{
+  std::vector<std::string> noargs;
+  std::vector<std::pair<std::string,std::string> > noenv;
+  
+  uint16_t pid = manager->Start (m_filename, 1<<20, noargs, noenv);
+  manager->SetFinishedCallback (pid, MakeBoundCallback (&DceManagerTestCase::Finished, pstatus));
+}
+Ptr<DceManager> 
+DceManagerTestCase::CreateManager (int *pstatus)
+{
+  Ptr<Node> a = CreateObject<Node> ();
+  Ptr<TaskManager> taskManager = CreateObject<TaskManager> ();
+  Ptr<TaskScheduler> taskScheduler = CreateObject<RrTaskScheduler> ();
+  Ptr<DceManager> aManager = CreateObject<DceManager> ();
+  Ptr<LoaderFactory> loaderFactory = CreateObject<DlmLoaderFactory> ();
+  taskManager->SetScheduler (taskScheduler);
+  a->AggregateObject (loaderFactory);
+  a->AggregateObject (taskManager);
+  a->AggregateObject (aManager);
+  Simulator::ScheduleWithContext (a->GetId (), Seconds (0.0),
+				  &DceManagerTestCase::StartApplication, this, 
+				  aManager, pstatus);
+  return aManager;
+}
+void
+DceManagerTestCase::Finished (int *pstatus, uint16_t pid, int status)
+{
+  *pstatus = status;
+}
+bool
+DceManagerTestCase::DoRun (void)
+{
+  int status = - 1;
+  Ptr<DceManager> a = CreateManager (&status);
+  Simulator::Run ();
+  Simulator::Destroy ();
+  NS_TEST_ASSERT_MSG_EQ (status, 0, "Process did not return successfully: " << g_testError);
+  return status != 0;
+}
+
+static class DceManagerTestSuite : public TestSuite
+{
+public:
+  DceManagerTestSuite ();
+private:
+} g_processTests;
+
+DceManagerTestSuite::DceManagerTestSuite ()
+  : TestSuite ("process-manager", UNIT)
+{
+  const char *tests [] = {
+  "test-empty",
+  "test-sleep",
+  "test-pthread",
+  "test-mutex",
+  "test-once",
+  "test-pthread-key",
+  "test-sem",
+  "test-malloc",
+  "test-malloc-2",
+  "test-fd-simple",
+  "test-strerror",
+  "test-stdio",
+  "test-string",
+  "test-netdb",
+  "test-env",
+  "test-cond",
+  "test-timer-fd",
+  "test-stdlib",
+  "test-select",
+  "test-nanosleep",
+  "test-random",
+  };
+  for (unsigned int i = 0; i < sizeof(tests)/sizeof(char*);i++)
+    {
+      AddTestCase (new DceManagerTestCase (tests[i]));
+    }
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/dce-manager.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,668 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2008 INRIA
+ *
+ * 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 "dce-manager.h"
+#include "process.h"
+#include "task-manager.h"
+#include "libc-simu.h"
+#include "unix-fd.h"
+#include "unix-file-fd.h"
+#include "utils.h"
+#include "alloc.h"
+#include "simu-stdio.h"
+#include "simu-unistd.h"
+#include "simu-pthread.h"
+#include "simu-fcntl.h"
+#include "sys/simu-stat.h"
+#include "system-wrappers.h"
+#include "loader-factory.h"
+#include "ns3/node.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/packet.h"
+#include "ns3/ptr.h"
+#include "ns3/uinteger.h"
+#include "ns3/boolean.h"
+#include "ns3/trace-source-accessor.h"
+#include "ns3/enum.h"
+
+#include <errno.h>
+#include <dlfcn.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+
+
+NS_LOG_COMPONENT_DEFINE ("DceManager");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (DceManager);
+
+TypeId 
+DceManager::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::DceManager")
+    .SetParent<Object> ()
+    .AddConstructor<DceManager> ()
+    .AddTraceSource ("Exit", "A process has exited",
+                     MakeTraceSourceAccessor (&DceManager::m_processExit))
+    .AddAttribute ("FirstPid", "The PID used by default when creating a process in this manager.",
+                   UintegerValue (1),
+                   MakeUintegerAccessor (&DceManager::m_nextPid),
+                   MakeUintegerChecker<uint16_t> ())
+    ;
+  return tid;
+}
+
+DceManager::DceManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+DceManager::~DceManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+void
+DceManager::DoDispose (void)
+{
+  NS_LOG_FUNCTION (this);
+  struct Process *tmp;
+  while (!m_processes.empty ())
+    {
+      tmp = m_processes.back ();
+      DeleteProcess (tmp);
+    }
+
+  Object::DoDispose ();
+}
+
+struct ::Libc *
+DceManager::GetLibc (void)
+{
+  static bool initialized = false;
+  static struct ::Libc libc;
+  if (initialized)
+    {
+      return &libc;
+    }
+  initialized = true;
+  libc_simu (&libc);
+  return &libc;
+}
+
+void
+DceManager::EnsureDirectoryExists (struct Thread *current, std::string dirName)
+{
+  int fd = simu_open (dirName.c_str(), O_DIRECTORY | O_RDONLY, 0);
+  if (fd != -1)
+    {
+      simu_close (fd);
+    }
+  else if (current->err == ENOENT)
+    {
+      int status = simu_mkdir (dirName.c_str (), S_IRWXU | S_IRWXG);
+      if (status == -1)
+	{
+	  NS_FATAL_ERROR ("Could not create directory " << dirName
+			  << ": " << strerror (current->err));
+	}
+    }
+  else
+    {
+      NS_FATAL_ERROR ("Could not open \"" << dirName << "\"");
+    }
+}
+
+int
+DceManager::CreatePidFile (struct Thread *current, std::string filename)
+{
+  EnsureDirectoryExists (current, "/var");
+  EnsureDirectoryExists (current, "/var/log");
+  std::ostringstream oss;
+  oss << "/var/log/" << current->process->pid;
+  std::string pidDirName = oss.str();
+  EnsureDirectoryExists (current, oss.str());
+  oss << "/" << filename;
+  std::string s = oss.str();
+  int fd = simu_creat (s.c_str (), S_IWUSR | S_IRUSR);
+  return fd;
+}
+
+void
+DceManager::DoStartProcess (void *context)
+{
+  struct ::Libc *libc = GetLibc ();
+
+  Thread *current = (Thread *)context;
+  // create fd 0
+  UnixFd *unixFd = new TermUnixFileFd (0);
+  current->process->openFiles.push_back (std::make_pair(0,unixFd));
+  // create fd 1
+  int fd = CreatePidFile (current, "stdout");
+  NS_ASSERT (fd == 1);
+  // create fd 2
+  fd = CreatePidFile (current, "stderr");
+  NS_ASSERT (fd == 2);
+
+  fd = CreatePidFile (current, "cmdline");
+  for (int i = 0; i < current->process->originalArgc; i++)
+    {
+      char *cur = current->process->originalArgv[i];
+      simu_write (fd, cur, strlen (cur));
+      simu_write (fd, " ", 1);
+    }
+  simu_write (fd, "\n", 1);
+  simu_close (fd);
+  NS_ASSERT (fd == 3);
+
+  void *h = current->process->loader->Load ("libc-ns3.so", RTLD_GLOBAL);
+  if (h == 0)
+    {
+      NS_FATAL_ERROR ("Unable to load libc-ns3.so");
+    }
+  void *symbol = current->process->loader->Lookup (h, "libc_setup");
+  if (symbol == 0)
+    {
+      NS_FATAL_ERROR ("This is not our fake libc !");
+    }
+  // construct the libc now
+  void (*libc_setup) (const struct Libc *fn);
+  libc_setup = (void (*) (const struct Libc *))(symbol);
+  libc_setup (libc);
+
+  h = current->process->loader->Load ("libpthread-ns3.so", RTLD_GLOBAL);
+  if (h == 0)
+    {
+      NS_FATAL_ERROR ("Unable to load libpthread-ns3.so");
+    }
+  symbol = current->process->loader->Lookup (h, "libpthread_setup");
+  if (symbol == 0)
+    {
+      NS_FATAL_ERROR ("This is not our fake libpthread !");
+    }
+  // construct libpthread now
+  void (*libpthread_setup) (const struct Libc *fn);
+  libpthread_setup = (void (*) (const struct Libc *))(symbol);
+  libpthread_setup (libc);
+
+  // finally, call into 'main'.
+  h = current->process->loader->Load (current->process->originalArgv[0], RTLD_GLOBAL);
+  current->process->mainHandle = h;
+  symbol = current->process->loader->Lookup (h, "main");
+  int (*main) (int, char **);
+  main = (int (*) (int, char **)) symbol;
+  int retval = main (current->process->originalArgc, current->process->originalArgv);
+  simu_exit (retval);
+}
+
+struct Process *
+DceManager::CreateProcess (std::string name, std::vector<std::string> args,
+                               std::vector<std::pair<std::string,std::string> > envs)
+{
+  struct Process *process = new Process ();
+  process->euid = 0;
+  process->ruid = 0;
+  process->suid = 0;
+  process->egid = 0;
+  process->rgid = 0;
+  process->sgid = 0;
+  process->alloc = new KingsleyAlloc ();
+  process->originalArgv = 0;
+  process->originalArgc = 0;
+  process->originalEnvp = 0;
+  SetArgv (process, name, args);
+  SetEnvp (process, envs);
+  Ptr<LoaderFactory> loaderFactory = this->GetObject<LoaderFactory> ();
+  process->loader = loaderFactory->Create (process->originalArgc, process->originalArgv,
+                                           process->originalEnvp);
+  process->exitValue = 0;
+  process->name = name;
+  process->ppid = 0;
+  process->pid = AllocatePid ();
+  process->manager = this;
+  sigemptyset (&process->pendingSignals);
+  // setup a signal handler for SIGKILL which calls simu_exit.
+  struct SignalHandler handler;
+  handler.signal = SIGKILL;
+  handler.flags = 0;
+  sigemptyset (&handler.mask);
+  handler.handler = &DceManager::SigkillHandler;
+  process->signalHandlers.push_back (handler);
+  // we reserve 0 for the mutex initialized with PTHREAD_MUTEX_INITIALIZER 
+  // we reserve 2 for a destroyed mutex
+  // 1 is such a common value that we try to avoid it.
+  // we unfortunately cannot avoid the value 0 because we 
+  // have to be compatible with the system PHREAD_MUTEX_INITIALIZER
+  // which uses the value 0.
+  process->nextMid = 3;
+  // we reserve 2 for a destroyed mutex
+  // 0 and 1 are such common values that we avoid them.
+  process->nextSid = 3;
+  // we reserve 2 for a destroyed condition variable
+  // 0 and 1 are such common values that we avoid them.
+  process->nextCid = 3;
+  process->cwd = "/";
+  process->pstdin = 0;
+  process->pstdout = 0;
+  process->pstderr = 0;
+  process->penvp = 0;
+
+  //"seeding" random variable
+  process->rndVarible = UniformVariable (0, RAND_MAX);
+  m_processes.push_back (process);
+
+  return process;
+}
+
+void 
+DceManager::TaskSwitch (enum Task::SwitchType type, void *context)
+{
+  Loader *loader = (Loader *)context;
+  switch (type)
+    {
+    case Task::TO:
+      loader->NotifyStartExecute ();
+      break;
+    case Task::FROM:
+      loader->NotifyEndExecute ();
+      break;
+    }
+}
+
+
+uint16_t
+DceManager::Start (std::string name, std::vector<std::string> args,
+                       std::vector<std::pair<std::string,std::string> > envs)
+{
+  NS_LOG_FUNCTION (this << name << args.size ());
+  struct Process *process = CreateProcess (name, args, envs);
+  struct Thread *thread = CreateThread (process);
+  Task *task = TaskManager::Current ()->Start (&DceManager::DoStartProcess, thread);
+  task->SetContext (thread);
+  task->SetSwitchNotifier (&DceManager::TaskSwitch, process->loader);
+  thread->task = task;
+  return process->pid;
+}
+uint16_t
+DceManager::Start (std::string name, uint32_t stackSize, std::vector<std::string> args,
+                       std::vector<std::pair<std::string,std::string> > envs)
+{
+  NS_LOG_FUNCTION (this << name << stackSize << args.size () << envs.size ());
+  struct Process *process = CreateProcess (name, args, envs);
+  struct Thread *thread = CreateThread (process);
+  Task *task = TaskManager::Current ()->Start (&DceManager::DoStartProcess, thread, stackSize);
+  task->SetContext (thread);
+  task->SetSwitchNotifier (&DceManager::TaskSwitch, process->loader);
+  thread->task = task;
+  return process->pid;
+}
+
+
+uint16_t
+DceManager::AllocatePid (void)
+{
+  // Note that this function purposedly never allocates pid 0 
+  // to make it useable in the kernel stack layer for kernel-level
+  // special tasks (which thus all share the same pid)
+  NS_LOG_FUNCTION (this);
+  for (uint16_t i = 0; i < 0xffff; i++)
+    {
+      uint16_t candidatePid = (m_nextPid + i) & 0xffff;
+      if (candidatePid != 0 && SearchProcess (candidatePid) == 0)
+        {
+          m_nextPid = (candidatePid + 1) & 0xffff;
+          return candidatePid;
+        }
+    }
+  NS_FATAL_ERROR ("Too many processes");
+  return 0; // quiet compiler
+}
+uint16_t
+DceManager::AllocateTid (const struct Process *process) const
+{
+  for (uint16_t tid = 0; tid < 0xffff; tid++)
+    {
+      bool found = false;
+      for (std::vector<struct Thread *>::const_iterator i = process->threads.begin (); i != process->threads.end (); ++i)
+        {
+          struct Thread *tmp = *i;
+          if (tmp->tid == tid)
+            {
+              found = true;
+              break;
+            }
+        }
+      if (!found)
+        {
+          return tid;
+        }
+    }
+  NS_FATAL_ERROR ("We attempted to allocate a new tid for this process but none were available: "
+                  "too many threads created at the same time.");
+  // quiet compiler
+  return 0;
+}
+struct Thread *
+DceManager::CreateThread (struct Process *process)
+{
+  NS_LOG_FUNCTION (this << process);
+  struct Thread *thread = new Thread ();
+  NS_LOG_DEBUG ("Create " << thread);
+  thread->err = 0;
+  thread->tid = AllocateTid (process);
+  thread->process = process;
+  thread->isDetached = false;
+  thread->hasExitValue = false;
+  thread->joinWaiter = 0;
+  sigemptyset (&thread->signalMask);
+  if (!process->threads.empty ())
+    {
+      // copy all key values.
+      Thread *tmp = process->threads.front ();
+      thread->keyValues = tmp->keyValues;
+      // reset all values to NULL
+      for (std::list<struct ThreadKeyValue>::iterator i = thread->keyValues.begin ();
+           i != thread->keyValues.end (); ++i)
+        {
+          i->value = 0;
+        }
+    }
+  process->threads.push_back (thread);
+  return thread;
+}
+
+void 
+DceManager::Exit (void)
+{
+  TaskManager::Current ()->Exit ();
+}
+
+bool
+DceManager::ThreadExists (Thread *thread)
+{
+  for (std::vector<Process *>::const_iterator i = m_processes.begin (); i != m_processes.end (); ++i)
+    {
+      Process *process = *i;
+      for (std::vector<Thread *>::const_iterator j = process->threads.begin (); 
+           j != process->threads.end (); ++j)
+        {
+          Thread *cur = *j;
+          if (cur == thread)
+            {
+              return true;
+            }
+        }
+    }
+  return false;
+}
+
+void 
+DceManager::Yield (void)
+{
+  TaskManager::Current ()->Yield ();
+}
+
+void 
+DceManager::Wait (void)
+{
+  TaskManager::Current ()->Sleep ();
+}
+
+Time
+DceManager::Wait (Time timeout)
+{
+  return TaskManager::Current ()->Sleep (timeout);
+}
+
+void 
+DceManager::Wakeup (Thread *thread)
+{
+  NS_ASSERT (ThreadExists (thread));
+  return TaskManager::Current ()->Wakeup (thread->task);
+}
+
+void 
+DceManager::SetFinishedCallback (uint16_t pid, Callback<void,uint16_t,int> cb)
+{
+  Process *process = SearchProcess (pid);
+  if (process == 0)
+    {
+      return;
+    }
+  process->finished = cb;
+}
+void 
+DceManager::Stop (uint16_t pid)
+{
+  NS_LOG_FUNCTION (this << pid);
+  Process *process = SearchProcess (pid);
+  if (process == 0)
+    {
+      return;
+    }
+  DeleteProcess (process);
+}
+
+void 
+DceManager::SigkillHandler (int signal)
+{
+  NS_ASSERT (signal == SIGKILL);
+  simu_exit (-1);
+}
+void
+DceManager::DeleteThread (struct Thread *thread)
+{
+  NS_LOG_FUNCTION (this << thread);
+  if (thread->task != 0)
+    {
+      // the task could be 0 if it was Exited by
+      // pthread_exit and it was not pthread_detached.
+      GetObject<TaskManager> ()->Stop (thread->task);
+    }
+  thread->task = 0;
+  for (std::vector<Thread *>::iterator i = thread->process->threads.begin ();
+       i != thread->process->threads.end (); ++i)
+    {
+      if (*i == thread)
+        {
+          thread->process->threads.erase (i);
+          break;
+        }
+    }
+  delete thread;
+}
+
+void
+DceManager::DeleteProcess (struct Process *process)
+{
+  NS_LOG_FUNCTION (this << process);
+
+  // Close all streams opened
+  for (uint32_t i =  0; i < process->openStreams.size (); i++)
+    {
+      // Note that, while this code might look straightforward,
+      // it is not so. Specifically, we call here the system fclose
+      // function which will call indirectly system_close in 
+      // system-wrappers.cc which will call simu_close in simu-fd.cc
+      // which will return -1 because it is called without a 'current'
+      // thread
+      SystemWrappersEnableNoop ();
+      fclose (process->openStreams[i]);
+      SystemWrappersDisable ();
+    }
+  process->openStreams.clear ();
+
+  if (!process->finished.IsNull ())
+    {
+      process->finished (process->pid, process->exitValue);
+    }
+  // stop itimer timers if there are any.
+  process->itimer.Cancel ();
+  // close all its fds.
+  for (uint32_t index = 0; index < process->openFiles.size (); index++)
+    {
+      process->openFiles[index].first = -1;
+      process->openFiles[index].second->Unref ();
+      process->openFiles[index].second = 0;
+    }
+  process->openFiles.clear ();
+  // finally, delete remaining threads
+  struct Thread *tmp;
+  while (!process->threads.empty ())
+    {
+      tmp = process->threads.back ();
+      process->threads.pop_back ();
+      DeleteThread (tmp);
+    }
+  // delete all mutexes
+  for (uint32_t i = 0; i < process->mutexes.size (); ++i)
+    {
+      struct Mutex *mutex = process->mutexes[i];
+      // XXX: do some error checking here to ensure that no thread is
+      // blocked in a critical section.
+      delete mutex;
+    }
+  process->mutexes.clear ();
+  // delete all semaphores
+  for (uint32_t i = 0; i < process->semaphores.size (); ++i)
+    {
+      struct Semaphore *semaphore = process->semaphores[i];
+      // XXX: do some error checking here to ensure that no thread is
+      // blocked in a critical section.
+      delete semaphore;
+    }
+  // delete all extra buffers
+  while (!process->allocated.empty ())
+    {
+      void *buffer = process->allocated.back ();
+      process->allocated.pop_back ();
+      free (buffer);
+    }
+  // delete process data structure.
+  m_processExit (process->pid, process->exitValue);
+  // remove ourselves from list of processes
+  for (std::vector<Process *>::iterator i = m_processes.begin ();
+       i != m_processes.end (); ++i)
+    {
+      if (*i == process)
+        {
+          m_processes.erase (i);
+          break;
+        }
+    }
+  delete process->loader;
+  delete process->alloc;
+  delete process;
+}
+
+bool
+DceManager::CheckProcessContext (void) const
+{
+  return TaskManager::Current () != 0 && TaskManager::Current ()->CurrentTask () != 0;
+}
+
+Thread *
+DceManager::SearchThread (uint16_t pid, uint16_t tid)
+{
+  NS_LOG_FUNCTION (this << pid << tid);
+  NS_ASSERT (CheckProcessContext ());
+  Process *process = SearchProcess (pid);
+  if (process == 0)
+    {
+      return 0;
+    }
+  for (std::vector<Thread *>::const_iterator j = process->threads.begin (); 
+       j != process->threads.end (); ++j)
+    {
+      Thread *thread = *j;
+      if (thread->tid == tid)
+        {
+          return thread;
+        }
+    }
+  return 0;
+}
+Process *
+DceManager::SearchProcess (uint16_t pid) const
+{
+  NS_LOG_FUNCTION (this << pid);
+
+  for (std::vector<Process *>::const_iterator i = m_processes.begin (); i != m_processes.end (); ++i)
+    {
+      Process *process = *i;
+      if (process->pid == pid)
+        {
+          return process;
+        }
+    }
+  return 0;
+}
+
+void 
+DceManager::SetArgv (struct Process *process, std::string filename, std::vector<std::string> args)
+{
+  NS_ASSERT (process->originalArgv == 0);
+  int argc = args.size () + 1;
+  char **argv = (char **)malloc (sizeof (char *) * (argc + 1));
+  process->allocated.push_back (argv);
+  argv[0] = strdup (filename.c_str ());
+  process->allocated.push_back (argv[0]);
+  for (uint32_t i = 0; i < args.size (); ++i)
+    {
+      char *arg = strdup (args[i].c_str ());
+      NS_LOG_DEBUG ("argc=" << argc << " i=" << i << " v=" << arg);
+      argv[i+1] = arg;
+      process->allocated.push_back (arg);
+    }
+  argv[argc] = 0;
+  process->originalArgv = argv;
+  process->originalArgc = argc;
+}
+
+void 
+DceManager::SetEnvp (struct Process *process, 
+                         std::vector<std::pair<std::string,std::string> > envs)
+{
+  int envpc = envs.size ();
+  char **envp = (char **)malloc (sizeof (char *) * (envpc + 1));
+  process->allocated.push_back (envp);
+  for (uint32_t i = 0; i < envs.size (); ++i)
+    {
+      int size = envs[i].first.size () + envs[i].second.size () + 1;
+      envp[i] = (char*)malloc (size+1);
+      process->allocated.push_back (envp[i]);
+      memcpy (envp[i], envs[i].first.c_str (), envs[i].first.size ());
+      envp[i][envs[i].first.size ()] = '=';
+      memcpy (envp[i] + envs[i].first.size () + 1, envs[i].second.c_str (), envs[i].second.size ());
+      envp[i][size] = 0;
+      NS_LOG_DEBUG ("envpc=" << envpc << " i=" << i << " v=" << envp[i]);
+    }
+  envp[envpc] = 0;
+  process->originalEnvp = envp;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/dce-manager.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,127 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2008 INRIA
+ *
+ * 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 DCE_MANAGER_H
+#define DCE_MANAGER_H
+
+#include <string>
+#include "ns3/object.h"
+#include "ns3/nstime.h"
+#include "ns3/traced-callback.h"
+#include "ns3/simulator.h"
+#include "task-manager.h"
+
+extern "C" struct Libc;
+
+namespace ns3 {
+
+struct Process;
+struct Thread;
+
+/**
+ * \brief Manages a set of virtual POSIX processes within the same
+ *        address space.
+ *
+ * Functionality provided by this class:
+ *
+ *  - a non-preemptive process scheduler. By default, this scheduler
+ *    is a round robin scheduler. This scheduler allows a 'synchronous'
+ *    programming style where functions can block until certain conditions
+ *    are verified as opposed to event-driven programming as is common
+ *    in most simulators.
+ *  - user-space thread library (named fibers) used by the process
+ *    scheduler to allocate stack space to each thread within each process.
+ *    The default implementation uses in fact kernel-space POSIX threads
+ *    but it's easy to switch to a real userspace implementation using the
+ *    FiberManagerType attribute.
+ *  - an ELF loader which controls how each user binary is loaded in memory
+ *    and makes sure that each instance of the same binary has private global
+ *    variables. The default implementation is ns3::ElfLoaderCopy but a
+ *    more efficient implementation (both cpu and memory-wise can be found in
+ *    ns3::ElfLoaderSmart) and it's easy to control which implementation is
+ *    used with the LoaderType attribute.
+ *
+ * A couple of applications which you can try with this loader:
+ *   - iperf: recompile with: "CFLAGS=-fPIC CXXFLAGS=-fPIC LDFLAGS=-pie ./configure && make"
+ *   - ip: recompile iproute2 with: "make CCOPTS='-fPIC' LDFLAGS=-pie"
+ *         Note: to get tc recompiled, it seems that you need to run bison by hand:
+ *         "cd tc && bison -d -t -v -o emp_ematch.yacc.c emp_ematch.y"
+ *   - ping: recompile iputils: edit Makefile: replace "CFLAGS=" with "CFLAGS+=" and run:
+ *           "make CFLAGS=-fPIC LDFLAGS=-pie"
+ */
+class DceManager : public Object
+{
+public:	
+  typedef Callback<void> Runnable;
+  static TypeId GetTypeId (void);
+
+  DceManager ();
+  ~DceManager ();
+
+  uint16_t Start (std::string name, std::vector<std::string> args,
+                  std::vector<std::pair<std::string,std::string> > envs);
+  uint16_t Start (std::string name, uint32_t stackSize,
+                  std::vector<std::string> args,
+                  std::vector<std::pair<std::string,std::string> > envs);
+  void SetFinishedCallback (uint16_t pid, Callback<void,uint16_t,int> cb);
+  void Stop (uint16_t pid);
+
+  // internal methods
+  struct Thread *CreateThread (struct Process *process);
+  void DeleteProcess (struct Process *process);
+  void DeleteThread (struct Thread *thread);
+
+  Thread *SearchThread (uint16_t pid, uint16_t tid);
+  Process *SearchProcess (uint16_t pid) const;
+
+  void Exit (void);
+  void Wakeup (Thread *thread);
+  void Wait (void);
+  Time Wait (Time timeout);
+  void Yield (void);
+
+private:
+
+  // inherited from Object.
+  virtual void DoDispose (void);
+
+  struct Process *CreateProcess (std::string name, std::vector<std::string> args,
+                                 std::vector<std::pair<std::string,std::string> > envs);
+  static void DoStartProcess (void *context);
+  bool CheckProcessContext (void) const;
+  uint16_t AllocatePid (void);
+  uint16_t AllocateTid (const struct Process *process) const;
+  static void SigkillHandler (int signal);
+  bool ThreadExists (Thread *thread);
+  static struct ::Libc *GetLibc (void);
+  void SetArgv (struct Process *process, std::string filename, std::vector<std::string> args);
+  void SetEnvp (struct Process *process, std::vector<std::pair<std::string,std::string> > envp);
+  static void EnsureDirectoryExists (struct Thread *current, std::string dirName);
+  static int CreatePidFile (struct Thread *current, std::string prefix);
+  static void TaskSwitch (enum Task::SwitchType type, void *context);
+
+  std::vector<Process *> m_processes;
+  uint16_t m_nextPid;
+  TracedCallback<uint16_t, int> m_processExit;
+};
+
+} // namespace ns3
+
+#endif /* DCE_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/dlm-loader-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,131 @@
+#include "dlm-loader-factory.h"
+#include "ns3/log.h"
+#include "ns3/fatal-error.h"
+#include <list>
+#include <dlfcn.h>
+
+NS_LOG_COMPONENT_DEFINE("DlmLoaderFactory");
+
+extern "C" {
+  // The function and structure declarations below are not exactly equal to the
+  // corresponding declarations in the elf loader, mostly for simplicity to 
+  // avoid dragging in too many dependent declarations.
+
+typedef Lmid_t (*DlLmidNew) (int, char **, char **);
+typedef void (*DlLmidDelete)(Lmid_t);
+typedef int (*DlLmidAddLibRemap) (Lmid_t lmid, const char *src, const char *dst);
+typedef void (*Ns3ReportTestError) (const char *);
+
+}
+
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED(DlmLoaderFactory);
+
+class DlmLoader : public Loader
+{
+public:
+  DlmLoader (int argc, char **argv, char **envp);
+  virtual ~DlmLoader ();
+  virtual void UnloadAll (void);
+  virtual void *Load (std::string filename, int flag);
+  virtual void Unload (void *module);
+  virtual void *Lookup (void *module, std::string symbol);
+private:
+  Lmid_t m_lmid;
+  std::list<void *> m_loaded;
+};
+
+DlmLoader::DlmLoader (int argc, char **argv, char **envp)
+{
+  NS_LOG_FUNCTION (this << argc);
+  void *libvdl = dlopen ("libvdl.so", RTLD_LAZY | RTLD_LOCAL);
+  DlLmidNew dlLmidNew = (DlLmidNew) dlsym (libvdl, "dl_lmid_new");
+  dlclose (libvdl);
+  if (dlLmidNew == 0)
+    {
+      NS_FATAL_ERROR ("Could not find our fancy elf loader");
+      // Note: we do not link explicitely against our fancy elf loader
+      // because it appears to break our stupid build system
+      // so, we have to lookup the necessary magic functions at runtime.
+    }
+
+  // create a new context
+  m_lmid = dlLmidNew (argc, argv, envp);
+
+}
+DlmLoader::~DlmLoader ()
+{
+  NS_LOG_FUNCTION (this);
+  m_loaded.clear ();
+  void *libvdl = dlopen ("libvdl.so", RTLD_LAZY | RTLD_LOCAL);
+  DlLmidDelete dlLmidDelete = (DlLmidDelete) dlsym (libvdl, "dl_lmid_delete");
+  dlclose (libvdl);
+  if (dlLmidDelete == 0)
+    {
+      NS_FATAL_ERROR ("Could not find our fancy elf loader for lmid deletion");
+      // Note: we do not link explicitely against our fancy elf loader
+      // because it appears to break our stupid build system
+      // so, we have to lookup the necessary magic functions at runtime.
+      return;
+    }
+  dlLmidDelete (m_lmid);
+}
+void 
+DlmLoader::UnloadAll (void)
+{
+  NS_LOG_FUNCTION (this);
+  for (std::list<void *>::const_iterator i = m_loaded.begin ();
+       i != m_loaded.end (); ++i)
+    {
+      ::dlclose (*i);
+    }
+}
+void *
+DlmLoader::Load (std::string filename, int flag)
+{
+  NS_LOG_FUNCTION (this << filename << flag);
+  void *module = dlmopen (m_lmid, filename.c_str (), flag);
+  m_loaded.push_back (module);
+  return module;
+}
+void 
+DlmLoader::Unload (void *module)
+{
+  NS_LOG_FUNCTION (this << module);
+  ::dlclose (module);
+  m_loaded.remove (module);
+}
+void *
+DlmLoader::Lookup (void *module, std::string symbol)
+{
+  NS_LOG_FUNCTION (this << module << symbol);
+  void *p = dlsym (module, symbol.c_str ());
+  return p;
+}
+
+
+TypeId 
+DlmLoaderFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::DlmLoaderFactory")
+    .SetParent<LoaderFactory> ()
+    .AddConstructor<DlmLoaderFactory> ()
+    ;
+  return tid;
+}
+
+DlmLoaderFactory::DlmLoaderFactory ()
+{}
+DlmLoaderFactory::~DlmLoaderFactory ()
+{}
+Loader *
+DlmLoaderFactory::Create (int argc, char **argv, char **envp)
+{
+  DlmLoader *loader = new DlmLoader (argc, argv, envp);
+  return loader;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/dlm-loader-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#ifndef DLM_LOADER_FACTORY_H
+#define DLM_LOADER_FACTORY_H
+
+#include "loader-factory.h"
+
+namespace ns3 {
+
+class DlmLoaderFactory : public LoaderFactory
+{
+public:
+  static TypeId GetTypeId (void);
+  DlmLoaderFactory ();
+  virtual ~DlmLoaderFactory ();
+  virtual Loader *Create (int argc, char **argv, char **envp);
+};
+
+} // namespace ns3
+
+#endif /* DLM_LOADER_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/elf-cache.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,352 @@
+#include "elf-cache.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sstream>
+#include <string.h>
+#include <sys/mman.h>
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE("ElfCache");
+
+ElfCache::ElfCache (std::string directory, uint32_t uid)
+  : m_directory (directory),
+    m_uid (uid)
+{
+  struct Overriden overriden;
+  overriden.from = "libc.so.6";
+  overriden.to = "libc-ns3.so";
+  m_overriden.push_back (overriden);
+  overriden.from = "libpthread.so.0";
+  overriden.to = "libpthread-ns3.so";
+  m_overriden.push_back (overriden);
+}
+
+std::string
+ElfCache::GetBasename (std::string filename) const
+{
+  std::string::size_type tmp = filename.find_last_of ("/");  
+  if (tmp == std::string::npos)
+    {
+      return filename;
+    }
+  return filename.substr (tmp+1, filename.size () - (tmp+1));
+}
+
+void
+ElfCache::CopyFile (std::string source, std::string destination) const
+{
+  NS_LOG_FUNCTION (this << source << destination);
+  int src = open (source.c_str (), O_RDONLY);
+  int dst = open (destination.c_str (), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
+  uint8_t buffer[1024];
+  ssize_t bytes_read = read (src, buffer, 1024);
+  while (bytes_read > 0)
+    {
+      ssize_t bytes_written = 0;
+      while (bytes_written != bytes_read)
+	{
+	  ssize_t written = write (dst, buffer + bytes_written, bytes_read - bytes_written);
+	  bytes_written += written;
+	}
+      bytes_read = read (src, buffer, 1024);
+    }
+  close (src);
+  close (dst);
+  NS_LOG_DEBUG ("copied " << source << " to " << destination);
+}
+
+long
+ElfCache::GetDtStrTab (ElfW(Dyn) *dyn, long baseAddress) const
+{
+  bool prelinked = false;
+  long dt_strtab = 0;
+  while (dyn->d_tag != DT_NULL)
+    {
+      if (dyn->d_tag == DT_STRTAB)
+	{
+	  dt_strtab = dyn->d_un.d_val;
+	}
+      else if (dyn->d_tag == DT_GNU_PRELINKED)
+	{
+	  prelinked = true;
+	}
+      dyn++;
+    }
+  if (prelinked)
+    {
+      dt_strtab -= baseAddress;
+    }
+  return dt_strtab;
+}
+
+unsigned long
+ElfCache::GetBaseAddress (ElfW(Phdr) *phdr, long phnum) const
+{
+  unsigned long end = ~0; // the max value storable in a uint64_t
+  unsigned long base = end;
+  for (long i = 0; i < phnum; i++, phdr++)
+    {
+      if (phdr->p_type == PT_LOAD)
+	{
+	  unsigned long ph_base = phdr->p_vaddr & ~(phdr->p_align-1);
+	  if (ph_base < base)
+	    {
+	      base = ph_base;
+	    }
+	}
+    }
+  if (base == end)
+    {
+      NS_LOG_ERROR ("Could not find base address.");
+    }
+  return base;
+}
+
+
+uint8_t
+ElfCache::NumberToChar (uint8_t c) const
+{
+  NS_ASSERT (c <= 60);
+  if (c < 10)
+    {
+      return c + 0x30;
+    }
+  else if (c < (10+25))
+    {
+      return c - 10 + 0x41;
+    }
+  else if (c < (10+25+25))
+    {
+      return c - (10 + 25) + 0x61;
+    }
+  return 0; // quiet compiler
+}
+void
+ElfCache::WriteString (char *str, uint32_t uid) const
+{
+  // we use base 4 chars in base 60.
+  if (uid >= 60 * 60 * 60 * 60)
+    {
+      NS_FATAL_ERROR ("Please, report a bug: not enough unique strings for loaded code.");
+    }
+  uint8_t a = uid % 60;
+  uint8_t b = (uid / 60) % 60;
+  uint8_t c = (uid / 3600) % 60;
+  uint8_t d = (uid / 216000) % 60;
+  str[0] = NumberToChar (d);
+  str[1] = NumberToChar (c);
+  str[2] = NumberToChar (b);
+  str[3] = NumberToChar (a);
+  NS_LOG_DEBUG ("wrote " << str);
+}
+
+struct ElfCache::FileInfo
+ElfCache::EditBuffer (uint8_t *map, uint32_t selfId) const
+{
+  ElfW(Ehdr) *header = (ElfW(Ehdr) *)map;
+  ElfW(Phdr) *phdr = (ElfW(Phdr) *)(map + header->e_phoff);
+  ElfW(Dyn) *dyn = 0;
+  long base_address = GetBaseAddress (phdr, header->e_phnum);
+
+  // find DYNAMIC and fill DataSection
+  struct FileInfo fileInfo;
+  for (uint32_t i = 0; i < header->e_phnum; i++, phdr++)
+    {
+      switch (phdr->p_type)
+	{
+	case PT_LOAD:
+	  if (phdr->p_flags & PF_W)
+	    {
+	      // data section !
+	      fileInfo.p_vaddr = phdr->p_vaddr;
+	      fileInfo.p_memsz = phdr->p_memsz;
+	    }
+	  break;
+	case PT_DYNAMIC:
+	  // now, seek DT_NEEDED
+	  dyn = (ElfW(Dyn) *)(map + phdr->p_offset);
+	  break;
+	}
+    }
+  // first, Patch the DT_NEEDED, and, DT_SONAME entries
+  // and save the DT_INIT entry
+  long dt_strtab = GetDtStrTab (dyn, base_address);
+  long dt_init = 0;
+  ElfW(Dyn) *cur = dyn;
+  while (cur->d_tag != DT_NULL)
+    {
+      if (cur->d_tag == DT_NEEDED)
+	{
+	  char *needed = (char *)(map + dt_strtab + cur->d_un.d_val);
+	  if (std::string (needed) != "ld-linux-x86-64.so.2" &&
+	      std::string (needed) != "ld-linux.so.2")
+	    {
+	      uint32_t id = GetDepId (needed);
+	      fileInfo.deps.push_back (id);
+	      WriteString (needed, id);
+	    }
+	}
+      else if (cur->d_tag == DT_SONAME)
+	{
+	  char *soname = (char *)(map + dt_strtab + cur->d_un.d_val);
+	  WriteString (soname, selfId);
+	}
+      else if (cur->d_tag == DT_INIT)
+	{
+	  dt_init = cur->d_un.d_val;
+	}
+      cur++;
+    }
+  // then, eliminate DT_FINI, DT_FINI_ARRAY and DT_FINI_ARRAYSZ
+  cur = dyn;
+  while (cur->d_tag != DT_NULL)
+    {
+      if (cur->d_tag == DT_FINI)
+	{
+	  cur->d_tag = DT_INIT;
+	  cur->d_un.d_val = dt_init;
+	}
+      else if (cur->d_tag == DT_FINI_ARRAYSZ)
+	{
+	  cur->d_un.d_val = 0;
+	}
+      cur++;
+    }
+  return fileInfo;
+}
+
+struct ElfCache::FileInfo
+ElfCache::EditFile (std::string filename, uint32_t selfId) const
+{
+  NS_LOG_FUNCTION (this << filename);
+  int fd = ::open (filename.c_str (), O_RDWR);
+  NS_ASSERT_MSG (fd != -1, "unable to open file=" << filename << " error=" << strerror (errno));
+  struct stat st;
+  int retval = ::fstat(fd, &st);
+  NS_ASSERT_MSG (retval == 0, "unable to fstat file=" << filename << " error=" << strerror (errno));
+  uint64_t size = st.st_size;
+  uint8_t *buffer = (uint8_t *) ::mmap (0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  NS_ASSERT_MSG (buffer != MAP_FAILED, "unable to mmap file=" << filename << " error=" << strerror (errno));
+  close (fd);
+
+  struct FileInfo fileInfo = EditBuffer (buffer, selfId);
+
+  // write back changes to hard disk
+  retval = ::msync (buffer, size, MS_SYNC);
+  NS_ASSERT_MSG (retval == 0, "msync failed " << strerror (errno));
+
+  retval = ::munmap (buffer, size);
+  NS_ASSERT_MSG (retval == 0, "munmap failed " << strerror (errno));
+
+  return fileInfo;
+}
+
+uint32_t 
+ElfCache::AllocateId (void)
+{
+  static uint32_t id = 0;
+  id++;
+  return id;
+}
+
+uint32_t
+ElfCache::GetDepId (std::string depname) const
+{
+  for (std::vector<struct Overriden>::const_iterator i = m_overriden.begin (); i != m_overriden.end (); ++i)
+    {
+      struct Overriden overriden = *i;
+      if (overriden.from == depname)
+	{
+	  depname = overriden.to;
+	}
+    }
+  for (std::vector<struct ElfCachedFile>::const_iterator i = m_files.begin (); i != m_files.end (); ++i)
+    {
+      if (depname == i->basename)
+	{
+	  return i->id;
+	}
+    }
+  NS_ASSERT_MSG (false, "did not find " << depname);
+  return 0; // quiet compiler
+}
+
+std::string
+ElfCache::EnsureCacheDirectory (void) const
+{
+  int retval = ::mkdir (m_directory.c_str (), S_IRWXU);
+  if (retval == 0)
+    {
+      NS_LOG_DEBUG ("Created elf loader cache directory.");
+    }
+  std::ostringstream oss;
+  oss << m_directory << "/" << m_uid;
+  retval = ::mkdir (oss.str ().c_str (), S_IRWXU);
+  if (retval == 0)
+    {
+      NS_LOG_DEBUG ("Created elf loader cache directory.");
+    }
+  return oss.str ();
+}
+
+struct ElfCache::ElfCachedFile
+ElfCache::Add (std::string filename)
+{
+  NS_LOG_FUNCTION (this << filename);
+  std::string basename = GetBasename (filename);
+  // check if we have an override rule for this file
+  for (std::vector<struct Overriden>::const_iterator i = m_overriden.begin (); i != m_overriden.end (); ++i)
+    {
+      struct Overriden overriden = *i;
+      if (overriden.from == basename)
+	{
+	  // check if the overriden file is already in-store.
+	  for (std::vector<struct ElfCachedFile>::const_iterator i = m_files.begin (); i != m_files.end (); ++i)
+	    {
+	      if (i->basename == overriden.to)
+		{
+		  return *i;
+		}
+	    }
+	  NS_ASSERT (false);
+	}
+    }
+
+  // check if the file is already in-store.
+  for (std::vector<struct ElfCachedFile>::const_iterator i = m_files.begin (); i != m_files.end (); ++i)
+    {
+      if (i->basename == basename)
+	{
+	  return *i;
+	}
+    }  
+
+  std::string directory = EnsureCacheDirectory ();
+  std::string fileCopy = directory + "/" + basename;
+  CopyFile (filename, fileCopy);
+
+  uint32_t selfId = AllocateId ();
+
+  struct FileInfo fileInfo = EditFile (fileCopy, selfId);
+
+  struct ElfCachedFile cached;
+  cached.cachedFilename = fileCopy;
+  cached.basename = basename;
+  cached.data_p_vaddr = fileInfo.p_vaddr;
+  cached.data_p_memsz = fileInfo.p_memsz;
+  cached.id = selfId;
+  cached.deps = fileInfo.deps;
+
+  m_files.push_back (cached);
+  return cached;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/elf-cache.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,61 @@
+#ifndef ELF_CACHE_H
+#define ELF_CACHE_H
+
+#include <string>
+#include <stdint.h>
+#include <elf.h>
+#include <link.h>
+#include <vector>
+
+namespace ns3 {
+
+class ElfCache
+{
+public:
+  ElfCache (std::string directory, uint32_t uid);
+
+  struct ElfCachedFile
+  {
+    std::string cachedFilename;
+    std::string basename;
+    long data_p_vaddr;
+    long data_p_memsz;
+    uint32_t id;
+    std::vector<uint32_t> deps;
+  };
+  struct ElfCachedFile Add (std::string filename);
+
+private:
+  struct FileInfo
+  {
+    long p_vaddr;
+    long p_memsz;
+    std::vector<uint32_t> deps;
+  };
+  struct Overriden
+  {
+    std::string from;
+    std::string to;
+  };
+  std::string GetBasename (std::string filename) const;
+  void CopyFile (std::string source, std::string destination) const;
+  void WriteString (char *str, uint32_t uid) const;
+  uint8_t NumberToChar (uint8_t c) const;
+  static uint32_t AllocateId (void);
+  struct FileInfo EditBuffer (uint8_t *map, uint32_t selfId) const;
+  struct FileInfo EditFile (std::string filename, uint32_t selfId) const;
+  uint32_t GetDepId (std::string depname) const;
+  std::string EnsureCacheDirectory (void) const;
+  unsigned long GetBaseAddress (ElfW(Phdr) *phdr, long phnum) const;
+  long GetDtStrTab (ElfW(Dyn) *dyn, long baseAddress) const;
+
+
+  std::string m_directory;
+  uint32_t m_uid;
+  std::vector<struct ElfCachedFile> m_files;
+  std::vector<struct Overriden> m_overriden;
+};
+
+} // namespace ns3
+
+#endif /* ELF_CACHE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/elf-dependencies.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,243 @@
+#include "elf-dependencies.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <algorithm>
+
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE("ElfDependencies");
+
+ElfDependencies::ElfDependencies (std::string filename)
+{
+  std::string fullname;
+  bool found;
+  found = SearchFile (filename, &fullname);
+  NS_ASSERT (found);
+  std::vector<struct Dependency> deps = GatherDependencies (fullname);
+  std::reverse (deps.begin (), deps.end ());
+  struct Dependency dependency;
+  dependency.required = filename;
+  dependency.found = fullname;
+  deps.push_back (dependency);
+  m_deps = deps;
+}
+
+std::vector<struct ElfDependencies::Dependency>
+ElfDependencies::GatherDependencies (std::string fullname) const
+{
+  NS_LOG_FUNCTION (this << fullname);
+  /* We gather the dependencies for the input file using the 'ldd' program.
+   * To do this, we do a standard fork+exec and forward the output of ldd
+   * to the parent through a pipe which is then parsed in the parent.
+   */
+  std::vector<struct Dependency> dependencies;
+
+  int pipefd[2];
+  int retval = ::pipe (pipefd);
+  if (retval == -1)
+    {
+      NS_LOG_ERROR ("Cannot create pipe: " << ::strerror (errno));
+      return dependencies;
+    }
+  pid_t pid = ::fork ();
+  if (pid == 0)
+    {
+      // child.
+      NS_LOG_DEBUG ("Child");
+      ::close (pipefd[0]);
+      int tmp;
+      tmp = dup2 (pipefd[1], 1);
+      if (tmp == -1)
+	{
+	  NS_LOG_ERROR ("Cannot redirect stdout");
+	  ::exit (0);
+	}
+      retval = ::execl ("/usr/bin/ldd", "ldd", fullname.c_str (), (char *)NULL);
+      if (retval == -1)
+	{
+	  NS_LOG_ERROR ("Cannot execl ldd: " << ::strerror (errno));
+	}
+      ::close (pipefd[1]);
+      ::_exit (EXIT_SUCCESS);
+    }
+  else
+    {
+      // parent.
+      NS_LOG_DEBUG ("Parent");
+      ::close (pipefd[1]);
+      std::string lddOutput;
+      uint8_t c;
+      ssize_t bytesRead = ::read (pipefd[0], &c, 1);
+      while (bytesRead == 1)
+	{
+	  lddOutput.push_back (c);
+	  bytesRead = ::read (pipefd[0], &c, 1);
+	}
+      waitpid (pid, 0, 0);
+      ::close (pipefd[0]);
+      std::string::size_type cur = 0;
+      while (true)
+	{
+	  NS_LOG_DEBUG ("line=" << lddOutput);
+	  std::string::size_type dep_start = lddOutput.find_first_not_of (" \t", cur);
+	  std::string::size_type dep_end = lddOutput.find (" ", dep_start);
+	  std::string::size_type full_start = lddOutput.find_first_of (">", dep_end);
+	  full_start = lddOutput.find_first_not_of (" \t", full_start + 1);
+	  std::string::size_type full_end = lddOutput.find_first_of (" \n", full_start);
+	  NS_LOG_DEBUG ("dep_start=" << dep_start << " dep_end=" << dep_end << " full_start=" << full_start << " full_end=" << full_end);
+	  if (dep_start != std::string::npos &&
+	      full_start != std::string::npos &&
+	      full_start > dep_start)
+	    {
+	      std::string depname = lddOutput.substr (dep_start, dep_end - dep_start);
+	      std::string fulldepname = lddOutput.substr (full_start, full_end - (full_start));
+	      NS_LOG_DEBUG (depname << "->" << fulldepname);
+	      if (depname == "linux-gate.so.1" ||
+		  depname == "ld-linux.so.2" ||
+		  depname == "ld-linux-x86-64.so.2" ||
+		  depname == "/lib/ld-linux.so.2" ||
+		  depname == "/lib64/ld-linux-x86-64.so.2" ||
+		  depname == "/usr/lib/debug/ld-linux-x86-64.so.2" ||
+		  depname == "linux-vdso.so.1")
+		{
+		  goto next;
+		}
+	      else
+		{
+		  struct Dependency dependency;
+		  dependency.required = depname;
+		  dependency.found = fulldepname;
+		  dependencies.push_back (dependency);
+		}
+	    }
+	  else
+	    {
+	      break;
+	    }
+	next:
+	  cur = lddOutput.find_first_of ("\n", full_start);
+	  if (cur != std::string::npos)
+	    {
+	      cur++;
+	    }
+	  else
+	    {
+	      break;
+	    }
+	}
+      
+    }
+
+  return dependencies;
+}
+
+
+std::list<std::string>
+ElfDependencies::Split (std::string input, std::string sep) const
+{
+  NS_LOG_FUNCTION (this << input << sep);
+  std::list<std::string> retval;
+  std::string::size_type cur = 0, next;
+  while (true)
+    {
+      next = input.find (sep, cur);
+      if (next == cur)
+	{
+	  cur ++;
+	  continue;
+	} 
+      else if (next == std::string::npos)
+	{
+	  if (input.size () != cur)
+	    {
+	      retval.push_back (input.substr (cur, input.size () - cur));
+	    }
+	  break;
+	}
+      retval.push_back (input.substr (cur, next - cur));
+      cur = next + 1;
+    }
+  return retval;
+}
+
+std::list<std::string>
+ElfDependencies::GetSearchDirectories (void) const
+{
+  NS_LOG_FUNCTION (this);
+  std::list<std::string> directories;
+  char *ldLibraryPath = getenv ("LD_LIBRARY_PATH");
+  if (ldLibraryPath != 0)
+    {
+      std::list<std::string> tmp = Split (ldLibraryPath, ":");
+      directories.insert (directories.end (), 
+			  tmp.begin (),
+			  tmp.end ());
+    }
+  char *path = getenv ("PATH");
+  if (path != 0)
+    {
+      std::list<std::string> tmp = Split (path, ":");
+      directories.insert (directories.end (), 
+			  tmp.begin (),
+			  tmp.end ());
+    }
+  directories.push_back ("/lib");
+  directories.push_back ("/usr/lib");
+  directories.push_back (".");
+  return directories;
+}
+
+bool
+ElfDependencies::Exists (std::string filename) const
+{
+  //NS_LOG_FUNCTION (this << filename);
+  struct stat st;
+  int retval = ::stat (filename.c_str (), &st);
+  return retval == 0;
+}
+
+bool
+ElfDependencies::SearchFile (std::string filename, std::string *fullname) const
+{
+  NS_LOG_FUNCTION (this << filename);
+  if (Exists (filename))
+    {
+      *fullname = filename;
+      NS_LOG_DEBUG ("Found: " << filename << " as " << *fullname);
+      return true;
+    }
+  std::list<std::string> dirs = GetSearchDirectories ();
+  for (std::list<std::string>::const_iterator i = dirs.begin (); i != dirs.end (); i++)
+    {
+      if (Exists (*i + "/" + filename))
+	{
+	  *fullname = *i + "/" + filename;
+	  NS_LOG_DEBUG ("Found: " << filename << " as " << *fullname);
+	  return true;
+	}
+    }
+  return false;
+}
+
+
+ElfDependencies::Iterator 
+ElfDependencies::Begin (void) const
+{
+  return m_deps.begin ();
+}
+
+ElfDependencies::Iterator 
+ElfDependencies::End (void) const
+{
+  return m_deps.end ();
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/elf-dependencies.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,39 @@
+#ifndef ELF_DEPENDENCIES_H
+#define ELF_DEPENDENCIES_H
+
+#include <string>
+#include <vector>
+#include <list>
+
+namespace ns3 {
+
+class ElfDependencies
+{
+ public:
+  struct Dependency
+  {
+    std::string required;
+    std::string found;
+  };
+  typedef std::vector<struct Dependency>::const_iterator Iterator;
+
+  ElfDependencies (std::string filename);
+
+  Iterator Begin (void) const;
+  Iterator End (void) const;
+
+ private:
+  std::list<std::string> Split (std::string input, std::string sep) const;
+  std::list<std::string> GetSearchDirectories (void) const;
+  bool Exists (std::string filename) const;
+  bool SearchFile (std::string filename, std::string *dirname) const;
+  std::vector<struct Dependency> GatherDependencies (std::string fullname) const;
+
+
+  std::vector<struct Dependency> m_deps;
+};
+
+} // namespace ns3
+
+
+#endif /* ELF_DEPENDENCIES_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/fiber-manager.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,8 @@
+#include "fiber-manager.h"
+
+namespace ns3 {
+
+FiberManager::~FiberManager ()
+{}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/fiber-manager.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,74 @@
+#ifndef FIBER_MANAGER_H
+#define FIBER_MANAGER_H
+
+#include <stdint.h>
+
+namespace ns3 {
+
+struct Fiber
+{};
+
+class FiberManager
+{
+public:
+  virtual ~FiberManager ();
+  /**
+   * \param callback function to use as main loop for the 
+   *        newly-created fiber
+   * \param stackSize size of the stack to allocate for this
+   *        fiber.
+   * \returns a newly-created fiber context.
+   */
+  virtual struct Fiber *Create (void (*callback) (void *),
+				void *context,
+				uint32_t stackSize) = 0;
+  /**
+   * \returns an empty context
+   *
+   * Create a fiber context which can be used as a from
+   * argument to the SwitchTo method
+   * This method is usually used to create a context which
+   * references the main 'normal' thread. i.e., the thread
+   * initially managed by the underlying kernel which
+   * runs on the kernel-managed stack.
+   */
+  virtual struct Fiber *CreateFromCaller (void) = 0;
+
+  /**
+   * \param context to delete
+   *
+   * Release any ressource associated to this context.
+   * Obviously, this method must be called from another 
+   * context than the one which is being deleted.
+   */
+  virtual void Delete (struct Fiber *fiber) = 0;
+
+  /**
+   * \param from from context
+   * \param to to context
+   *
+   * This function saves the caller's context into the from
+   * context and restores the current context from the to
+   * context. The first time this function is called, it is
+   * usually called with a from set to a context obtained
+   * through CreateFromCaller and with a to set to a context
+   * obtained through Create.
+   */
+  virtual void SwitchTo (struct Fiber *from, 
+			 const struct Fiber *to) = 0;
+
+  /**
+   * \return size of stack allocated in fiber.
+   */
+  virtual uint32_t GetStackSize (struct Fiber *fiber) const = 0;
+
+  /**
+   * \param fn a function which will be invoked whenever SwitchTo
+   * is invoked, just before it returns to the destination fiber.
+   */
+  virtual void SetSwitchNotification (void (*fn) (void)) = 0;
+};
+
+} // namespace ns3
+
+#endif /* FIBER_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libc-global-variables.c	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#undef __OPTIMIZE__
+#include <stdio.h>
+#include <netinet/in.h>
+#include "libc-globals.h"
+
+
+FILE *stdin;
+FILE *stdout;
+FILE *stderr;
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+char *optarg = 0;
+int optind = 0, opterr = 0, optopt = 0;
+const char *_libc_intl_domainname = "libc";
+char **__environ = 0;
+
+#define weak_alias(name, aliasname) \
+  extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)))
+
+weak_alias(__environ,environ);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libc-globals.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,14 @@
+#ifndef LIBC_GLOBALS_H
+#define LIBC_GLOBALS_H
+
+#include <stdio.h>
+
+struct LibcGlobals
+{
+  FILE *stdin;
+  FILE *stdout;
+  FILE *stderr;
+  char **envp;
+};
+
+#endif /* LIBC_GLOBALS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libc-ns3.version	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,5 @@
+NS3 {
+global:
+	libc_setup;
+	libc_global_setup;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libc-simu.c	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,279 @@
+#define _GNU_SOURCE 1
+#include "libc-simu.h"
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdio.h>
+#include <locale.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include <time.h>
+#include "sys/simu-socket.h"
+#include "simu-unistd.h"
+#include "simu-netdb.h"
+#include "simu-pthread.h"
+#include "simu-stdio.h"
+#include "simu-stdarg.h"
+#include "simu-errno.h"
+#include "simu-fcntl.h"
+#include "sys/simu-time.h"
+#include "sys/simu-ioctl.h"
+#include "simu-sched.h"
+#include "simu-poll.h"
+#include "simu-signal.h"
+#include "simu-stdlib.h"
+#include "simu-time.h"
+#include "sys/simu-mman.h"
+#include "sys/simu-stat.h"
+#include "sys/simu-select.h"
+#include "simu-semaphore.h"
+#include "arpa/simu-inet.h"
+#include "simu-cxa.h"
+#include "simu-string.h"
+#include "simu-global-variables.h"
+#include "sys/simu-timerfd.h"
+#include "simu-random.h"
+#include "net/simu-if.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int (*__gxx_personality_v0) (int a, int b, 
+				    unsigned c, 
+				    struct _Unwind_Exception *d, 
+				    struct _Unwind_Context *e);
+extern int __xpg_strerror_r (int __errnum, char *__buf, size_t __buflen);
+
+
+void libc_simu (struct Libc *libc)
+{
+  libc->global_variables_setup = simu_global_variables_setup;
+  libc->strerror_fn = strerror;
+  libc->gnu_strerror_r_fn = strerror_r;
+  libc->xsi_strerror_r_fn = __xpg_strerror_r;
+  libc->atexit_fn = simu_atexit;
+  libc->__cxa_finalize_fn = simu__cxa_finalize;
+  libc->__cxa_atexit_fn = simu__cxa_atexit;
+  libc->__gxx_personality_v0_fn = __gxx_personality_v0;
+  libc->newlocale_fn = newlocale;
+  libc->uselocale_fn = uselocale;
+  libc->wctob_fn = wctob;
+  libc->btowc_fn = btowc;
+  libc->wctype_l_fn = wctype_l;
+  libc->htonl_fn = htonl;
+  libc->htons_fn = htons;
+  libc->ntohl_fn = ntohl;
+  libc->ntohs_fn = ntohs;
+  libc->socket_fn = simu_socket;
+  libc->getsockname_fn = simu_getsockname;
+  libc->getpeername_fn = simu_getpeername;
+  libc->bind_fn = simu_bind;
+  libc->read_fn = simu_read;
+  libc->connect_fn = simu_connect;
+  libc->write_fn = simu_write;
+  libc->writev_fn = simu_writev;
+  libc->memset_fn = memset;
+  libc->memcpy_fn = memcpy;
+  libc->memcmp_fn = memcmp;
+  libc->memmove_fn = memmove;
+  libc->strcpy_fn = strcpy;
+  libc->strncpy_fn = strncpy;
+  libc->strcmp_fn = strcmp;
+  libc->strncmp_fn = strncmp;
+  libc->strlen_fn = strlen;
+  libc->strchr_fn = strchr;
+  libc->strrchr_fn = strrchr;
+  libc->strcasecmp_fn = strcasecmp;
+  libc->strncasecmp_fn = strncasecmp;
+  libc->strdup_fn = simu_strdup;
+  libc->strndup_fn = simu_strndup;
+  libc->sleep_fn = simu_sleep;
+  libc->fopen_fn = simu_fopen;
+  libc->fdopen_fn = simu_fdopen;
+  libc->freopen_fn = simu_freopen;
+  libc->fclose_fn = simu_fclose;
+  libc->fcloseall_fn = simu_fcloseall;
+  libc->fread_fn = simu_fread;
+  libc->fwrite_fn = simu_fwrite;
+  libc->fflush_fn = simu_fflush;
+  libc->fseek_fn = simu_fseek;
+  libc->ftell_fn = simu_ftell;
+  libc->fgetpos_fn = simu_fgetpos;
+  libc->fsetpos_fn = simu_fsetpos;
+  libc->ferror_fn = simu_ferror;
+  libc->feof_fn = simu_feof;
+  libc->fileno_fn = simu_fileno;
+  libc->clearerr_fn = simu_clearerr;
+  libc->setvbuf_fn = simu_setvbuf;
+  libc->rewind_fn = simu_rewind;
+  libc->vfprintf_fn = simu_vfprintf;
+  libc->vsprintf_fn = vsprintf;
+  libc->vsnprintf_fn = vsnprintf;
+  libc->fputc_fn = simu_fputc;
+  libc->fputs_fn = simu_fputs;
+  libc->fgetc_fn = simu_fgetc;
+  libc->fgets_fn = simu_fgets;
+  libc->ungetc_fn = simu_ungetc;
+
+  libc->fcntl_fn = simu_fcntl;
+  libc->nanosleep_fn = simu_nanosleep;
+
+  libc->random_fn = simu_random;
+  libc->rand_fn = simu_rand;
+  libc->srandom_fn = simu_srandom;
+  libc->srand_fn = simu_srand;
+
+  libc->__errno_location_fn = simu_get_errno;
+  libc->getopt_r_fn = simu_getopt_r;
+  libc->getopt_long_r_fn = simu_getopt_long_r;
+  libc->getpid_fn = simu_getpid;
+  libc->getppid_fn = simu_getppid;
+  libc->getuid_fn = simu_getuid;
+  libc->geteuid_fn = simu_geteuid;
+  libc->setuid_fn = simu_setuid;
+  libc->setgid_fn = simu_setgid;
+  libc->seteuid_fn = simu_seteuid;
+  libc->setegid_fn = simu_setegid;
+  libc->setreuid_fn = simu_setreuid;
+  libc->setregid_fn = simu_setregid;
+  libc->setresuid_fn = simu_setresuid;
+  libc->setresgid_fn = simu_setresgid;
+  libc->inet_aton_fn = inet_aton;
+  libc->inet_ntoa_fn = inet_ntoa;
+  libc->inet_ntop_fn = simu_inet_ntop;
+  libc->inet_network_fn = inet_network;
+  libc->inet_makeaddr_fn = inet_makeaddr;
+  libc->inet_lnaof_fn = inet_lnaof;
+  libc->inet_netof_fn = inet_netof;
+  libc->inet_addr_fn = inet_addr;
+  libc->mmap64_fn = simu_mmap64;
+  libc->munmap_fn = simu_munmap;
+  libc->xstat_fn = simu_xstat;
+  libc->lxstat_fn = simu_lxstat;
+  libc->fxstat_fn = simu_fxstat;
+  libc->xstat64_fn = simu_xstat64;
+  libc->lxstat64_fn = simu_lxstat64;
+  libc->fxstat64_fn = simu_fxstat64;
+  libc->dup_fn = simu_dup;
+  libc->dup2_fn = simu_dup2;
+  libc->open_fn = simu_open;
+  libc->close_fn = simu_close;
+  libc->unlink_fn = simu_unlink;
+  libc->remove_fn = simu_remove;
+  libc->mkdir_fn = simu_mkdir;
+  libc->rmdir_fn = simu_rmdir;
+  libc->setsockopt_fn = simu_setsockopt;
+  libc->getsockopt_fn = simu_getsockopt;
+  libc->select_fn = simu_select;
+  libc->listen_fn = simu_listen;
+  libc->accept_fn = simu_accept;
+  libc->shutdown_fn = simu_shutdown;
+  libc->calloc_fn = simu_calloc;
+  libc->malloc_fn = simu_malloc;
+  libc->free_fn = simu_free;
+  libc->realloc_fn = simu_realloc;
+  libc->gettimeofday_fn = simu_gettimeofday;
+  libc->time_fn = simu_time;
+  libc->isatty_fn = simu_isatty;
+  libc->send_fn = simu_send;
+  libc->sendto_fn = simu_sendto;
+  libc->sendmsg_fn = simu_sendmsg;
+  libc->recv_fn = simu_recv;
+  libc->recvfrom_fn = simu_recvfrom;
+  libc->recvmsg_fn = simu_recvmsg;
+  libc->ioctl_fn = simu_ioctl;
+  libc->sched_yield_fn = simu_sched_yield;
+  libc->poll_fn = simu_poll;
+  libc->__cmsg_nxthdr_fn = __cmsg_nxthdr;
+  libc->atoi_fn = atoi;
+  libc->atol_fn = atol;
+  libc->atoll_fn = atoll;
+  libc->atof_fn = atof;
+  libc->setitimer_fn = simu_setitimer;
+  libc->getitimer_fn = simu_getitimer;
+  libc->exit_fn = simu_exit;
+  libc->signal_fn = simu_signal;
+  libc->sigaction_fn = simu_sigaction;
+  libc->sigemptyset_fn = sigemptyset;
+  libc->sigfillset_fn = sigfillset;
+  libc->sigaddset_fn = sigaddset;
+  libc->sigdelset_fn = sigdelset;
+  libc->sigismember_fn = sigismember;
+  libc->strtol_fn = simu_strtol;
+  libc->strtoll_fn = simu_strtoll;
+  libc->strtoul_fn = simu_strtoul;
+  libc->strtoull_fn = simu_strtoull;
+  libc->strtod_fn = simu_strtod;
+  libc->getcwd_fn = simu_getcwd;
+  libc->getwd_fn = simu_getwd;
+  libc->get_current_dir_name_fn = simu_get_current_dir_name;
+  libc->chdir_fn = simu_chdir;
+  libc->fchdir_fn = simu_fchdir;
+  libc->localtime_fn = localtime;
+  libc->strftime_fn = strftime;
+  libc->__ctype_b_loc_fn = __ctype_b_loc;
+  libc->gmtime_r_fn = gmtime_r;
+
+  libc->pthread_create_fn = simu_pthread_create;
+  libc->pthread_exit_fn = simu_pthread_exit;
+  libc->pthread_self_fn = simu_pthread_self;
+  libc->pthread_once_fn = simu_pthread_once;
+  libc->pthread_getspecific_fn = simu_pthread_getspecific;
+  libc->pthread_setspecific_fn = simu_pthread_setspecific;
+  libc->pthread_key_create_fn = simu_pthread_key_create;
+  libc->pthread_key_delete_fn = simu_pthread_key_delete;
+  libc->pthread_mutex_destroy_fn = simu_pthread_mutex_destroy;
+  libc->pthread_mutex_init_fn = simu_pthread_mutex_init;
+  libc->pthread_mutex_lock_fn = simu_pthread_mutex_lock;
+  libc->pthread_mutex_unlock_fn = simu_pthread_mutex_unlock;
+  libc->pthread_mutex_trylock_fn = simu_pthread_mutex_trylock;
+  libc->pthread_mutexattr_init_fn = simu_pthread_mutexattr_init;
+  libc->pthread_mutexattr_destroy_fn = simu_pthread_mutexattr_destroy;
+  libc->pthread_mutexattr_settype_fn = simu_pthread_mutexattr_settype;
+  libc->pthread_cancel_fn = simu_pthread_cancel;
+  libc->pthread_kill_fn = simu_pthread_kill;
+  libc->pthread_join_fn = simu_pthread_join;
+  libc->pthread_detach_fn = simu_pthread_detach;
+  libc->sem_init_fn = simu_sem_init;
+  libc->sem_destroy_fn = simu_sem_destroy;
+  libc->sem_post_fn = simu_sem_post;
+  libc->sem_wait_fn = simu_sem_wait;
+  libc->sem_timedwait_fn = simu_sem_timedwait;
+  libc->sem_trywait_fn = simu_sem_trywait;
+  libc->sem_getvalue_fn = simu_sem_getvalue;
+  libc->pthread_cond_destroy_fn = simu_pthread_cond_destroy;
+  libc->pthread_cond_init_fn = simu_pthread_cond_init;
+  libc->pthread_cond_broadcast_fn = simu_pthread_cond_broadcast;
+  libc->pthread_cond_signal_fn = simu_pthread_cond_signal;
+  libc->pthread_cond_timedwait_fn = simu_pthread_cond_timedwait;
+  libc->pthread_cond_wait_fn = simu_pthread_cond_wait;
+  libc->pthread_condattr_destroy_fn = simu_pthread_condattr_destroy;
+  libc->pthread_condattr_init_fn = simu_pthread_condattr_init;
+
+  libc->gethostbyname_fn = simu_gethostbyname;
+  libc->gethostbyname2_fn = simu_gethostbyname2;
+  libc->getaddrinfo_fn = simu_getaddrinfo;
+  libc->freeaddrinfo_fn = simu_freeaddrinfo;
+  libc->gai_strerror_fn = simu_gai_strerror;
+
+  libc->getenv_fn = simu_getenv;
+  libc->putenv_fn = simu_putenv;
+  libc->setenv_fn = simu_setenv;
+  libc->unsetenv_fn = simu_unsetenv;
+  libc->clearenv_fn = simu_clearenv;
+
+  libc->toupper_fn = toupper;
+  libc->tolower_fn = tolower;
+
+  libc->timerfd_create_fn = simu_timerfd_create;
+  libc->timerfd_settime_fn = simu_timerfd_settime;
+  libc->timerfd_gettime_fn = simu_timerfd_gettime;
+
+  libc->if_nametoindex_fn = simu_if_nametoindex;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libc-simu.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,16 @@
+#ifndef LIBC_SIMU_H
+#define LIBC_SIMU_H
+
+#include "libc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void libc_simu (struct Libc *libc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBC_SIMU_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libc.c	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,1103 @@
+#define _GNU_SOURCE 1
+#undef __OPTIMIZE__
+#include "libc.h"
+#include <signal.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include "simu-global-variables.h"
+
+  // macros stolen from glibc.
+#define weak_alias(name, aliasname) \
+  extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)))
+
+
+static struct Libc g_libc;
+
+int printf(const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  int retval = g_libc.vfprintf_fn (stdout, format, ap);
+  va_end (ap);
+  return retval;
+}
+int sprintf(char *str, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  int retval = g_libc.vsprintf_fn (str, format, ap);
+  va_end (ap);
+  return retval;
+}
+int snprintf(char *str, size_t size, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  int retval = g_libc.vsnprintf_fn (str, size, format, ap);
+  va_end (ap);
+  return retval;
+}
+int fprintf(FILE *stream, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  int retval = g_libc.vfprintf_fn (stream, format, ap);
+  va_end (ap);
+  return retval;
+}
+int vprintf(const char *format, va_list ap)
+{
+  return g_libc.vfprintf_fn (stdout, format, ap);
+}
+int vsprintf(char *str, const char *format, va_list ap)
+{
+  return g_libc.vsprintf_fn (str, format, ap);
+}
+int vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+  return g_libc.vsnprintf_fn (str, size, format, ap);
+}
+int vfprintf(FILE *stream, const char *format, va_list ap)
+{
+  return g_libc.vfprintf_fn (stream, format, ap);
+}
+
+int open (const char *pathname, int flags, ...)
+{
+  va_list list;
+  va_start (list, flags);
+  mode_t mode = 0;
+  if (flags & O_CREAT)
+    {
+      mode = va_arg (list, mode_t);
+    }
+  int fd = g_libc.open_fn (pathname, flags, mode);
+  va_end (list);
+  return fd;
+}
+int close (int fd)
+{
+  int retval = g_libc.close_fn (fd);
+  return retval;
+}
+int unlink(const char *pathname)
+{
+  int retval = g_libc.unlink_fn (pathname);
+  return retval;
+}
+int remove (const char *pathname)
+{
+  int retval = g_libc.remove_fn (pathname);
+  return retval;
+}
+int mkdir (const char *pathname, mode_t mode)
+{
+  int retval = g_libc.mkdir_fn (pathname, mode);
+  return retval;
+}
+int rmdir(const char *pathname)
+{
+  int retval = g_libc.rmdir_fn (pathname);
+  return retval;
+}
+int atexit_fn (void (*fn)(void))
+{
+  return g_libc.atexit_fn (fn);
+}
+void __cxa_finalize (void *d)
+{
+  g_libc.__cxa_finalize_fn (d);
+}
+
+int __cxa_atexit (void (*func) (void *), void *arg, void *d)
+{
+  return g_libc.__cxa_atexit_fn (func, arg, d);
+}
+
+int __gxx_personality_v0 (int a, int b, 
+			  unsigned c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
+{
+  return g_libc.__gxx_personality_v0_fn (a,b,c,d,e);
+}
+__locale_t __newlocale (int category_mask, const char *locale, __locale_t base)
+{
+  return g_libc.newlocale_fn (category_mask, locale, base);
+}
+weak_alias (__newlocale, newlocale);
+__locale_t __uselocale (__locale_t __dataset)
+{
+  return g_libc.uselocale_fn (__dataset);
+}
+weak_alias (__uselocale, uselocale);
+int wctob (wint_t c)
+{
+  return g_libc.wctob_fn (c);
+}
+wint_t btowc (int c)
+{
+  return g_libc.btowc_fn (c);
+}
+wctype_t __wctype_l (__const char *__property, __locale_t __locale)
+{
+  return g_libc.wctype_l_fn (__property, __locale);
+}
+weak_alias (__wctype_l, wctype_l);
+int puts (const char *s)
+{
+  return g_libc.fputs_fn (s, stdout);
+}
+int fputs (const char *s, FILE *stream)
+{
+  return g_libc.fputs_fn (s, stream);
+}
+int fputc (int c, FILE *stream)
+{
+  return g_libc.fputc_fn (c, stream);
+}
+int _IO_putc(int c, FILE *stream)
+{
+  return g_libc.fputc_fn (c, stream);
+}
+int putchar (int c)
+{
+  return putc (c, stdout);
+}
+char* fgets (char *s, int size, FILE *stream)
+{
+  return g_libc.fgets_fn (s, size, stream);
+}
+int fgetc (FILE *stream)
+{
+  return g_libc.fgetc_fn (stream);
+}
+// for the getc macro
+int _IO_getc (FILE *stream)
+{
+  return g_libc.fgetc_fn (stream);
+}
+// Note: it looks like that the stdio.h header does
+// not define putc and getc as macros if you include
+// them from C++ so that we do need to define the putc
+// and getc functions anyway. 
+#undef putc
+int putc(int c, FILE *stream)
+{
+  return g_libc.fputc_fn (c, stream);
+}
+#undef getc
+int getc (FILE *stream)
+{
+  return g_libc.fgetc_fn (stream);
+}
+int ungetc(int c, FILE *stream)
+{
+  return g_libc.ungetc_fn (c, stream);
+}
+uint32_t htonl (uint32_t hostlong)
+{
+  return g_libc.htonl_fn (hostlong);
+}
+uint16_t htons (uint16_t hostshort)
+{
+  return g_libc.htons_fn (hostshort);
+}
+uint32_t ntohl (uint32_t netlong)
+{
+  return g_libc.ntohl_fn (netlong);
+}
+uint16_t ntohs (uint16_t netshort)
+{
+  return g_libc.ntohs_fn (netshort);
+}
+int socket (int domain, int type, int protocol)
+{
+  return g_libc.socket_fn (domain, type, protocol);
+}
+int bind (int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  return g_libc.bind_fn (sockfd, my_addr, addrlen);
+}
+ssize_t read (int fd, void *buf, size_t count)
+{
+  return g_libc.read_fn (fd, buf, count);
+}
+int connect (int sockfd, const struct sockaddr *serv_addr,socklen_t addrlen)
+{
+  return g_libc.connect_fn (sockfd, serv_addr, addrlen);
+}
+int listen (int s, int backlog)
+{
+  return g_libc.listen_fn (s, backlog);
+}
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+  return g_libc.accept_fn (sockfd, addr, addrlen);
+}
+int shutdown(int s, int how)
+{
+  return g_libc.shutdown_fn (s, how);
+}
+ssize_t write (int fd, const void *buf, size_t count)
+{
+  return g_libc.write_fn (fd, buf, count);
+}
+ssize_t writev (int fd, const struct iovec *iov, int iovcnt)
+{
+  return g_libc.writev_fn (fd, iov, iovcnt);
+}
+void * memset (void *s, int c, size_t n)
+{
+  return g_libc.memset_fn (s,c,n);
+}
+void *memcpy(void *dest, const void *src, size_t n)
+{
+  return g_libc.memcpy_fn (dest, src, n);
+}
+int memcmp (const void *s1, const void *s2, size_t n)
+{
+  return g_libc.memcmp_fn (s1, s2, n);
+}
+void *memmove(void *dest, const void *src, size_t n)
+{
+  return g_libc.memmove_fn (dest, src, n);
+}
+char *strcpy (char *dest, const char *src)
+{
+  return g_libc.strcpy_fn (dest, src);
+}
+char *strncpy(char *dest, const char *src, size_t n)
+{
+  return g_libc.strncpy_fn (dest, src, n);
+}
+int strcmp(const char *s1, const char *s2)
+{
+  return g_libc.strcmp_fn (s1, s2);
+}
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+  return g_libc.strncmp_fn (s1, s2, n);
+}
+size_t strlen (const char *s)
+{
+  return g_libc.strlen_fn (s);
+}
+char *strchr(const char *s, int c)
+{
+  return g_libc.strchr_fn (s, c);
+}
+char *strrchr(const char *s, int c)
+{
+  return g_libc.strrchr_fn (s, c);
+}
+int strcasecmp(const char *s1, const char *s2)
+{
+  return g_libc.strcasecmp_fn (s1, s2);
+}
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+  return g_libc.strncasecmp_fn (s1, s2, n);
+}
+char *strdup(const char *s)
+{
+  return g_libc.strdup_fn (s);
+}
+weak_alias (strdup, __strdup);
+char *strndup(const char *s, size_t n)
+{
+  return g_libc.strndup_fn (s, n);
+}
+unsigned int sleep(unsigned int seconds)
+{
+  return g_libc.sleep_fn (seconds);
+}
+int nanosleep (const struct timespec *req, struct timespec *rem)
+{
+  return g_libc.nanosleep_fn (req, rem);
+}
+long int random (void)
+{
+  return g_libc.random_fn ();
+}
+int rand (void)
+{
+  return g_libc.rand_fn ();
+}
+void srandom (unsigned int seed)
+{
+  return g_libc.srandom_fn (seed);
+}
+void srand (unsigned int seed)
+{
+  return g_libc.srand_fn (seed);
+}
+FILE *fopen (const char *path, const char *mode)
+{
+  return g_libc.fopen_fn (path, mode);
+}
+FILE *fdopen (int fildes, const char *mode)
+{
+  return g_libc.fdopen_fn (fildes, mode);
+}
+FILE *freopen (const char *path, const char *mode, FILE *stream)
+{
+  return g_libc.freopen_fn (path, mode, stream);
+}
+int fclose (FILE *fp)
+{
+  return g_libc.fclose_fn (fp);
+}
+int fcloseall (void)
+{
+  return g_libc.fcloseall_fn ();
+}
+size_t fread (void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+  return g_libc.fread_fn (ptr, size, nmemb, stream);
+}
+size_t fwrite (const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+  return g_libc.fwrite_fn (ptr, size, nmemb, stream);
+}
+int fflush (FILE *stream)
+{
+  return g_libc.fflush_fn (stream);
+}
+int fseek(FILE *stream, long offset, int whence)
+{
+  return g_libc.fseek_fn (stream, offset, whence);
+}
+long ftell(FILE *stream)
+{
+  return g_libc.ftell_fn (stream);
+}
+int ferror(FILE *stream)
+{
+  return g_libc.ferror_fn (stream);
+}
+int feof (FILE *stream)
+{
+  return g_libc.feof_fn (stream);
+}
+int fileno(FILE *stream)
+{
+  return g_libc.fileno_fn (stream);
+}
+void clearerr(FILE *stream)
+{
+  return g_libc.clearerr_fn (stream);
+}
+int fcntl(int fd, int cmd, ...)
+{
+  unsigned long arg;
+  va_list list;
+  va_start (list, cmd);
+  arg = va_arg (list, unsigned long);
+  va_end (list);
+  int status = g_libc.fcntl_fn (fd, cmd, arg);
+  return status;
+}
+void rewind(FILE *stream)
+{
+  return g_libc.rewind_fn (stream);
+}
+int fgetpos (FILE *stream, fpos_t *pos)
+{
+  return g_libc.fgetpos_fn (stream, pos);
+}
+int fsetpos (FILE *stream, const fpos_t *pos)
+{
+  return g_libc.fsetpos_fn (stream, pos);
+}
+
+
+int setvbuf (FILE *stream, char *buf, int mode, size_t size)
+{
+  return g_libc.setvbuf_fn (stream, buf, mode, size);
+}
+void setbuf(FILE *stream, char *buf)
+{
+  setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
+}
+
+void setbuffer(FILE *stream, char *buf, size_t size)
+{
+  setvbuf(stream, buf, buf ? _IOFBF : _IONBF, size);
+}
+
+void setlinebuf(FILE *stream)
+{
+  setvbuf(stream, (char *) NULL, _IOLBF, 0);
+}
+
+
+int *__errno_location (void)
+{
+  return g_libc.__errno_location_fn ();
+}
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+  return g_libc.getopt_r_fn (argc, argv, optstring, &optarg, &optind, &opterr, &optopt);
+}
+int getopt_long(int argc, char * const argv[], const char *optstring,
+    const struct option *longopts, int *longindex)
+{
+  return g_libc.getopt_long_r_fn (argc, argv, optstring, longopts, longindex,
+    &optarg, &optind, &opterr, &optopt);
+}
+pid_t getpid (void)
+{
+  return g_libc.getpid_fn ();
+}
+pid_t getppid (void)
+{
+  return g_libc.getppid_fn ();
+}
+uid_t getuid(void)
+{
+  return g_libc.getuid_fn ();
+}
+uid_t geteuid(void)
+{
+  return g_libc.geteuid_fn ();
+}
+int setuid(uid_t uid)
+{
+  return g_libc.setuid_fn (uid);
+}
+int setgid(gid_t gid)
+{
+  return g_libc.setgid_fn (gid);
+}
+int seteuid(uid_t euid)
+{
+  return g_libc.seteuid_fn (euid);
+}
+int setegid(gid_t egid)
+{
+  return g_libc.setegid_fn (egid);
+}
+int setreuid(uid_t ruid, uid_t euid)
+{
+  return g_libc.setreuid_fn (ruid, euid);
+}
+int setregid(gid_t rgid, gid_t egid)
+{
+  return g_libc.setregid_fn (rgid, egid);
+}
+int setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+  return g_libc.setresuid_fn (ruid, euid, suid);
+}
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+  return g_libc.setresgid_fn (rgid,egid,sgid);
+}
+int inet_aton(const char *cp, struct in_addr *inp)
+{
+  return g_libc.inet_aton_fn (cp, inp);
+}
+char *inet_ntoa(struct in_addr in)
+{
+  return g_libc.inet_ntoa_fn (in);
+}
+const char *inet_ntop (int af, const void *src,
+		       char *dst, socklen_t cnt)
+{
+  return g_libc.inet_ntop_fn (af, src, dst, cnt);
+}
+in_addr_t inet_network(const char *cp)
+{
+  return g_libc.inet_network_fn (cp);
+}
+struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host)
+{
+  return g_libc.inet_makeaddr_fn (net,host);
+}
+in_addr_t inet_lnaof(struct in_addr in)
+{
+  return g_libc.inet_lnaof_fn (in);
+}
+in_addr_t inet_netof(struct in_addr in)
+{
+  return g_libc.inet_netof_fn (in);
+}
+in_addr_t inet_addr(const char *cp)
+{
+  return g_libc.inet_addr_fn (cp);
+}
+int getsockname(int s, struct sockaddr *name, socklen_t *namelen)
+{
+  return g_libc.getsockname_fn (s, name, namelen);
+}
+int getpeername(int s, struct sockaddr *name, socklen_t *namelen)
+{
+  return g_libc.getpeername_fn (s, name, namelen);
+}
+int select(int nfds, fd_set *readfds, fd_set *writefds,
+		fd_set *exceptfds, struct timeval *timeout)
+{
+  return g_libc.select_fn(nfds, readfds, writefds, exceptfds, timeout);
+}
+int setsockopt (int s, int level, int optname,
+		const void *optval, socklen_t optlen)
+{
+  return g_libc.setsockopt_fn (s, level, optname, optval, optlen);
+}
+int getsockopt(int s, int level, int optname,
+	       void *optval, socklen_t *optlen)
+{
+  return g_libc.getsockopt_fn (s, level, optname, optval, optlen);
+}
+void *calloc (size_t nmemb, size_t size)
+{
+  return g_libc.calloc_fn (nmemb, size);
+}
+void *malloc (size_t size)
+{
+  return g_libc.malloc_fn (size);
+}
+void free (void *ptr)
+{
+  return g_libc.free_fn (ptr);
+}
+void *realloc (void *ptr, size_t size)
+{
+  return g_libc.realloc_fn (ptr, size);
+}
+sighandler_t signal(int signum, sighandler_t handler)
+{
+  return g_libc.signal_fn (signum, handler);
+}
+int sigaction(int signum, const struct sigaction *act,
+	      struct sigaction *oldact)
+{
+  return g_libc.sigaction_fn (signum, act, oldact);
+}
+int sigemptyset(sigset_t *set)
+{
+  return g_libc.sigemptyset_fn (set);
+}
+int sigfillset(sigset_t *set)
+{
+  return g_libc.sigfillset_fn (set);
+}
+int sigaddset(sigset_t *set, int signum)
+{
+  return g_libc.sigaddset_fn (set, signum);
+}
+int sigdelset(sigset_t *set, int signum)
+{
+  return g_libc.sigdelset_fn (set, signum);
+}
+int sigismember(const sigset_t *set, int signum)
+{
+  return g_libc.sigismember_fn (set, signum);
+}
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+  return g_libc.gettimeofday_fn (tv, tz);
+}
+time_t time(time_t *t)
+{
+  return g_libc.time_fn (t);
+}
+int isatty(int desc)
+{
+  return g_libc.isatty_fn (desc);
+}
+ssize_t send(int s, const void *buf, size_t len, int flags)
+{
+  return g_libc.send_fn (s, buf, len, flags);
+}
+ssize_t sendto(int s, const void *buf, size_t len, int flags,
+	       const struct sockaddr *to, socklen_t tolen)
+{
+  return g_libc.sendto_fn (s, buf, len, flags, to, tolen);
+}
+ssize_t sendmsg(int s, const struct msghdr *msg, int flags)
+{
+  return g_libc.sendmsg_fn (s, msg, flags);
+}
+ssize_t recv(int s, void *buf, size_t len, int flags)
+{
+  return g_libc.recv_fn (s, buf, len, flags);
+}
+ssize_t recvfrom(int s, void *buf, size_t len, int flags,
+		 struct sockaddr *from, socklen_t *fromlen)
+{
+  return g_libc.recvfrom_fn (s, buf, len, flags, from, fromlen);
+}
+ssize_t recvmsg(int s, struct msghdr *msg, int flags)
+{
+  return g_libc.recvmsg_fn (s, msg, flags);
+}
+int ioctl(int d, int request, ...)
+{
+  va_list ap;
+  va_start (ap, request);
+  char *argp = va_arg (ap, char *);
+  int retval = g_libc.ioctl_fn (d, request, argp);
+  va_end (ap);
+  return retval;
+}
+int sched_yield(void)
+{
+  return g_libc.sched_yield_fn ();
+}
+int poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+  return g_libc.poll_fn (fds, nfds, timeout);
+}
+struct cmsghdr *__cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
+{
+  return g_libc.__cmsg_nxthdr_fn (mhdr, cmsg);
+}
+int atoi(const char *nptr)
+{
+  return g_libc.atoi_fn (nptr);
+}
+long atol(const char *nptr)
+{
+  return g_libc.atol_fn (nptr);
+}
+long long atoll(const char *nptr)
+{
+  return g_libc.atoll_fn (nptr);
+}
+long long atoq(const char *nptr)
+{
+  return g_libc.atoll_fn (nptr);
+}
+double atof(const char *nptr)
+{
+  return g_libc.atof_fn (nptr);
+}
+int getitimer(int which, struct itimerval *value)
+{
+  return g_libc.getitimer_fn (which, value);
+}
+int setitimer(int which, const struct itimerval *value,
+	      struct itimerval *ovalue)
+{
+  return g_libc.setitimer_fn (which, value, ovalue);
+}
+void exit(int status)
+{
+  g_libc.exit_fn (status);
+  int a = 0;
+  while (1)
+    {
+      // loop forever to quiet compiler warning:
+      // warning: ‘noreturn’ function does return
+      a++;
+    }
+}
+long int strtol (const char *nptr, char **endptr, int base)
+{
+  return g_libc.strtol_fn (nptr, endptr, base);
+}
+long long int strtoll (const char *nptr, char **endptr, int base)
+{
+  return g_libc.strtoll_fn (nptr, endptr, base);
+}
+unsigned long int strtoul(const char *nptr, char **endptr, int base)
+{
+  return g_libc.strtoul_fn (nptr, endptr, base);
+}
+unsigned long long int strtoull(const char *nptr, char **endptr,
+				int base)
+{
+  return g_libc.strtoull_fn (nptr, endptr, base);
+}
+
+long int __strtol_internal (const char *nptr, char **endptr, int base, int group)
+{
+  return g_libc.strtol_fn (nptr, endptr, base);
+}
+double strtod (const char *nptr, char **endptr)
+{
+  return g_libc.strtod_fn (nptr, endptr);
+}
+void herror(const char *s)
+{}
+char *setlocale(int category, const char *locale)
+{
+  static char loc[] = "";
+  return loc;
+}
+char *getcwd(char *buf, size_t size)
+{
+  return g_libc.getcwd_fn (buf, size);
+}
+char *getwd(char *buf)
+{
+  return g_libc.getwd_fn (buf);
+}
+
+char *get_current_dir_name(void)
+{
+  return g_libc.get_current_dir_name_fn ();
+}
+int chdir(const char *path)
+{
+  return g_libc.chdir_fn (path);
+}
+int fchdir(int fd)
+{
+  return g_libc.fchdir_fn (fd);
+}
+int pthread_create (pthread_t *thread,
+		    const pthread_attr_t *attr,
+		    void *(*start_routine)(void*), void * arg)
+{
+  return g_libc.pthread_create_fn (thread, attr, start_routine, arg);
+}
+void pthread_exit(void *retval)
+{
+  return g_libc.pthread_exit_fn (retval);
+}
+pthread_t pthread_self (void)
+{
+  return g_libc.pthread_self_fn ();
+}
+int pthread_cancel (pthread_t thread)
+{
+  return g_libc.pthread_cancel_fn (thread);
+}
+int pthread_mutex_destroy (pthread_mutex_t *mutex)
+{
+  return g_libc.pthread_mutex_destroy_fn (mutex);
+}
+int pthread_mutex_init (pthread_mutex_t * mutex,
+			const pthread_mutexattr_t * attr)
+{
+  return g_libc.pthread_mutex_init_fn (mutex, attr);
+}
+int pthread_mutex_lock (pthread_mutex_t *mutex)
+{
+  return g_libc.pthread_mutex_lock_fn (mutex);
+}
+int pthread_mutex_unlock (pthread_mutex_t *mutex)
+{
+  return g_libc.pthread_mutex_unlock_fn (mutex);
+}
+int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+  return g_libc.pthread_mutex_trylock_fn (mutex);
+}
+int pthread_mutexattr_init (pthread_mutexattr_t *attribute)
+{
+  return g_libc.pthread_mutexattr_init_fn (attribute);
+}
+int pthread_mutexattr_destroy (pthread_mutexattr_t *attribute)
+{
+  return g_libc.pthread_mutexattr_destroy_fn (attribute);
+}
+int pthread_mutexattr_settype (pthread_mutexattr_t *attribute, int kind)
+{
+  return g_libc.pthread_mutexattr_settype_fn (attribute, kind);
+}
+int pthread_once (pthread_once_t *once_control, void (*init_routine)(void))
+{
+  return g_libc.pthread_once_fn (once_control, init_routine);
+}
+void *pthread_getspecific (pthread_key_t key)
+{
+  return g_libc.pthread_getspecific_fn (key);
+}
+int pthread_setspecific (pthread_key_t key, const void *value)
+{
+  return g_libc.pthread_setspecific_fn (key, value);
+}
+int pthread_key_create (pthread_key_t *key, void (*destructor)(void*))
+{
+  return g_libc.pthread_key_create_fn (key, destructor);
+}
+int pthread_key_delete (pthread_key_t key)
+{
+  return g_libc.pthread_key_delete_fn (key);
+}
+int pthread_kill (pthread_t thread, int sig)
+{
+  return g_libc.pthread_kill_fn (thread, sig);
+}
+int pthread_join (pthread_t thread_handle, void **value_ptr)
+{
+  return g_libc.pthread_join_fn (thread_handle, value_ptr);
+}
+int pthread_detach(pthread_t thread)
+{
+  return g_libc.pthread_detach_fn (thread);
+}
+int __xstat (int ver, const char *filename,
+	     struct stat *stat_buf)
+{
+  return g_libc.xstat_fn (ver, filename, stat_buf);
+}
+int __fxstat (int ver, int fd,
+	      struct stat *stat_buf)
+{
+  return g_libc.fxstat_fn (ver, fd, stat_buf);
+}
+int __lxstat (int ver, const char *pathname,
+	      struct stat *stat_buf)
+{
+  return g_libc.lxstat_fn (ver, pathname, stat_buf);
+}
+int __xstat64 (int ver, const char *filename,
+	       struct stat64 *stat_buf)
+{
+  return g_libc.xstat64_fn (ver, filename, stat_buf);
+}
+int __fxstat64 (int ver, int fd,
+		struct stat64 *stat_buf)
+{
+  return g_libc.fxstat64_fn (ver, fd, stat_buf);
+}
+int __lxstat64 (int ver, const char *pathname,
+		struct stat64 *stat_buf)
+{
+  return g_libc.lxstat64_fn (ver, pathname, stat_buf);
+}
+
+int open64 (const char *file, int oflag, ...)
+{
+  va_list list;
+  va_start (list, oflag);
+  mode_t mode = 0;
+  if (oflag & O_CREAT)
+    {
+      mode = va_arg (list, mode_t);
+    }
+  int fd = g_libc.open_fn (file, oflag, mode);
+  va_end (list);
+  return fd;
+}
+void *
+mmap64 (void *addr, size_t len, int prot, int flags, int fd, off64_t offset)
+{
+  return g_libc.mmap64_fn (addr, len, prot, flags, fd, offset);
+}
+void *
+mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+  return g_libc.mmap64_fn (addr, len, prot, flags, fd, offset);
+}
+int munmap(void *start, size_t length)
+{
+  return g_libc.munmap_fn (start, length);
+}
+int dup(int oldfd)
+{
+  return g_libc.dup_fn (oldfd);
+}
+int dup2(int oldfd, int newfd)
+{
+  return g_libc.dup2_fn (oldfd, newfd);
+}
+struct tm *localtime(const time_t *timep)
+{
+  return g_libc.localtime_fn (timep);
+}
+size_t strftime(char *s, size_t max, const char *format,
+		const struct tm *tm)
+{
+  return g_libc.strftime_fn (s, max, format, tm);
+}
+const unsigned short int **__ctype_b_loc (void)
+{
+  return g_libc.__ctype_b_loc_fn ();
+}
+char *strerror (int errnum)
+{
+  return g_libc.strerror_fn (errnum);
+}
+int __xpg_strerror_r (int errnum, char *buf, size_t buflen)
+{
+  return g_libc.xsi_strerror_r_fn (errnum, buf, buflen);
+}
+char * strerror_r(int errnum, char *buf, size_t buflen)
+{
+  return g_libc.gnu_strerror_r_fn (errnum, buf, buflen);
+}
+void perror(const char *s)
+{
+  fprintf (stderr, "%s: %s\n", s, strerror (*(g_libc.__errno_location_fn ())));
+}
+struct tm *gmtime_r(const time_t *timep, struct tm *result)
+{
+  return g_libc.gmtime_r_fn (timep, result);
+}
+struct tm *gmtime(const time_t *timep)
+{
+  static struct tm result;
+  return g_libc.gmtime_r_fn (timep, &result);
+}
+int sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+  return g_libc.sem_init_fn (sem, pshared, value);
+}
+int sem_destroy(sem_t *sem)
+{
+  return g_libc.sem_destroy_fn (sem);
+}
+int sem_post(sem_t *sem)
+{
+  return g_libc.sem_post_fn (sem);
+}
+int sem_wait(sem_t *sem)
+{
+  return g_libc.sem_wait_fn (sem);
+}
+int sem_trywait(sem_t *sem)
+{
+  return g_libc.sem_trywait_fn (sem);
+}
+int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
+{
+  return g_libc.sem_timedwait_fn (sem, abs_timeout);
+}
+int sem_getvalue(sem_t *sem, int *sval)
+{
+  return g_libc.sem_getvalue_fn (sem, sval);
+}
+int pthread_cond_destroy (pthread_cond_t *cond)
+{
+  return g_libc.pthread_cond_destroy_fn (cond);
+}
+int pthread_cond_init (pthread_cond_t *cond,
+		       const pthread_condattr_t *attr)
+{
+  return g_libc.pthread_cond_init_fn (cond, attr);
+}
+int pthread_cond_broadcast (pthread_cond_t *cond)
+{
+  return g_libc.pthread_cond_broadcast_fn (cond);
+}
+int pthread_cond_signal (pthread_cond_t *cond)
+{
+  return g_libc.pthread_cond_signal_fn (cond);
+}
+int pthread_cond_timedwait(pthread_cond_t * cond,
+			   pthread_mutex_t * mutex,
+			   const struct timespec * abstime)
+{
+  return g_libc.pthread_cond_timedwait_fn (cond, mutex, abstime);
+}
+int pthread_cond_wait(pthread_cond_t * cond,
+		      pthread_mutex_t * mutex)
+{
+  return g_libc.pthread_cond_wait_fn (cond, mutex);
+}
+int pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+  return g_libc.pthread_condattr_destroy_fn (attr);
+}
+int pthread_condattr_init(pthread_condattr_t *attr)
+{
+  return g_libc.pthread_condattr_init_fn (attr);
+}
+
+struct hostent *gethostbyname (const char *name)
+{
+  return g_libc.gethostbyname_fn (name);
+}
+struct hostent *gethostbyname2(const char *name, int af)
+{
+  return g_libc.gethostbyname2_fn (name, af);
+}
+int getaddrinfo(const char *node, const char *service,
+		const struct addrinfo *hints,
+		struct addrinfo **res)
+{
+  return g_libc.getaddrinfo_fn (node, service, hints, res);
+}
+
+void freeaddrinfo(struct addrinfo *res)
+{
+  return g_libc.freeaddrinfo_fn (res);
+}
+
+const char *gai_strerror(int errcode)
+{
+  return g_libc.strerror_fn (errcode);
+}
+
+char *getenv (const char *name)
+{
+  return g_libc.getenv_fn (name);
+}
+int putenv(char *string)
+{
+  return g_libc.putenv_fn (string);
+}
+int setenv(const char *name, const char *value, int overwrite)
+{
+  return g_libc.setenv_fn (name, value, overwrite);
+}
+int unsetenv(const char *name)
+{
+  return g_libc.unsetenv_fn (name);
+}
+int clearenv(void)
+{
+  return g_libc.clearenv_fn ();
+}
+int toupper(int c)
+{
+  return g_libc.toupper_fn (c);
+}
+int tolower(int c)
+{
+  return g_libc.tolower_fn (c);
+}
+
+
+int timerfd_create (int clockid, int flags)
+{
+  return g_libc.timerfd_create_fn (clockid, flags);
+}
+int timerfd_settime(int fd, int flags,
+			 const struct itimerspec *new_value,
+			 struct itimerspec *old_value)
+{
+  return g_libc.timerfd_settime_fn (fd, flags, new_value, old_value);
+}
+int timerfd_gettime (int fd, struct itimerspec *cur_value)
+{
+  return g_libc.timerfd_gettime_fn (fd, cur_value);
+}
+
+unsigned if_nametoindex (const char *ifname) {
+  return g_libc.if_nametoindex_fn (ifname);
+}
+void LIBSETUP (const struct Libc *fn)
+{
+  /* The following assignment of fn to g_libc is a bit weird: we perform a copy of the data 
+   * structures by hand rather than executing g_libc = fn. This is obviously done on purpose. 
+   * The reason is that g_libc = fn would trigger a call to the memcpy function because the 
+   * Libc structure is very big. The memcpy function is resolved through the dynamic loader's 
+   * symbol lookup mechanism to the local memcpy function and that local memcpy function happens 
+   * to be calling g_libc.memcpy_fn which is set to NULL before the data structure is initialized. 
+   */
+  const uint8_t *src = (const uint8_t *)fn;
+  uint8_t *dst = (uint8_t *)&g_libc;
+  uint32_t i;
+  for (i = 0; i < sizeof (struct Libc); ++i)
+    {
+      *dst = *src;
+      src++;
+      dst++;
+    }
+  struct SimuGlobalVariables globals;
+  globals.pstdin = &stdin;
+  globals.pstdout = &stdout;
+  globals.pstderr = &stderr;
+  globals.penvp = &environ;
+  g_libc.global_variables_setup (&globals);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libc.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,303 @@
+
+#ifndef LIBC_H
+#define LIBC_H
+#define _LARGEFILE64_SOURCE 1
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <locale.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <poll.h>
+#include <semaphore.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct stat;
+struct stat64;
+struct _Unwind_Context;
+struct _Unwind_Exception;
+struct timezone;
+struct itimerval;
+struct sigaction;
+struct option;
+struct addrinfo;
+struct itimerspec;
+struct SimuGlobalVariables;
+
+struct Libc
+{
+  void (*global_variables_setup) (struct SimuGlobalVariables *globals);
+  int (*vfprintf_fn) (FILE *, const char *, va_list);
+  int (*vsprintf_fn) (char *, const char *, va_list);
+  int (*vsnprintf_fn) (char *, size_t, const char *, va_list);
+  void *(*mmap64_fn) (void *addr, size_t len, int prot, int flags, int fd, off64_t offset);
+  int (*munmap_fn) (void *start, size_t length);
+
+  int (*xstat_fn) (int, const char *, struct stat *);
+  int (*fxstat_fn) (int, int , struct stat *);
+  int (*lxstat_fn) (int, const char *, struct stat *);
+
+  int (*xstat64_fn) (int, const char *, struct stat64 *);
+  int (*fxstat64_fn) (int, int , struct stat64 *);
+  int (*lxstat64_fn) (int, const char *, struct stat64 *);
+
+  int (*open_fn) (const char *, int, mode_t );
+  int (*close_fn) (int);
+  int (*fcntl_fn)(int fd, int cmd, unsigned long arg);
+  int (*unlink_fn) (const char *);
+  int (*remove_fn) (const char *);
+  int (*mkdir_fn) (const char *pathname, mode_t mode);
+  int (*rmdir_fn) (const char *pathname);
+  int (*dup_fn) (int);
+  int (*dup2_fn) (int, int);
+  int (*atexit_fn) (void (*)(void));
+  void (*__cxa_finalize_fn) (void *d);
+  int (*__cxa_atexit_fn) (void (*func) (void *), void *arg, void *d);
+  int (*__gxx_personality_v0_fn) (int a, int b, 
+				  unsigned c, struct _Unwind_Exception *d, struct _Unwind_Context *e);
+  __locale_t (*newlocale_fn) (int category_mask, const char *locale, __locale_t base);
+  __locale_t (*uselocale_fn) (__locale_t __dataset);
+  int (*wctob_fn) (wint_t c);
+  wint_t (*btowc_fn) (int c);
+  wctype_t (*wctype_l_fn) (__const char *__property, __locale_t __locale);
+
+  uint32_t (*htonl_fn) (uint32_t hostlong);
+  uint16_t (*htons_fn) (uint16_t hostshort);
+  uint32_t (*ntohl_fn) (uint32_t netlong);
+  uint16_t (*ntohs_fn) (uint16_t netshort);
+  int (*socket_fn) (int domain, int type, int protocol);
+  int (*getsockname_fn) (int s, struct sockaddr *name, socklen_t *namelen);
+  int (*getpeername_fn) (int s, struct sockaddr *name, socklen_t *namelen);
+  int (*bind_fn) (int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
+  ssize_t (*read_fn) (int fd, void *buf, size_t count);
+  int (*connect_fn) (int sockfd, const struct sockaddr *serv_addr,socklen_t addrlen);
+  ssize_t (*write_fn) (int fd, const void *buf, size_t count);
+  ssize_t (*writev_fn) (int fd, const struct iovec *iov, int iovcnt);
+  int (*setsockopt_fn) (int s, int level, int optname,
+			const void *optval, socklen_t optlen);
+  int (*getsockopt_fn) (int s, int level, int optname,
+			void *optval, socklen_t *optlen);
+  int (*select_fn)(int nfds, fd_set *readfds, fd_set *writefds,
+                     fd_set *exceptfds, struct timeval *timeout);
+  int (*listen_fn) (int s, int backlog);
+  int (*accept_fn) (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+  int (*shutdown_fn) (int s, int how);
+  void * (*memset_fn) (void *s, int c, size_t n);
+  void * (*memcpy_fn) (void *dest, const void *src, size_t n);
+  int (*memcmp_fn) (const void *s1, const void *s2, size_t n);
+  void *(*memmove_fn) (void *dest, const void *src, size_t n);
+  char *(*strcpy_fn) (char *dest, const char *src);
+  char *(*strncpy_fn) (char *dest, const char *src, size_t n);
+  int (*strcmp_fn)(const char *s1, const char *s2);
+  int (*strncmp_fn) (const char *s1, const char *s2, size_t n);
+  size_t (*strlen_fn) (const char *s);
+  char *(*strchr_fn) (const char *s, int c);
+  char *(*strrchr_fn) (const char *s, int c);
+  int (*strcasecmp_fn) (const char *s1, const char *s2);
+  int (*strncasecmp_fn) (const char *s1, const char *s2, size_t n);
+  char *(*strdup_fn) (const char *s);
+  char *(*strndup_fn) (const char *s, size_t n);
+  unsigned int (*sleep_fn) (unsigned int seconds);
+  int (*nanosleep_fn) (const struct timespec *req, struct timespec *rem);
+
+  long int (*random_fn)(void);
+  int (*rand_fn)(void);
+  void (*srandom_fn)(unsigned int seed);
+  void (*srand_fn)(unsigned int seed);
+
+  FILE *(*fopen_fn) (const char *path, const char *mode);
+  FILE *(*fdopen_fn) (int fildes, const char *mode);
+  FILE *(*freopen_fn) (const char *path, const char *mode, FILE *stream);
+  int (*fclose_fn) (FILE *fp);
+  int (*fcloseall_fn) (void);
+  size_t (*fread_fn) (void *ptr, size_t size, size_t nmemb, FILE *stream);
+  size_t (*fwrite_fn) (const void *ptr, size_t size, size_t nmemb,
+		       FILE *stream);
+  int (*fputs_fn) (const char *, FILE *);
+  int (*fputc_fn) (int, FILE *);
+  char* (*fgets_fn) (char *, int, FILE *);
+  int (*fgetc_fn) (FILE *);
+  int (*ungetc_fn) (int c, FILE *stream);
+
+  int (*fflush_fn) (FILE *stream);
+  int (*fseek_fn)(FILE *stream, long offset, int whence);
+  long (*ftell_fn)(FILE *stream);
+  void (*rewind_fn)(FILE *stream);
+  int (*fgetpos_fn) (FILE *stream, fpos_t *pos);
+  int (*fsetpos_fn) (FILE *stream, const fpos_t *pos);
+
+  int (*ferror_fn)(FILE *stream);
+  int (*feof_fn)(FILE *stream);
+  int (*fileno_fn) (FILE *stream);
+  void (*clearerr_fn) (FILE *stream);
+
+
+  int (*setvbuf_fn) (FILE *stream, char *buf, int mode, size_t size);
+
+
+  int *(*__errno_location_fn) (void);
+  int (*getopt_r_fn) (int argc, char * const argv[], const char *optstring, 
+		      char **poptarg, int *poptind, int *popterr, int *poptopt);
+  int (*getopt_long_r_fn) (int argc, char * const argv[], const char *optstring, 
+      const struct option *longopts, int *longindex,
+      char **poptarg, int *poptind, int *popterr, int *poptopt);
+  pid_t (*getpid_fn) (void);
+  pid_t (*getppid_fn) (void);
+  uid_t (*getuid_fn) (void);
+  uid_t (*geteuid_fn) (void);
+  int (*setuid_fn) (uid_t uid);
+  int (*setgid_fn) (gid_t gid);
+  int (*seteuid_fn) (uid_t euid);
+  int (*setegid_fn) (gid_t egid);
+  int (*setreuid_fn) (uid_t ruid, uid_t euid);
+  int (*setregid_fn) (gid_t rgid, gid_t egid);
+  int (*setresuid_fn) (uid_t ruid, uid_t euid, uid_t suid);
+  int (*setresgid_fn) (gid_t rgid, gid_t egid, gid_t sgid);
+
+  int (*inet_aton_fn) (const char *cp, struct in_addr *inp);
+  char *(*inet_ntoa_fn) (struct in_addr in);
+  const char *(*inet_ntop_fn) (int af, const void *src,
+			       char *dst, socklen_t cnt);
+  in_addr_t (*inet_network_fn) (const char *cp);
+  struct in_addr (*inet_makeaddr_fn) (in_addr_t net, in_addr_t host);
+  in_addr_t (*inet_lnaof_fn)(struct in_addr in);
+  in_addr_t (*inet_netof_fn)(struct in_addr in);
+  in_addr_t (*inet_addr_fn) (const char *cp);
+
+  void *(*calloc_fn) (size_t nmemb, size_t size);
+  void *(*malloc_fn) (size_t size);
+  void (*free_fn) (void *ptr);
+  void *(*realloc_fn) (void *ptr, size_t size);
+  int (*gettimeofday_fn) (struct timeval *tv, struct timezone *tz);
+  time_t (*time_fn) (time_t *t);
+  int (*isatty_fn) (int desc);
+  ssize_t (*send_fn)(int s, const void *buf, size_t len, int flags);
+  ssize_t (*sendto_fn)(int s, const void *buf, size_t len, int flags,
+		       const struct sockaddr *to, socklen_t tolen);
+  ssize_t (*sendmsg_fn)(int s, const struct msghdr *msg, int flags);
+  ssize_t (*recv_fn) (int s, void *buf, size_t len, int flags);
+  ssize_t (*recvfrom_fn) (int s, void *buf, size_t len, int flags,
+			  struct sockaddr *from, socklen_t *fromlen);
+  ssize_t (*recvmsg_fn) (int s, struct msghdr *msg, int flags);
+  int (*ioctl_fn) (int d, int request, char *argp);
+  int (*sched_yield_fn) (void);
+  int (*poll_fn) (struct pollfd *fds, nfds_t nfds, int timeout);
+  struct cmsghdr *(*__cmsg_nxthdr_fn) (struct msghdr *mhdr, struct cmsghdr *cmsg);
+  int (*atoi_fn) (const char *nptr);
+  long (*atol_fn) (const char *nptr);
+  long long (*atoll_fn) (const char *nptr);
+  double (*atof_fn) (const char *nptr);
+  int (*getitimer_fn)(int which, struct itimerval *value);
+  int (*setitimer_fn)(int which, const struct itimerval *value,
+		      struct itimerval *ovalue);
+  void (*exit_fn) (int status);
+  sighandler_t (*signal_fn) (int signum, sighandler_t handler);
+  int (*sigaction_fn) (int signum, const struct sigaction *act,
+		       struct sigaction *oldact);
+  int (*sigemptyset_fn) (sigset_t *set);
+  int (*sigfillset_fn) (sigset_t *set);
+  int (*sigaddset_fn) (sigset_t *set, int signum);
+  int (*sigdelset_fn) (sigset_t *set, int signum);
+  int (*sigismember_fn) (const sigset_t *set, int signum);
+  long int (*strtol_fn) (const char *nptr, char **endptr, int base);
+  long long int (*strtoll_fn) (const char *nptr, char **endptr, int base);
+  unsigned long int (*strtoul_fn) (const char *nptr, char **endptr, int base);
+  unsigned long long int (*strtoull_fn) (const char *nptr, char **endptr, int base);
+  double (*strtod_fn) (const char *nptr, char **endptr);
+  char *(*getcwd_fn) (char *buf, size_t size);
+  char *(*getwd_fn) (char *buf);
+  char *(*get_current_dir_name_fn) (void);
+  int (*chdir_fn) (const char *path);
+  int (*fchdir_fn) (int fd);
+  struct tm *(*localtime_fn)(const time_t *timep);
+  size_t (*strftime_fn) (char *s, size_t max, const char *format,
+			 const struct tm *tm);
+  const unsigned short int **(*__ctype_b_loc_fn) (void);
+  char *(*strerror_fn) (int errnum);
+  int (*xsi_strerror_r_fn)(int errnum, char *buf, size_t buflen);
+  char *(*gnu_strerror_r_fn)(int errnum, char *buf, size_t buflen);
+
+  int (*pthread_create_fn) (pthread_t *thread,
+			    const pthread_attr_t *attr,
+			    void *(*start_routine)(void*), void * arg);
+  void (*pthread_exit_fn) (void *retval);
+  pthread_t (*pthread_self_fn) (void);
+  int (*pthread_mutex_destroy_fn) (pthread_mutex_t *mutex);
+  int (*pthread_mutex_init_fn) (pthread_mutex_t * mutex,
+				const pthread_mutexattr_t * attr);
+  int (*pthread_mutex_lock_fn) (pthread_mutex_t *mutex);
+  int (*pthread_mutex_unlock_fn) (pthread_mutex_t *mutex);
+  int (*pthread_mutex_trylock_fn) (pthread_mutex_t *mutex);
+  int (*pthread_mutexattr_init_fn) (pthread_mutexattr_t *attribute);
+  int (*pthread_mutexattr_destroy_fn) (pthread_mutexattr_t *attribute);
+  int (*pthread_mutexattr_settype_fn) (pthread_mutexattr_t *attribute, int kind);
+  int (*pthread_key_create_fn) (pthread_key_t *key, void (*destructor)(void*));
+  int (*pthread_key_delete_fn) (pthread_key_t key);
+  int (*pthread_setspecific_fn) (pthread_key_t key, const void *value);
+  void *(*pthread_getspecific_fn) (pthread_key_t key);
+  int (*pthread_once_fn) (pthread_once_t *, void (*)(void));
+  int (*pthread_cancel_fn) (pthread_t thread);
+  int (*pthread_kill_fn) (pthread_t thread, int sig);
+  int (*pthread_join_fn) (pthread_t thread_handle, void **value_ptr);
+  int (*pthread_detach_fn) (pthread_t thread);
+  int (*sem_init_fn)(sem_t *sem, int pshared, unsigned int value);
+  int (*sem_destroy_fn)(sem_t *sem);
+  int (*sem_post_fn)(sem_t *sem);
+  int (*sem_wait_fn)(sem_t *sem);
+  int (*sem_trywait_fn)(sem_t *sem);
+  int (*sem_timedwait_fn)(sem_t *sem, const struct timespec *abs_timeout);
+  int (*sem_getvalue_fn)(sem_t *sem, int *sval);
+  int (*pthread_cond_destroy_fn) (pthread_cond_t *cond);
+  int (*pthread_cond_init_fn) (pthread_cond_t *cond,
+			       const pthread_condattr_t *attr);
+  int (*pthread_cond_broadcast_fn) (pthread_cond_t *cond);
+  int (*pthread_cond_signal_fn) (pthread_cond_t *cond);
+  int (*pthread_cond_timedwait_fn)(pthread_cond_t * cond,
+				   pthread_mutex_t * mutex,
+				   const struct timespec * abstime);
+  int (*pthread_cond_wait_fn)(pthread_cond_t * cond,
+			      pthread_mutex_t * mutex);
+  int (*pthread_condattr_destroy_fn)(pthread_condattr_t *attr);
+  int (*pthread_condattr_init_fn)(pthread_condattr_t *attr);
+
+  struct tm *(*gmtime_r_fn)(const time_t *timep, struct tm *result);
+
+  struct hostent *(*gethostbyname_fn) (const char *name);
+  struct hostent *(*gethostbyname2_fn) (const char *name, int af);
+  int (*getaddrinfo_fn) (const char *node, const char *service,
+			 const struct addrinfo *hints,
+			 struct addrinfo **res);
+  void (*freeaddrinfo_fn) (struct addrinfo *res);
+  const char *(*gai_strerror_fn)(int errcode);
+  char *(*getenv_fn) (const char *name);
+  int (*putenv_fn)(char *string);
+  int (*setenv_fn)(const char *name, const char *value, int overwrite);
+  int (*unsetenv_fn)(const char *name);
+  int (*clearenv_fn)(void);
+  int (*toupper_fn)(int c);
+  int (*tolower_fn)(int c);
+
+
+  int (*timerfd_create_fn) (int clockid, int flags);
+  int (*timerfd_settime_fn)(int fd, int flags,
+			 const struct itimerspec *new_value,
+			 struct itimerspec *old_value);
+  int (*timerfd_gettime_fn) (int fd, struct itimerspec *cur_value);
+
+  unsigned (*if_nametoindex_fn) (const char *ifname);
+
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/libpthread-ns3.version	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,4 @@
+NS3 {
+global:
+	libpthread_setup;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/linux-socket-fd-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,743 @@
+#include "linux-socket-fd-factory.h"
+#include "linux-socket-fd.h"
+#include "loader-factory.h"
+#include "dce-manager.h"
+#include "process.h"
+#include "utils.h"
+#include "task-manager.h"
+#include "alloc.h"
+#include "sim/include/sim-init.h"
+#include "ns3/log.h"
+#include "ns3/string.h"
+#include "ns3/node.h"
+#include "ns3/net-device.h"
+#include "ns3/random-variable.h"
+#include "ns3/event-id.h"
+#include "ns3/simulator.h"
+#include "ns3/mac48-address.h"
+#include "ns3/packet.h"
+#include <dlfcn.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+NS_LOG_COMPONENT_DEFINE("LinuxSocketFdFactory");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED(LinuxSocketFdFactory);
+
+TypeId 
+LinuxSocketFdFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::LinuxSocketFdFactory")
+    .SetParent<SocketFdFactory> ()
+    .AddConstructor<LinuxSocketFdFactory> ()
+    .AddAttribute ("Library", "File to load in memory",
+		   StringValue("liblinux.so"),
+		   MakeStringAccessor (&LinuxSocketFdFactory::m_library),
+		   MakeStringChecker ())
+    ;
+  return tid;
+}
+LinuxSocketFdFactory::LinuxSocketFdFactory ()
+  : m_loader (0),
+    m_exported (0),
+    m_alloc (new KingsleyAlloc ()),
+    m_logFile (0)
+{}
+
+LinuxSocketFdFactory::~LinuxSocketFdFactory ()
+{
+  for (uint32_t i = 0; i < m_devices.size(); i++)
+    {
+      // Note: we don't really destroy devices from here
+      // because calling destroy requires a task context
+      // m_exported->dev_destroy(m_devices[i].second);
+    }
+  delete m_exported;
+  delete m_loader;
+  delete m_alloc;
+  if (m_logFile != 0)
+    {
+      fclose (m_logFile);
+    }
+  m_exported = 0;
+  m_loader = 0;
+  m_alloc = 0;
+  m_logFile = 0;
+}
+
+void 
+LinuxSocketFdFactory::DoDispose (void)
+{
+  for (std::list<Task *>::const_iterator i = m_kernelTasks.begin (); i != m_kernelTasks.end (); ++i)
+    {
+      m_manager->Stop (*i);
+    }
+  m_kernelTasks.clear ();
+  m_manager = 0;
+}
+
+int 
+LinuxSocketFdFactory::Vprintf (struct SimKernel *kernel, const char *str, va_list args)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  return vfprintf (self->m_logFile, str, args);
+}
+
+void *
+LinuxSocketFdFactory::Malloc (struct SimKernel *kernel, unsigned long size)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  size += sizeof (size_t);
+  uint8_t *buffer = self->m_alloc->Malloc (size);
+  memcpy (buffer, &size, sizeof (size_t));
+  buffer += sizeof (size_t);
+  return buffer;
+}
+void 
+LinuxSocketFdFactory::Free (struct SimKernel *kernel, void *ptr)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  uint8_t *buffer = (uint8_t*)ptr;
+  size_t size;
+  buffer -= sizeof (size_t);
+  memcpy (&size, buffer, sizeof (size_t));
+  self->m_alloc->Free (buffer, size);
+}
+void *
+LinuxSocketFdFactory::Memcpy (struct SimKernel *kernel, void *dst, const void *src, unsigned long size)
+{
+  return memcpy (dst, src, size);
+}
+void *
+LinuxSocketFdFactory::Memset (struct SimKernel *kernel, void *dst, char value, unsigned long size)
+{
+  return memset (dst, value, size);
+}
+unsigned long 
+LinuxSocketFdFactory::Random (struct SimKernel *kernel)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  union {
+    uint8_t buffer[sizeof(unsigned long)];
+    unsigned long v;
+  } u;
+  for (uint8_t i = 0; i < sizeof(u.buffer); i++)
+    {
+      u.buffer[i] = self->m_variable.GetInteger(0,255);
+    }
+  return u.v;
+}
+void 
+LinuxSocketFdFactory::EventTrampoline (void (*fn) (void *context), 
+				       void *context, void (*pre_fn) (void),
+				       Ptr<EventIdHolder> event)
+{
+  m_loader->NotifyStartExecute ();
+  pre_fn ();
+  fn (context);
+  m_loader->NotifyEndExecute ();
+}
+void *
+LinuxSocketFdFactory::EventScheduleNs (struct SimKernel *kernel, unsigned long ns, void (*fn) (void *context), void *context,
+				       void (*pre_fn) (void))
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  Ptr<EventIdHolder> ev = Create<EventIdHolder> ();
+  EventId event = Simulator::Schedule (NanoSeconds(ns), 
+				       &LinuxSocketFdFactory::EventTrampoline, 
+				       self, fn, context, pre_fn, ev);
+  ev->id = event;
+  return &ev->id;
+}
+void 
+LinuxSocketFdFactory::EventCancel (struct SimKernel *kernel, void *ev)
+{
+  EventId *event = (EventId *)ev;
+  Simulator::Remove(*event);
+}
+static __u64 CurrentNs (struct SimKernel *kernel)
+{
+  return Simulator::Now ().GetNanoSeconds ();
+}
+
+void 
+LinuxSocketFdFactory::TaskSwitch (enum Task::SwitchType type, void *context)
+{
+  NS_LOG_FUNCTION (type << context);
+  Loader *loader = (Loader *)context;
+  switch (type)
+    {
+    case Task::TO:
+      loader->NotifyStartExecute ();
+      break;
+    case Task::FROM:
+      loader->NotifyEndExecute ();
+      break;
+    }
+}
+
+struct SimTask *
+LinuxSocketFdFactory::TaskStart (struct SimKernel *kernel, void (*callback) (void *), void *context)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  Task *task = self->m_manager->Start (callback, context, 1<<17);
+  struct SimTask *simTask = self->m_exported->task_create(task, 0);
+  task->SetExtraContext (simTask);
+  task->SetSwitchNotifier (&LinuxSocketFdFactory::TaskSwitch, self->m_loader);
+  self->m_kernelTasks.push_back (task);
+  return (struct SimTask *)task->GetExtraContext ();
+}
+struct SimTask *
+LinuxSocketFdFactory::TaskCurrent (struct SimKernel *kernel)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  TaskManager *manager = TaskManager::Current ();
+  Task *current = manager->CurrentTask ();
+  if (current->GetExtraContext () == 0)
+    {
+      uint32_t pid = 0;
+      struct Thread *thread = (struct Thread *)current->GetContext ();
+      if (thread != 0)
+	{
+	  pid = thread->process->pid;
+	}
+      struct SimTask *simTask = self->m_exported->task_create(current, pid);
+      current->SetExtraContext (simTask);
+    }
+  return (struct SimTask *)current->GetExtraContext ();
+}
+void 
+LinuxSocketFdFactory::TaskWait (struct SimKernel *kernel)
+{
+  // force initialization of 'current'
+  TaskCurrent (kernel);
+  // now, sleep.
+  TaskManager::Current ()->Sleep ();
+}
+int 
+LinuxSocketFdFactory::TaskWakeup (struct SimKernel *kernel, struct SimTask *task)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;  
+  TaskManager *manager = TaskManager::Current ();
+  Task *other = (Task *)self->m_exported->task_get_private(task);
+  bool isBlocked = other->IsBlocked ();
+  manager->Wakeup (other);
+  return isBlocked?1:0;
+}
+void 
+LinuxSocketFdFactory::TaskYield (struct SimKernel *kernel)
+{
+  // force initialization of 'current'
+  TaskCurrent (kernel);
+  // now, yield.
+  TaskManager::Current ()->Yield ();
+}
+void 
+LinuxSocketFdFactory::DevXmit (struct SimKernel *kernel, struct SimDevice *dev, unsigned char *data, int len)
+{
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *)kernel;
+  NetDevice *nsDev = (NetDevice *)self->m_exported->dev_get_private (dev);
+  NS_ASSERT (len >= 14);
+
+  struct ethhdr {
+    unsigned char   h_dest[6];
+    unsigned char   h_source[6];
+    uint16_t        h_proto;
+  } *hdr = (struct ethhdr *)data;
+  data += 14;
+  len -= 14;
+  Ptr<Packet> p = Create<Packet> (data, len);
+  uint16_t protocol = ntohs (hdr->h_proto);
+  Mac48Address dest;
+  dest.CopyFrom (hdr->h_dest);
+  nsDev->Send (p, dest, protocol);
+}
+
+
+struct SimDevice *
+LinuxSocketFdFactory::DevToDev (Ptr<NetDevice> device)
+{
+  for (uint32_t i = 0; i < m_devices.size (); i++)
+    {
+      if (m_devices[i].first == device)
+	{
+	  struct SimDevice *dev = m_devices[i].second;
+	  return dev;
+	}
+    }
+  return 0;
+}
+
+void
+LinuxSocketFdFactory::RxFromDevice (Ptr<NetDevice> device, Ptr<const Packet> p,
+				    uint16_t protocol, const Address & from,
+				    const Address &to, NetDevice::PacketType type)
+{
+  struct SimDevice *dev = DevToDev (device);
+  if (dev == 0)
+    {
+      return;
+    }
+
+  struct SimDevicePacket packet = m_exported->dev_create_packet (dev, p->GetSize () + 14);
+  p->CopyData (((unsigned char *)packet.buffer) + 14, p->GetSize ());
+  struct ethhdr {
+    unsigned char   h_dest[6];
+    unsigned char   h_source[6];
+    uint16_t        h_proto;
+  } *hdr = (struct ethhdr *)packet.buffer;
+  Mac48Address realFrom = Mac48Address::ConvertFrom (from);
+  Mac48Address realTo = Mac48Address::ConvertFrom (to);
+  realFrom.CopyTo (hdr->h_source);
+  realTo.CopyTo (hdr->h_dest);
+  hdr->h_proto = ntohs (protocol);
+  m_loader->NotifyStartExecute ();
+  m_exported->dev_rx (dev, packet);
+  m_loader->NotifyEndExecute ();
+}
+
+void
+LinuxSocketFdFactory::NotifyDeviceStateChange (Ptr<NetDevice> device)
+{
+  ScheduleTask (MakeEvent (&LinuxSocketFdFactory::NotifyDeviceStateChangeTask, 
+			   this, device));
+}
+void
+LinuxSocketFdFactory::NotifyDeviceStateChangeTask (Ptr<NetDevice> device)
+{
+  struct SimDevice *dev = DevToDev (device);
+  if (dev == 0)
+    {
+      return;
+    }  
+  Mac48Address ad = Mac48Address::ConvertFrom (device->GetAddress ());
+  uint8_t buffer[6];
+  ad.CopyTo (buffer);
+  m_exported->dev_set_address(dev, buffer);
+  m_exported->dev_set_mtu (dev, device->GetMtu ());
+}
+
+void
+LinuxSocketFdFactory::ScheduleTaskTrampoline (void *context)
+{
+  Task *current = TaskManager::Current ()->CurrentTask ();
+  LinuxSocketFdFactory *self = (LinuxSocketFdFactory *) current->GetExtraContext ();
+  current->SetExtraContext (0);
+  EventImpl *event = (EventImpl *)context;
+  event->Invoke ();
+  event->Unref ();
+  self->m_kernelTasks.remove (current);
+  TaskManager::Current ()->Exit ();
+}
+
+void
+LinuxSocketFdFactory::ScheduleTask (EventImpl *event)
+{
+  Task *task = m_manager->Start (&LinuxSocketFdFactory::ScheduleTaskTrampoline, 
+				 event, 1<<17);
+  task->SetExtraContext (this);
+  task->SetSwitchNotifier (&LinuxSocketFdFactory::TaskSwitch, m_loader);
+  m_kernelTasks.push_back (task);
+}
+
+void
+LinuxSocketFdFactory::NotifyAddDevice (Ptr<NetDevice> device)
+{
+  ScheduleTask (MakeEvent (&LinuxSocketFdFactory::NotifyAddDeviceTask, this, device));
+}
+void
+LinuxSocketFdFactory::NotifyAddDeviceTask (Ptr<NetDevice> device)
+{
+  int flags = 0;
+  //NS_ASSERT (!device->IsPointToPoint ());
+  //NS_ASSERT (device->NeedsArp ());
+  NS_ASSERT (device->IsMulticast ());
+  NS_ASSERT (device->IsBroadcast ());
+  if (device->IsMulticast ())
+    {
+      flags |= SIM_DEV_MULTICAST;
+    }
+  if (device->IsBroadcast ())
+    {
+      flags |= SIM_DEV_BROADCAST;
+    }
+  struct SimDevice *dev = m_exported->dev_create(PeekPointer(device), (enum SimDevFlags)flags);
+  device->AddStateChangeListener (MakeCallback (&LinuxSocketFdFactory::NotifyDeviceStateChange, this));
+  m_devices.push_back (std::make_pair(device,dev));
+  Ptr<Node> node = GetObject<Node> ();
+  node->RegisterProtocolHandler (MakeCallback (&LinuxSocketFdFactory::RxFromDevice, this), 
+				 0, device, true);
+  NotifyDeviceStateChangeTask (device);
+}
+
+std::vector<std::pair<std::string,struct SimSysFile *> >
+LinuxSocketFdFactory::GetSysFileList (void)
+{
+  struct MyIterator 
+  {
+    struct SimSysIterator head;
+    static void ReportStartDir (const struct SimSysIterator *iter, const char *dirname)
+    {
+      struct MyIterator *self = (struct MyIterator *)iter;
+      self->m_stack.push_back (self->m_currentPath);
+      self->m_currentPath += "." + std::string (dirname);
+    }
+    static void ReportEndDir (const struct SimSysIterator *iter)
+    {
+      struct MyIterator *self = (struct MyIterator *)iter;
+      self->m_currentPath = self->m_stack.back ();
+      self->m_stack.pop_back ();
+    }
+    static void ReportFile (const struct SimSysIterator *iter, const char *filename, int flags, struct SimSysFile *file)
+    {
+      struct MyIterator *self = (struct MyIterator *)iter;
+      std::string path = self->m_currentPath + "." + filename;
+      self->m_list.push_back (std::make_pair (path, file));
+    }
+    std::vector<std::string> m_stack;
+    std::vector<std::pair<std::string,struct SimSysFile *> > m_list;
+    std::string m_currentPath;
+  } iter;
+  iter.head.report_start_dir = &MyIterator::ReportStartDir;
+  iter.head.report_end_dir = &MyIterator::ReportEndDir;
+  iter.head.report_file = &MyIterator::ReportFile;
+  m_loader->NotifyStartExecute ();
+  m_exported->sys_iterate_files ((struct SimSysIterator *)&iter);
+  m_loader->NotifyEndExecute ();
+  return iter.m_list;
+}
+
+void
+LinuxSocketFdFactory::SetTask (std::string path, std::string value)
+{
+  std::vector<std::pair<std::string,struct SimSysFile *> > files = GetSysFileList ();
+  for (uint32_t i = 0; i < files.size (); i++)
+    {
+      if (files[i].first == path)
+	{
+	  const char *s = value.c_str ();
+	  int toWrite = value.size ();
+	  int written;
+	  written = m_exported->sys_file_write (files[i].second, s, toWrite, 0);
+	  break;
+	}
+    }
+}
+
+void 
+LinuxSocketFdFactory::Set (std::string path, std::string value)
+{
+  if (m_manager == 0)
+    {
+      m_earlySysfs.push_back (std::make_pair (path,value));
+    }
+  else
+    {
+      ScheduleTask (MakeEvent (&LinuxSocketFdFactory::SetTask, this, path, value));
+    }
+}
+
+void
+LinuxSocketFdFactory::InitializeStack (void)
+{  
+  void *handle = m_loader->Load (m_library, RTLD_LOCAL);
+  void *symbol = m_loader->Lookup (handle, "sim_init");
+  SimInit init = (SimInit) symbol;
+  if (init == 0)
+    {
+      NS_FATAL_ERROR ("Oops. Can't find initialization function");
+    }
+  m_exported = new struct SimExported ();
+  struct SimImported imported;
+  imported.vprintf = &LinuxSocketFdFactory::Vprintf;
+  imported.malloc = &LinuxSocketFdFactory::Malloc;
+  imported.free = &LinuxSocketFdFactory::Free;
+  imported.memcpy = &LinuxSocketFdFactory::Memcpy;
+  imported.memset = &LinuxSocketFdFactory::Memset;
+  imported.random = &LinuxSocketFdFactory::Random;
+  imported.event_schedule_ns = &LinuxSocketFdFactory::EventScheduleNs;
+  imported.event_cancel = &LinuxSocketFdFactory::EventCancel;
+  imported.current_ns = &CurrentNs;
+  imported.task_start = &LinuxSocketFdFactory::TaskStart;
+  imported.task_wait = &LinuxSocketFdFactory::TaskWait;
+  imported.task_current = &LinuxSocketFdFactory::TaskCurrent;
+  imported.task_wakeup = &LinuxSocketFdFactory::TaskWakeup;
+  imported.task_yield = &LinuxSocketFdFactory::TaskYield;
+  imported.dev_xmit = &LinuxSocketFdFactory::DevXmit;
+  init (m_exported, &imported, (struct SimKernel *)this);
+
+  // update the linux device list with simulation device list
+  Ptr<Node> node = GetObject<Node> ();
+  node->RegisterDeviceAdditionListener (MakeCallback (&LinuxSocketFdFactory::NotifyAddDevice, 
+						      this));
+  Set (".net.ipv4.conf.all.forwarding", "1");
+  Set (".net.ipv4.conf.all.log_martians", "1");
+
+  while (!m_earlySysfs.empty ())
+    {
+      std::pair<std::string,std::string> op = m_earlySysfs.front ();
+      Set (op.first, op.second);
+      m_earlySysfs.pop_front ();
+    }
+}
+
+void 
+LinuxSocketFdFactory::NotifyNewAggregate (void)
+{
+  Ptr<Node> node = this->GetObject<Node> ();
+  Ptr<LoaderFactory> loaderFactory = this->GetObject<LoaderFactory> ();
+  Ptr<TaskManager> taskManager = this->GetObject<TaskManager> ();
+  if (node != 0 && loaderFactory != 0 && taskManager != 0 && m_loader == 0)
+    {
+      m_manager = taskManager;
+      m_loader = loaderFactory->Create (0, 0, 0);
+      UtilsEnsureDirectoryExists (UtilsGetAbsRealFilePath (node->GetId (), "/var"));
+      UtilsEnsureDirectoryExists (UtilsGetAbsRealFilePath (node->GetId (), "/var/log"));
+      std::string path = UtilsGetAbsRealFilePath (node->GetId (), "/var/log/messages");
+      m_logFile = fopen (path.c_str (), "w");
+      setlinebuf(m_logFile);
+      // must use ScheduleWithContext to ensure that the initialization task gets
+      // a node context to be able to retrieve the task manager when it runs.
+      // i.e., TaskManager::Current() needs it.
+      Simulator::ScheduleWithContext (node->GetId (), Seconds (0.0),
+				      &LinuxSocketFdFactory::ScheduleTask, this,
+				      MakeEvent (&LinuxSocketFdFactory::InitializeStack, this));
+    }
+}
+
+UnixFd *
+LinuxSocketFdFactory::CreateSocket (int domain, int type, int protocol)
+{
+  GET_CURRENT(this << domain << type << protocol);
+  struct SimSocket *socket;
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_socket(domain, type, protocol, &socket);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      return 0;
+    }
+  UnixFd *fd = new LinuxSocketFd (this, socket);
+  return fd;
+}
+
+int 
+LinuxSocketFdFactory::Close (struct SimSocket *socket)
+{
+  GET_CURRENT(socket);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_close (socket);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+ssize_t 
+LinuxSocketFdFactory::Recvmsg(struct SimSocket *socket, struct msghdr *msg, int flags)
+{
+  GET_CURRENT(socket << msg << flags);
+  m_loader->NotifyStartExecute ();
+  ssize_t retval = m_exported->sock_recvmsg (socket, msg, flags);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+ssize_t 
+LinuxSocketFdFactory::Sendmsg(struct SimSocket *socket, const struct msghdr *msg, int flags)
+{
+  GET_CURRENT(socket << msg << flags);
+  m_loader->NotifyStartExecute ();
+  ssize_t retval = m_exported->sock_sendmsg (socket, msg, flags);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Getsockname(struct SimSocket *socket, struct sockaddr *name, socklen_t *namelen)
+{
+  GET_CURRENT(socket << name << namelen);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_getsockname (socket, name, (int*)namelen);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Getpeername(struct SimSocket *socket, struct sockaddr *name, socklen_t *namelen)
+{
+  GET_CURRENT(socket << name << namelen);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_getpeername (socket, name, (int*)namelen);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Bind (struct SimSocket *socket, const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  GET_CURRENT(socket << my_addr << addrlen);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_bind (socket, my_addr, addrlen);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Connect (struct SimSocket *socket, const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  GET_CURRENT(socket << my_addr << addrlen);
+  // XXX: handle O_NONBLOCK with flags.
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_connect (socket, my_addr, addrlen, 0);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Listen (struct SimSocket *socket, int backlog)
+{
+  GET_CURRENT(socket << backlog);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_listen (socket, backlog);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Shutdown(struct SimSocket *socket, int how)
+{
+  GET_CURRENT(socket << how);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_shutdown (socket, how);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int
+LinuxSocketFdFactory::Accept (struct SimSocket *socket, struct sockaddr *my_addr, socklen_t *addrlen)
+{
+  GET_CURRENT(socket << my_addr << addrlen);
+  struct SimSocket *newSocket;
+  // XXX: handle O_NONBLOCK
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_accept (socket, &newSocket, 0);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  if (my_addr != 0)
+    {
+      m_loader->NotifyStartExecute ();
+      retval = m_exported->sock_getpeername (newSocket, my_addr, (int*)addrlen);
+      if (retval < 0)
+	{
+	  current->err = -retval;
+	  m_exported->sock_close (newSocket);
+	  m_loader->NotifyEndExecute ();
+	  return -1;
+	}
+      m_loader->NotifyEndExecute ();
+    }
+  int fd = UtilsAllocateFd ();
+  if (fd == -1)
+    {
+      m_loader->NotifyStartExecute ();
+      m_exported->sock_close (newSocket);
+      current->err = EMFILE;
+      m_loader->NotifyEndExecute ();
+      return -1;
+    }
+
+  UnixFd *unixFd = new LinuxSocketFd (this, newSocket);
+  current->process->openFiles.push_back (std::make_pair (fd, unixFd));
+  return fd;
+}
+int 
+LinuxSocketFdFactory::Ioctl (struct SimSocket *socket, int request, char *argp)
+{
+  GET_CURRENT(socket << request << argp);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_ioctl (socket, request, argp);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Setsockopt (struct SimSocket *socket, int level, int optname,
+				  const void *optval, socklen_t optlen)
+{
+  GET_CURRENT(socket << level << optname << optval << optlen);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_setsockopt (socket, level, optname, optval, optlen);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+int 
+LinuxSocketFdFactory::Getsockopt (struct SimSocket *socket, int level, int optname,
+				  void *optval, socklen_t *optlen)
+{
+  GET_CURRENT(socket << level << optname << optval << optlen);
+  m_loader->NotifyStartExecute ();
+  int retval = m_exported->sock_getsockopt (socket, level, optname, optval, (int*)optlen);
+  m_loader->NotifyEndExecute ();
+  if (retval < 0)
+    {
+      current->err = -retval;
+      return -1;
+    }
+  return retval;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/linux-socket-fd-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,127 @@
+#ifndef LINUX_SOCKET_FD_FACTORY_H
+#define LINUX_SOCKET_FD_FACTORY_H
+
+#include "socket-fd-factory.h"
+#include "task-manager.h"
+#include "ns3/net-device.h"
+#include "ns3/random-variable.h"
+#include <sys/socket.h>
+#include <vector>
+#include <string>
+#include <utility>
+#include <stdarg.h>
+#include <stdio.h>
+
+extern "C" {
+struct SimExported;
+struct SimDevice;
+struct SimSocket;
+struct SimTask;
+struct SimKernel;
+struct SimSysFile;
+}
+
+class Alloc;
+
+namespace ns3 {
+
+class Loader;
+class NetDevice;
+class Task;
+class TaskManager;
+class Packet;
+
+class LinuxSocketFdFactory : public SocketFdFactory
+{
+public:
+  static TypeId GetTypeId (void);
+  LinuxSocketFdFactory ();
+  ~LinuxSocketFdFactory ();
+  virtual UnixFd *CreateSocket (int domain, int type, int protocol);
+
+  void Set (std::string path, std::string value);
+
+
+private:
+  friend class LinuxSocketFd;
+  struct EventIdHolder : public SimpleRefCount<EventIdHolder>
+  {
+    EventId id;
+  };
+
+  // called from LinuxSocketFd
+  int Close (struct SimSocket *socket);
+  ssize_t Recvmsg(struct SimSocket *socket, struct msghdr *msg, int flags);
+  ssize_t Sendmsg(struct SimSocket *socket, const struct msghdr *msg, int flags);
+  int Getsockname(struct SimSocket *socket, struct sockaddr *name, socklen_t *namelen);
+  int Getpeername(struct SimSocket *socket, struct sockaddr *name, socklen_t *namelen);
+  int Bind (struct SimSocket *socket, const struct sockaddr *my_addr, socklen_t addrlen);
+  int Connect (struct SimSocket *socket, const struct sockaddr *my_addr, socklen_t addrlen);
+  int Listen (struct SimSocket *socket, int backlog);
+  int Shutdown(struct SimSocket *socket, int how);
+  int Accept (struct SimSocket *socket, struct sockaddr *my_addr, socklen_t *addrlen);
+  int Ioctl (struct SimSocket *socket, int request, char *argp);
+  int Setsockopt (struct SimSocket *socket, int level, int optname,
+		  const void *optval, socklen_t optlen);
+  int Getsockopt (struct SimSocket *socket, int level, int optname,
+		  void *optval, socklen_t *optlen);
+
+  // called from kernel.
+  static int Vprintf (struct SimKernel *kernel, const char *str, va_list args);
+  static void *Malloc (struct SimKernel *kernel, unsigned long size);
+  static void Free (struct SimKernel *kernel, void *buffer);
+  static void *Memcpy (struct SimKernel *kernel, void *dst, const void *src, unsigned long size);
+  static void *Memset (struct SimKernel *kernel, void *dst, char value, unsigned long size);
+  static unsigned long Random (struct SimKernel *kernel);
+  static void *EventScheduleNs (struct SimKernel *kernel, unsigned long ns, void (*fn) (void *context), void *context,
+				void (*pre_fn) (void));
+  static void EventCancel (struct SimKernel *kernel, void *ev);
+  static struct SimTask *TaskStart (struct SimKernel *kernel, void (*callback) (void *), void *context);
+  static struct SimTask *TaskCurrent (struct SimKernel *kernel);
+  static void TaskWait (struct SimKernel *kernel);
+  static int TaskWakeup (struct SimKernel *kernel, struct SimTask *task);
+  static void TaskYield (struct SimKernel *kernel);
+  static void DevXmit (struct SimKernel *kernel, struct SimDevice *dev, unsigned char *data, int len);
+
+  // inherited from Object.
+  virtual void DoDispose (void);
+  virtual void NotifyNewAggregate (void);
+  // called from Node
+  void NotifyAddDevice (Ptr<NetDevice> device);
+  // called during initialization with a task context
+  // to enter the kernel functions.
+  void StartInitializationTask (void);
+  void InitializeStack (void);
+  void RxFromDevice (Ptr<NetDevice> device, Ptr<const Packet> p,
+		     uint16_t protocol, const Address & from,
+		     const Address &to, NetDevice::PacketType type);
+  struct SimDevice *DevToDev (Ptr<NetDevice> dev);
+  void NotifyDeviceStateChange (Ptr<NetDevice> device);
+  void NotifyDeviceStateChangeTask (Ptr<NetDevice> device);
+  void NotifyAddDeviceTask (Ptr<NetDevice> device);
+
+  std::vector<std::pair<std::string,struct SimSysFile *> > GetSysFileList (void);
+  void DoSet (std::string path, std::string value);
+  void SetTask (std::string path, std::string value);
+  static void TaskSwitch (enum Task::SwitchType type, void *context);
+  static void ScheduleTaskTrampoline (void *context);
+  void ScheduleTask (EventImpl *event);
+  void EventTrampoline (void (*fn) (void *context), 
+			void *context, void (*pre_fn) (void),
+			Ptr<EventIdHolder> event);
+
+  std::vector<std::pair<Ptr<NetDevice>,struct SimDevice *> > m_devices;
+  std::string m_library;
+  Loader *m_loader;
+  struct SimExported *m_exported;
+  std::list<Task *> m_kernelTasks;
+  Ptr<TaskManager> m_manager;
+  UniformVariable m_variable;
+  Alloc *m_alloc;
+  FILE *m_logFile;
+  std::list<std::pair<std::string,std::string> > m_earlySysfs;
+};
+
+} // namespace ns3
+
+#endif /* LINUX_SOCKET_FD_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/linux-socket-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,218 @@
+#include "linux-socket-fd.h"
+#include "linux-socket-fd-factory.h"
+#include "utils.h"
+#include "process.h"
+#include "ns3/log.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h> // for MMAP_FAILED
+
+NS_LOG_COMPONENT_DEFINE("LinuxSocketFd");
+
+namespace ns3 {
+
+LinuxSocketFd::LinuxSocketFd (Ptr<LinuxSocketFdFactory> factory, struct SimSocket *socket)
+  : m_factory (factory),
+    m_socket (socket),
+    m_statusFlags (0)
+{}
+
+LinuxSocketFd::~LinuxSocketFd ()
+{}
+
+int 
+LinuxSocketFd::Close (void)
+{
+  return m_factory->Close (m_socket);
+}
+ssize_t 
+LinuxSocketFd::Write (const void *buf, size_t count)
+{
+  NS_LOG_FUNCTION (this << buf << count);
+  struct msghdr msg;
+  struct iovec iov;
+  msg.msg_control = 0;
+  msg.msg_controllen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iov;
+  iov.iov_len = count;
+  iov.iov_base = (void*)buf;
+  msg.msg_name = 0;
+  msg.msg_namelen = 0;
+  ssize_t retval = Sendmsg (&msg, 0);
+  return retval;
+}
+ssize_t 
+LinuxSocketFd::Read(void *buf, size_t count)
+{
+  NS_LOG_FUNCTION (this << buf << count);
+  struct msghdr msg;
+  struct iovec iov;
+  msg.msg_control = 0;
+  msg.msg_controllen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iov;
+  iov.iov_len = count;
+  iov.iov_base = buf;
+  msg.msg_name = 0;
+  msg.msg_namelen = 0;
+  ssize_t retval = Recvmsg (&msg, 0);
+  return retval;
+}
+ssize_t 
+LinuxSocketFd::Recvmsg(struct msghdr *msg, int flags)
+{
+  bool nonBlocking = (m_statusFlags & O_NONBLOCK) == O_NONBLOCK;
+  flags |= nonBlocking?MSG_DONTWAIT:0;
+  return m_factory->Recvmsg (m_socket, msg, flags);
+}
+ssize_t 
+LinuxSocketFd::Sendmsg(const struct msghdr *msg, int flags)
+{
+  bool nonBlocking = (m_statusFlags & O_NONBLOCK) == O_NONBLOCK;
+  flags |= nonBlocking?MSG_DONTWAIT:0;
+  return m_factory->Sendmsg (m_socket, msg, flags);
+}
+bool 
+LinuxSocketFd::Isatty (void) const
+{
+  return false;
+}
+int 
+LinuxSocketFd::Setsockopt (int level, int optname,
+			   const void *optval, socklen_t optlen)
+{
+  return m_factory->Setsockopt (m_socket, level, optname, optval, optlen);
+}
+int 
+LinuxSocketFd::Getsockopt (int level, int optname,
+			   void *optval, socklen_t *optlen)
+{
+  return m_factory->Getsockopt (m_socket, level, optname, optval, optlen);
+}
+int 
+LinuxSocketFd::Getsockname(struct sockaddr *name, socklen_t *namelen)
+{
+  return m_factory->Getsockname (m_socket, name, namelen);
+}
+int 
+LinuxSocketFd::Getpeername(struct sockaddr *name, socklen_t *namelen)
+{
+  return m_factory->Getpeername (m_socket, name, namelen);
+}
+int 
+LinuxSocketFd::Ioctl (int request, char *argp)
+{
+  return m_factory->Ioctl (m_socket, request, argp);
+}
+int 
+LinuxSocketFd::Bind (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  return m_factory->Bind (m_socket, my_addr, addrlen);
+}
+int 
+LinuxSocketFd::Connect (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  return m_factory->Connect (m_socket, my_addr, addrlen);
+}
+int 
+LinuxSocketFd::Listen (int backlog)
+{
+  return m_factory->Listen (m_socket, backlog);
+}
+int 
+LinuxSocketFd::Shutdown(int how)
+{
+  return m_factory->Shutdown (m_socket, how);
+}
+int 
+LinuxSocketFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
+{
+  return m_factory->Accept (m_socket, my_addr, addrlen);
+}
+void *
+LinuxSocketFd::Mmap (void *start, size_t length, int prot, int flags, off64_t offset)
+{
+  GET_CURRENT (start << length << prot << flags << offset);
+  current->err = ENODEV;
+  return MAP_FAILED;
+}
+off64_t 
+LinuxSocketFd::Lseek (off64_t offset, int whence)
+{
+  GET_CURRENT(offset << whence);
+  current->err = ESPIPE;
+  return -1;  
+}
+int 
+LinuxSocketFd::Fxstat (int ver, struct ::stat *buf)
+{
+  GET_CURRENT(ver << buf);
+  buf->st_mode = S_IFSOCK;
+  buf->st_dev = -1;
+  buf->st_blksize = 0;
+  return 0;
+}
+int 
+LinuxSocketFd::Fxstat64 (int ver, struct ::stat64 *buf)
+{
+  GET_CURRENT(ver << buf);
+  buf->st_mode = S_IFSOCK;
+  buf->st_dev = -1;
+  buf->st_blksize = 0;
+  return 0;
+}
+int 
+LinuxSocketFd::Fcntl (int cmd, unsigned long arg)
+{
+  switch (cmd) 
+    {
+    case F_GETFL: //XXX this command should also consider the flags O_APPEND and O_ASYNC
+      return m_statusFlags;
+      break;
+    case F_SETFL:
+      m_statusFlags = arg;
+      return 0;
+      break;
+    default:
+      //XXX commands missing
+      NS_FATAL_ERROR ("fcntl not implemented on socket");
+      return -1;
+    }
+}
+int 
+LinuxSocketFd::Settime (int flags,
+			const struct itimerspec *new_value,
+			struct itimerspec *old_value)
+{
+  NS_LOG_FUNCTION (this << Current () << flags << new_value << old_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return -1;
+}
+int 
+LinuxSocketFd::Gettime (struct itimerspec *cur_value) const
+{
+  NS_LOG_FUNCTION (this << Current () << cur_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return -1;
+}
+
+bool 
+LinuxSocketFd::CanRecv (void) const
+{
+  // XXX: should be killed anyway for a Poll method
+  return false;
+}
+bool 
+LinuxSocketFd::CanSend (void) const
+{
+  // XXX: should be killed anyway for a Poll method
+  return false;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/linux-socket-fd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,62 @@
+#ifndef LINUX_SOCKET_FD_H
+#define LINUX_SOCKET_FD_H
+
+#include "unix-fd.h"
+#include "ns3/ptr.h"
+
+extern "C" {
+struct SimSocket;
+}
+
+namespace ns3 {
+
+class LinuxSocketFdFactory;
+
+class Waiter;
+
+class LinuxSocketFd : public UnixFd
+{
+public:
+  LinuxSocketFd (Ptr<LinuxSocketFdFactory> factory, struct SimSocket *socket);
+  virtual ~LinuxSocketFd ();
+
+  virtual int Close (void);
+  virtual ssize_t Write (const void *buf, size_t count);
+  virtual ssize_t Read(void *buf, size_t count);
+  virtual ssize_t Recvmsg(struct msghdr *msg, int flags);
+  virtual ssize_t Sendmsg(const struct msghdr *msg, int flags);
+  virtual bool Isatty (void) const;
+  virtual int Setsockopt (int level, int optname,
+			  const void *optval, socklen_t optlen);
+  virtual int Getsockopt (int level, int optname,
+			  void *optval, socklen_t *optlen);
+  virtual int Getsockname(struct sockaddr *name, socklen_t *namelen);
+  virtual int Getpeername(struct sockaddr *name, socklen_t *namelen);
+  virtual int Ioctl (int request, char *argp);
+  virtual int Bind (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual int Connect (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual int Listen (int backlog);
+  virtual int Shutdown(int how);
+  virtual int Accept (struct sockaddr *my_addr, socklen_t *addrlen);
+  virtual void *Mmap (void *start, size_t length, int prot, int flags, off64_t offset);
+  virtual off64_t Lseek (off64_t offset, int whence);
+  virtual int Fxstat (int ver, struct ::stat *buf);
+  virtual int Fxstat64 (int ver, struct ::stat64 *buf);
+  virtual int Fcntl (int cmd, unsigned long arg);
+  virtual int Settime (int flags,
+		       const struct itimerspec *new_value,
+		       struct itimerspec *old_value);
+  virtual int Gettime (struct itimerspec *cur_value) const;
+
+  virtual bool CanRecv (void) const;
+  virtual bool CanSend (void) const;
+
+private:
+  Ptr<LinuxSocketFdFactory> m_factory;
+  struct SimSocket *m_socket;
+  int m_statusFlags;
+};
+
+} // namespace ns3
+
+#endif /* LINUX_SOCKET_FD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/loader-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,24 @@
+#include "loader-factory.h"
+
+namespace ns3 {
+
+Loader::~Loader ()
+{}
+
+void Loader::NotifyStartExecute (void)
+{}
+void Loader::NotifyEndExecute (void)
+{}
+
+TypeId 
+LoaderFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::LoaderFactory")
+    .SetParent<Object> ()
+    ;
+  return tid;
+}
+LoaderFactory::~LoaderFactory ()
+{}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/loader-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,31 @@
+#ifndef LOADER_FACTORY_H
+#define LOADER_FACTORY_H
+
+#include "ns3/object.h"
+#include "ns3/simple-ref-count.h"
+
+namespace ns3 {
+
+class Loader
+{
+ public:
+  virtual ~Loader () = 0;
+  virtual void NotifyStartExecute (void);
+  virtual void NotifyEndExecute (void);
+  virtual void UnloadAll (void) = 0;
+  virtual void *Load (std::string filename, int flag) = 0;
+  virtual void Unload (void *module) = 0;
+  virtual void *Lookup (void *module, std::string symbol) = 0;
+};
+
+class LoaderFactory : public Object
+{
+ public:
+  static TypeId GetTypeId (void);
+  virtual ~LoaderFactory () = 0;
+  virtual Loader *Create (int argc, char **argv, char **envp) = 0;
+};
+
+} // namespace ns3
+
+#endif /* LOADER_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/net/simu-if.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,16 @@
+#ifndef SIMU_IF_H
+#define SIMU_IF_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned simu_if_nametoindex (const char *ifname);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_IF_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/TODO	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,12 @@
+- Notification on status change
+- NETLINK_RTM_NEWADDR/NETLINK_RTM_DELADDR 
+- NETLINK_RTM_SETLINK
+   => if zebra can specify types of link
+- NETLINK_RTM_GETLINK
+   => Dump is implemented
+- handle missing oif when NEW/DEL Route
+- RT_A_SRC/RT_A_PERFSRC in NEWROUTE/DELROUTE
+- IPv6 code (can we avoid the duplicated code btw/ v4,v6?)
+- Multiple table from upper layer (VRF support in quagga)
+- Doc (Doxygen)
+- Example for netlink?
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-attribute.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,433 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#include "netlink-attribute.h"
+#include "netlink-message.h"
+#include "netlink-message-route.h"
+#include "ns3/address-utils.h"
+
+namespace ns3 {
+
+
+/***********************************************************************************
+* \ NetlinkAttributeValue
+***********************************************************************************/
+NetlinkAttributeValue::NetlinkAttributeValue ()
+{
+  m_type = UNSPEC;
+  m_u32 = 0;
+}
+
+NetlinkAttributeValue:: NetlinkAttributeValue (NetlinkAttributeValueType type, uint8_t v)
+{
+  NS_ASSERT (type == U8);
+  m_type = U8;
+  m_u8 = v;
+}
+NetlinkAttributeValue:: NetlinkAttributeValue (NetlinkAttributeValueType type, uint16_t v)
+{
+  NS_ASSERT (type == U16);
+  m_type = U16;
+  m_u16 = v;
+}
+NetlinkAttributeValue:: NetlinkAttributeValue (NetlinkAttributeValueType type, uint32_t v)
+{
+  NS_ASSERT (type == U32);
+  m_type = U32;
+  m_u32 = v;
+}
+NetlinkAttributeValue:: NetlinkAttributeValue (NetlinkAttributeValueType type, uint64_t v)
+{
+  NS_ASSERT (type == U64);
+  m_type = U64;
+  m_u64 = v;
+}
+NetlinkAttributeValue:: NetlinkAttributeValue (NetlinkAttributeValueType type, std::string v)
+{
+  NS_ASSERT (type == STRING);
+  m_type = STRING;
+  m_string = v;
+}
+NetlinkAttributeValue:: NetlinkAttributeValue (NetlinkAttributeValueType type, Address v)
+{
+  NS_ASSERT (type == ADDRESS);
+  m_type = ADDRESS;
+  m_address = v;
+}
+
+void
+NetlinkAttributeValue::SetType (NetlinkAttributeValueType type)
+{
+  m_type = type;
+}
+NetlinkAttributeValueType
+NetlinkAttributeValue::GetType (void) const
+{
+  return m_type;
+}
+void
+NetlinkAttributeValue::SetAddress (Address value)
+{
+  m_address = value;
+}
+void
+NetlinkAttributeValue::SetString (std::string value)
+{
+  m_string = value;
+}
+void
+NetlinkAttributeValue::SetU64 (uint64_t value)
+{
+  m_u64 = value;
+}
+void
+NetlinkAttributeValue::SetU32 (uint32_t value)
+{
+  m_u32 = value;
+}
+void
+NetlinkAttributeValue::SetU16 (uint16_t value)
+{
+  m_u16 = value;
+}
+void
+NetlinkAttributeValue::SetU8 (uint8_t value)
+{
+  m_u8 = value;
+}
+Address
+NetlinkAttributeValue::GetAddress (void) const
+{
+  return m_address;
+}
+std::string
+NetlinkAttributeValue::GetString (void) const
+{
+  return m_string;
+}
+uint64_t
+NetlinkAttributeValue::GetU64 (void) const
+{
+  return m_u64;
+}
+uint32_t
+NetlinkAttributeValue::GetU32 (void) const
+{
+  return m_u32;
+}
+uint16_t
+NetlinkAttributeValue::GetU16 (void) const
+{
+  return m_u16;
+}
+uint8_t
+NetlinkAttributeValue::GetU8 (void) const
+{
+  return m_u8;
+}
+
+void
+NetlinkAttributeValue::Serialize (Buffer::Iterator& start) const
+{
+  uint32_t len;
+
+  if (m_type == U8)
+    {
+      start.WriteU8 (m_u8);
+      len = 1;
+    }
+  else if(m_type == U16)
+    {
+      start.WriteU16 (m_u16);
+      len = 2;
+    }
+  else if(m_type == U32)
+    {
+      start.WriteU32 (m_u32);
+      len = 4;
+    }
+  else if(m_type == STRING)
+    {
+      start.Write ((const uint8_t *)m_string.c_str (), (uint32_t)m_string.size ()+1);
+      len = (uint32_t)m_string.size () + 1;
+    }
+  else if(m_type == ADDRESS)
+    {
+      WriteTo (start, m_address);
+      len = m_address.GetLength ();
+    }
+  else
+    {
+      len = 0;
+    }
+  //netlink align
+  start.WriteU8 (0, NETLINK_MSG_ALIGN (len) - len);
+}
+
+uint32_t
+NetlinkAttributeValue::DeserializeWithType (Buffer::Iterator& start, 
+                                            NetlinkAttributeValueType_e type, uint16_t remaining)
+{
+  uint32_t len =0;
+  m_type = type;  
+
+  if (m_type == U8)
+    {
+      m_u8 = start.ReadU8 ();
+      len = 1;
+    }
+  else if (m_type == U16)
+    {
+      m_u16 = start.ReadU16 ();
+      len = 2;
+    }
+  else if (m_type == U32)
+    {
+      m_u32 = start.ReadU32 ();
+      len = 4;
+    }
+  else if (m_type == U64)
+    {
+      m_u64 = start.ReadU64 ();
+    }  
+  else if (m_type == STRING)
+    {
+      char buf[512];
+      uint32_t i = 0;
+      do 
+      {
+        buf[i] = start.ReadU8 ();
+      } while (buf[i++]);
+      
+      m_string = std::string (buf);
+      len = (uint32_t)m_string.size () + 1;
+    }
+  else if (m_type == ADDRESS)
+    {
+      ReadFrom (start, m_address, remaining);
+      len = m_address.GetLength ();
+    }
+  else
+    {
+      len = 0;
+    }
+
+  //netlink align
+  uint8_t buf[4];
+  start.Read (buf, NETLINK_MSG_ALIGN (len) - len);
+  
+  return NETLINK_MSG_ALIGN (len);
+}
+
+uint32_t
+NetlinkAttributeValue::GetSerializedSize ()const
+{
+  return NETLINK_MSG_ALIGN (GetSize ());
+}
+
+uint32_t
+NetlinkAttributeValue::GetSize () const
+{
+  uint32_t len;
+
+  if (m_type == U8)
+    {
+      len = 1;
+    }
+  else if(m_type == U16)
+    {
+      len =  2;
+    }
+  else if(m_type == U32)
+    {
+      len =  4;
+    }
+  else if (m_type == STRING)
+    {
+      len =  uint32_t (m_string.size () + 1);
+    }
+  else if (m_type == ADDRESS)
+    {
+      len =  m_address.GetLength ();
+    }
+  else
+    {
+      len = 0;
+    }
+
+    return len;
+}
+
+void
+NetlinkAttributeValue::Print (std::ostream &os) const
+{
+  os << "NetlinkAttributeValue (type= " << m_type <<", v= ";
+  if (m_type == U8)
+    {
+      os << m_u8;
+    }
+  else if (m_type == U16)
+    {
+      os << m_u16;
+    }
+  else if (m_type == U32)
+    {
+      os << m_u32;
+    }
+  else if (m_type == U64)
+    {
+      os << m_u64;
+    }  
+  else if (m_type == STRING)
+    {
+      os << m_string;
+    }
+  else if (m_type == ADDRESS)
+    {
+      os << "address(" << m_address <<")";
+    }
+  else
+    {
+      os << "NULL";
+    }
+  os <<")";
+}
+
+
+/***********************************************************************************
+* \ NetlinkAttribute
+***********************************************************************************/
+
+NetlinkAttribute::NetlinkAttribute ()
+  : m_len(4),
+    m_type (0)
+{
+}
+
+NetlinkAttribute::NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint8_t payload)
+{
+  m_payload = NetlinkAttributeValue (payloadtype, payload);
+  m_len = NETLINK_MSG_ATTR_SIZE + m_payload.GetSize ();
+  m_type = type;
+}
+
+NetlinkAttribute::NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint16_t payload)
+{
+  m_payload = NetlinkAttributeValue (payloadtype, payload);
+  m_len = NETLINK_MSG_ATTR_SIZE + m_payload.GetSize ();
+  m_type = type;
+}
+NetlinkAttribute::NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint32_t payload)
+{
+  m_payload = NetlinkAttributeValue (payloadtype, payload);
+  m_len = NETLINK_MSG_ATTR_SIZE + m_payload.GetSize ();
+  m_type = type;;
+}
+NetlinkAttribute::NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint64_t payload)
+{
+  m_payload = NetlinkAttributeValue (payloadtype, payload);
+  m_len = NETLINK_MSG_ATTR_SIZE + m_payload.GetSize ();
+  m_type = type;
+}
+NetlinkAttribute::NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  std::string payload)
+{
+  m_payload = NetlinkAttributeValue (payloadtype, payload);
+  m_len = NETLINK_MSG_ATTR_SIZE + m_payload.GetSize ();
+  m_type = type;
+}
+NetlinkAttribute::NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  Address payload)
+{
+  m_payload = NetlinkAttributeValue (payloadtype, payload);
+  m_len = NETLINK_MSG_ATTR_SIZE + m_payload.GetSize ();
+  m_type = type;
+}
+
+void
+NetlinkAttribute::SetAttrLen (uint16_t v)
+{
+  m_len = v;
+}
+void 
+NetlinkAttribute::SetAttrType (uint16_t v)
+{
+  m_type = v;
+}
+void
+NetlinkAttribute::SetAttrPayload (NetlinkAttributeValue v)
+{
+  m_payload = v;
+}
+uint16_t
+NetlinkAttribute::GetAttrLen () const
+{
+  return m_len;
+}
+uint16_t
+NetlinkAttribute::GetAttrType () const
+{
+  return m_type;
+}
+NetlinkAttributeValue
+NetlinkAttribute::GetAttrPayload() const
+{
+  return m_payload;
+}
+
+void 
+NetlinkAttribute::Print (std::ostream &os) const
+{  
+  os << "NetlinkAttribute "
+     << "len: " << m_len << " "
+     << "type: " << m_type<<" "
+     << "payload:[";
+  m_payload.Print(os);
+  os<<"]";
+}
+
+uint32_t 
+NetlinkAttribute::GetSerializedSize (void) const
+{
+  /* this is the size of an nlattr payload. */
+  return NETLINK_MSG_ATTR_SIZE + m_payload.GetSerializedSize ();
+}
+
+void
+NetlinkAttribute::Serialize (Buffer::Iterator& start) const
+{
+  start.WriteU16 (m_len);
+  start.WriteU16 (m_type);
+  m_payload.Serialize (start);
+}
+
+uint32_t
+NetlinkAttribute::Deserialize (Buffer::Iterator& start, NetlinkAttributeValueType vtypes[])
+{
+  NetlinkAttributeValueType type;
+
+  m_len = start.ReadU16 ();
+  m_type = start.ReadU16 ();
+  type = vtypes[m_type];
+  m_payload.DeserializeWithType (start, type, m_len - 4);
+
+  return GetSerializedSize ();
+}
+
+}; // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-attribute.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,124 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#ifndef NETLINK_ATTRIBUTE_H
+#define NETLINK_ATTRIBUTE_H
+
+
+#include <stdint.h>
+#include <string>
+#include <ostream>
+#include "ns3/address.h"
+#include "ns3/buffer.h"
+
+namespace ns3 {
+
+/**
+* \brief The Netlink Attribute
+*/
+
+typedef enum NetlinkAttributeValueType_e {
+  UNSPEC, // invalid initial value.
+  U8,
+  U16,
+  U32,
+  U64,
+  STRING,
+  ADDRESS,
+}NetlinkAttributeValueType;
+
+class NetlinkAttributeValue
+{
+public:
+  NetlinkAttributeValue ();
+  NetlinkAttributeValue (NetlinkAttributeValueType type, uint8_t v);
+  NetlinkAttributeValue (NetlinkAttributeValueType type, uint16_t v);
+  NetlinkAttributeValue (NetlinkAttributeValueType type, uint32_t v);
+  NetlinkAttributeValue (NetlinkAttributeValueType type, uint64_t v);
+  NetlinkAttributeValue (NetlinkAttributeValueType type, std::string v);
+  NetlinkAttributeValue (NetlinkAttributeValueType type, Address v);
+  
+  void Serialize (Buffer::Iterator& start) const;
+  uint32_t DeserializeWithType (Buffer::Iterator& start, NetlinkAttributeValueType type, uint16_t remaining);
+  uint32_t GetSerializedSize (void) const;
+  uint32_t GetSize (void) const;
+  void Print (std::ostream &os) const;
+
+  void SetType (NetlinkAttributeValueType type);
+  NetlinkAttributeValueType GetType (void) const;
+  void SetAddress (Address value);
+  void SetString (std::string value);
+  void SetU64 (uint64_t value);
+  void SetU32 (uint32_t value);
+  void SetU16 (uint16_t value);
+  void SetU8 (uint8_t value);
+  Address GetAddress (void) const;
+  std::string GetString (void) const;
+  uint64_t GetU64 (void) const;
+  uint32_t GetU32 (void) const;
+  uint16_t GetU16 (void) const;
+  uint8_t GetU8 (void) const;
+
+private:
+  NetlinkAttributeValueType m_type;
+  uint64_t m_u64;
+  uint32_t m_u32;
+  uint16_t m_u16;
+  uint8_t m_u8;
+  std::string m_string;
+  Address m_address;
+};
+
+struct NetlinkAttribute
+{
+public:
+  NetlinkAttribute ();
+  NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint8_t payload);
+  NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint16_t payload);
+  NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint32_t payload);
+  NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  uint64_t payload);
+  NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  std::string payload);
+  NetlinkAttribute (uint16_t type, NetlinkAttributeValueType payloadtype,  Address payload);
+
+  //static TypeId GetTypeId (void);
+  //virtual TypeId GetInstanceTypeId (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator& start) const;
+  uint32_t Deserialize (Buffer::Iterator& start, NetlinkAttributeValueType vtypes[]);
+
+  void SetAttrLen (uint16_t v);
+  void SetAttrType (uint16_t v);
+  void SetAttrPayload (NetlinkAttributeValue v);
+  uint16_t GetAttrLen () const;
+  uint16_t GetAttrType () const;
+  NetlinkAttributeValue GetAttrPayload () const;
+
+private:
+  static const int NETLINK_MSG_ATTR_SIZE = 4; /* size of the nlattr field*/
+  uint16_t m_len;
+  uint16_t m_type; 
+  NetlinkAttributeValue m_payload;
+};
+
+}; // namespace ns3
+
+#endif /* NETLINK_ATTRIBUTE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-message-route.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,647 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#include "netlink-message-route.h"
+#include "netlink-message.h"
+
+namespace ns3 {
+
+/***********************************************************************************
+* \ NetlinkPayload
+***********************************************************************************/
+TypeId 
+NetlinkPayload::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::NetlinkPayload")
+    .SetParent<ObjectBase> ()
+    ;
+  return tid;
+}
+
+
+/***********************************************************************************
+* \ GeneralMessage
+***********************************************************************************/
+
+NS_OBJECT_ENSURE_REGISTERED (GeneralMessage);
+NS_OBJECT_ENSURE_REGISTERED (InterfaceInfoMessage);
+NS_OBJECT_ENSURE_REGISTERED (InterfaceAddressMessage);
+NS_OBJECT_ENSURE_REGISTERED (RouteMessage);
+
+GeneralMessage::GeneralMessage ()
+  : m_family(0)
+{}
+GeneralMessage::~GeneralMessage ()
+{}
+
+void
+GeneralMessage::SetFamily (uint8_t v)
+{
+  m_family = v;
+}
+uint8_t
+GeneralMessage::GetFamily (void) const
+{
+  return m_family;
+}
+
+TypeId 
+GeneralMessage::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::GeneralMessage")
+    .SetParent<NetlinkPayload> ()
+    .AddConstructor<GeneralMessage> ()
+    ;
+  return tid;
+}
+
+TypeId 
+GeneralMessage::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+void 
+GeneralMessage::Print (std::ostream &os) const
+{
+  os << " ----GeneralMessage ("
+     << "family: " << (uint32_t)m_family << ")"; 
+}
+
+uint32_t 
+GeneralMessage::GetSerializedSize (void) const
+{
+  /* this is the size of an nlmsghdr payload. */
+  return NETLINK_MSG_ALIGN (NETLINK_GENMSG_SIZE);
+}
+
+
+void
+GeneralMessage::Serialize (Buffer::Iterator& start) const
+{
+  start.WriteU8 (m_family);
+  start.WriteU8 (0, 3);
+}
+
+uint32_t
+GeneralMessage::Deserialize (Buffer::Iterator& start)
+{
+  uint8_t buf[3];
+  m_family = start.ReadU8 ();
+  start.Read (buf, 3);
+  return GetSerializedSize ();
+}
+uint32_t
+GeneralMessage::Deserialize (Buffer::Iterator& start, uint32_t len)
+{
+  uint8_t buf[3];
+  m_family = start.ReadU8 ();
+  start.Read (buf, 3);
+  return GetSerializedSize ();
+}
+
+
+uint32_t
+GeneralMessage::GetNNetlinkAttribute (void)const
+{
+  return m_attributes.size ();
+}
+NetlinkAttribute
+GeneralMessage::GetNetlinkAttribute (uint32_t index)const
+{
+  NS_ASSERT(index < GetNNetlinkAttribute ());
+  return m_attributes[index];
+}
+
+uint32_t
+GeneralMessage::GetAttributeSerializedSize (void) const
+{
+  uint32_t size = 0;
+
+  for (uint32_t i = 0; i < m_attributes.size (); i ++)
+    {
+      size += m_attributes[i].GetSerializedSize ();
+    }
+  return size;
+}
+bool
+GeneralMessage::GetAttributeByType (NetlinkAttribute& attr, uint16_t type)
+{
+  for (uint32_t i = 0; i < m_attributes.size (); i ++)
+    {
+      if (type == m_attributes[i].GetAttrType ())
+        {
+          attr = m_attributes[i];
+          return true;
+        }
+    }
+  return false;  
+}
+void
+GeneralMessage::AppendAttribute (NetlinkAttribute v)
+{
+  m_attributes.push_back (v);
+}
+
+void
+GeneralMessage::SerializeAttribute (Buffer::Iterator& start) const
+{
+  for (uint32_t i = 0; i < m_attributes.size (); i ++)
+    {
+      m_attributes[i].Serialize (start);
+    }
+}
+
+void
+GeneralMessage::PrintAttribute (std::ostream &os) const
+{
+  for (uint32_t i = 0; i < m_attributes.size (); i ++)
+    {
+      os << " ----Attribute (" << i << "):";
+      m_attributes[i].Print(os);
+    }
+}
+
+/***********************************************************************************
+* \ InterfaceInfoMessage
+***********************************************************************************/
+InterfaceInfoMessage::InterfaceInfoMessage ()
+  : m_reserved (0),
+    m_deviceType (0),
+    m_interfaceIndex(0),
+    m_deviceFlags (0),
+    m_changeMask (0)
+{
+  memset ((void*)m_attributeTypes, 0, sizeof (m_attributeTypes));
+  m_attributeTypes[IFL_A_UNSPEC] = UNSPEC;
+  m_attributeTypes[IFL_A_ADDRESS] = ADDRESS;
+  m_attributeTypes[IFL_A_BROADCAST] = ADDRESS;
+  m_attributeTypes[IFL_A_IFNAME] = STRING;
+  m_attributeTypes[IFL_A_MTU] = U32;
+  m_attributeTypes[IFL_A_LINK] = U32;
+  m_attributeTypes[IFL_A_QDISC] = U8;
+  m_attributeTypes[IFL_A_STATS] = UNSPEC;
+  m_attributeTypes[IFL_A_COST] = UNSPEC;
+}
+InterfaceInfoMessage::~InterfaceInfoMessage ()
+{}
+void
+InterfaceInfoMessage::SetDeviceType (uint16_t type)
+{
+  m_deviceType = type;
+}
+void
+InterfaceInfoMessage::SetInterfaceIndex (int32_t index)
+{
+  m_interfaceIndex = index;
+}
+void
+InterfaceInfoMessage::SetDeviceFlags (uint32_t flags)
+{
+  m_deviceFlags = flags;
+}
+void
+InterfaceInfoMessage::SetChangeMask (uint32_t mask)
+{
+  m_changeMask = mask;
+}
+uint16_t
+InterfaceInfoMessage::GetDeviceType (void) const
+{
+  return m_deviceType;
+}
+int32_t
+InterfaceInfoMessage::GetInterfaceIndex (void) const
+{
+  return m_interfaceIndex;
+}
+uint32_t
+InterfaceInfoMessage::GetDeviceFlags (void) const
+{
+  return m_deviceFlags;
+}
+uint32_t
+InterfaceInfoMessage::GetChangeMask (void) const
+{
+  return m_changeMask;
+}
+TypeId 
+InterfaceInfoMessage::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::InterfaceInfoMessage")
+    .SetParent<GeneralMessage> ()
+    .AddConstructor<InterfaceInfoMessage> ()
+    ;
+  return tid;
+}
+TypeId 
+InterfaceInfoMessage::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+void 
+InterfaceInfoMessage::Print (std::ostream &os) const
+{  
+  os << " ----InterfaceInfoMessage ("
+     << "deviceType: " << m_deviceType << " "
+     << "interfaceIndex: " << m_interfaceIndex << " "
+     << "deviceFlags: " << m_deviceFlags << " "
+     << "changeMask: " << m_changeMask << ")" ;
+  PrintAttribute (os);
+}
+uint32_t 
+InterfaceInfoMessage::GetSerializedSize (void) const
+{
+  return NETLINK_INTERFACE_SIZE + GetAttributeSerializedSize ();
+}
+
+void
+InterfaceInfoMessage::Serialize (Buffer::Iterator& start) const
+{
+  start.WriteU8 (m_family);
+  start.WriteU8 (m_reserved);
+  start.WriteU16 (m_deviceType);
+  start.WriteU32 (m_interfaceIndex);
+  start.WriteU32 (m_deviceFlags);
+  start.WriteU32 (m_changeMask);
+
+  SerializeAttribute (start);
+}
+uint32_t
+InterfaceInfoMessage::Deserialize (Buffer::Iterator& start, uint32_t len)
+{
+  m_family = start.ReadU8 ();
+  m_reserved = start.ReadU8 ();
+  m_deviceType = start.ReadU16 ();
+  m_interfaceIndex = start.ReadU32 ();
+  m_deviceFlags = start.ReadU32 ();
+  m_changeMask = start.ReadU32 ();
+
+  len -= NETLINK_INTERFACE_SIZE;
+
+  while (len)
+    {
+      NetlinkAttribute attr;
+
+      len -= attr.Deserialize (start, m_attributeTypes);
+      m_attributes.push_back (attr);
+    }
+
+  return GetSerializedSize ();
+}
+
+
+
+/***********************************************************************************
+* \InterfaceAddressMessage
+***********************************************************************************/
+InterfaceAddressMessage::InterfaceAddressMessage ()
+  : m_length (0),
+    m_flags (0),
+    m_scope (0),
+    m_index(0)
+{
+  memset ((void*)m_attributeTypes, 0, sizeof (m_attributeTypes));
+  m_attributeTypes[IF_A_UNSPEC] = UNSPEC;
+  m_attributeTypes[IF_A_ADDRESS] = ADDRESS;
+  m_attributeTypes[IF_A_LOCAL] = ADDRESS;
+  m_attributeTypes[IF_A_LABEL] = STRING;
+  m_attributeTypes[IF_A_BROADCAST] = ADDRESS;
+  m_attributeTypes[IF_A_ANYCAST] = ADDRESS;
+  m_attributeTypes[IF_A_CACHEINFO] = UNSPEC;
+  m_attributeTypes[IF_A_MULTICAST] = ADDRESS;
+}
+InterfaceAddressMessage::~InterfaceAddressMessage ()
+{
+}
+void
+InterfaceAddressMessage::SetFamily (uint8_t family)
+{
+  m_family = family;
+}
+void
+InterfaceAddressMessage::SetLength (uint8_t length)
+{
+  m_length = length;
+}
+void
+InterfaceAddressMessage::SetFlags (uint8_t flags)
+{
+  m_flags = flags;
+}
+void
+InterfaceAddressMessage::SetScope (uint8_t scope)
+{
+  m_scope = scope;
+}
+void
+InterfaceAddressMessage::SetInterfaceIndex (int32_t index)
+{
+  m_index = index;
+}
+
+uint8_t
+InterfaceAddressMessage::GetFamily (void) const
+{
+  return m_family;
+}
+uint8_t
+InterfaceAddressMessage::GetLength (void) const
+{
+  return m_length;
+}
+uint8_t
+InterfaceAddressMessage::GetFlags (void) const
+{
+  return m_flags;
+}
+uint8_t
+InterfaceAddressMessage::GetScope (void) const
+{
+  return m_scope;
+}
+int32_t
+InterfaceAddressMessage::GetInterfaceIndex (void) const
+{
+  return m_index;
+}
+
+TypeId 
+InterfaceAddressMessage::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::InterfaceAddressMessage")
+    .SetParent<GeneralMessage> ()
+    .AddConstructor<InterfaceAddressMessage> ()
+    ;
+  return tid;
+}
+TypeId 
+InterfaceAddressMessage::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+void 
+InterfaceAddressMessage::Print (std::ostream &os) const
+{  
+  os << " ----InterfaceAddressMessage ("
+     << "family: " << (uint32_t)m_family << " "
+     << "length: " << (uint32_t)m_length << " "
+     << "flags: " << (uint32_t)m_flags << " "
+     << "scope: " << (uint32_t)m_scope << " "
+     << "index: " << m_index << ")";
+  PrintAttribute (os);
+}
+uint32_t 
+InterfaceAddressMessage::GetSerializedSize (void) const
+{
+  return NETLINK_ADDRESS_SIZE + GetAttributeSerializedSize ();
+}
+
+void
+InterfaceAddressMessage::Serialize (Buffer::Iterator& start) const
+{
+  start.WriteU8 (m_family);
+  start.WriteU8 (m_length);
+  start.WriteU8 (m_flags);
+  start.WriteU8 (m_scope);
+  start.WriteU32 (m_index);
+
+  SerializeAttribute(start);
+}
+
+uint32_t
+InterfaceAddressMessage::Deserialize (Buffer::Iterator& start, uint32_t len)
+{
+  m_family = start.ReadU8 ();
+  m_length = start.ReadU8 ();
+  m_flags = start.ReadU8 ();
+  m_scope = start.ReadU8 ();
+  m_index = start.ReadU32 ();
+
+  len -= NETLINK_ADDRESS_SIZE;
+
+  while (len)
+    {
+      NetlinkAttribute attr;
+
+      len -= attr.Deserialize (start, m_attributeTypes);
+      m_attributes.push_back (attr);
+    }
+
+  return GetSerializedSize ();
+}
+
+
+
+/***********************************************************************************
+* \ RouteMessage
+***********************************************************************************/
+RouteMessage::RouteMessage ()
+  : m_dstLen (0),
+    m_srcLen (0),
+    m_tos (0),
+    m_tableId (0),
+    m_protocol(0),
+    m_scope (0),
+    m_type (0),
+    m_flags (0)
+{
+  memset ((void*)m_attributeTypes, 0, sizeof (m_attributeTypes));
+  m_attributeTypes[RT_A_UNSPEC] = UNSPEC;
+  m_attributeTypes[RT_A_DST] = ADDRESS;
+  m_attributeTypes[RT_A_SRC] = ADDRESS;
+  m_attributeTypes[RT_A_IIF] = U32;
+  m_attributeTypes[RT_A_OIF] = U32;
+  m_attributeTypes[RT_A_GATEWAY] = ADDRESS;
+  m_attributeTypes[RT_A_PRIORITY] = U8;
+  m_attributeTypes[RT_A_PREFSRC] = ADDRESS;
+  m_attributeTypes[RT_A_METRICS] = UNSPEC;
+  //others default value UNSPEC
+}
+RouteMessage::~RouteMessage ()
+{}
+
+void
+RouteMessage::SetFamily (uint8_t v)
+{
+  m_family = v;
+}
+void
+RouteMessage::SetDstLength (uint8_t v)
+{
+  m_dstLen = v;
+}
+void
+RouteMessage::SetSrcLength (uint8_t v)
+{
+  m_srcLen = v;
+}
+void
+RouteMessage::SetTos (uint8_t v)
+{
+  m_tos = v;
+}
+void
+RouteMessage::SetTableId (uint8_t v)
+{
+  m_tableId = v;
+}
+void
+RouteMessage::SetProtocol (uint8_t v)
+{
+  m_protocol = v;
+}
+void
+RouteMessage::SetScope (uint8_t v)
+{
+  m_scope = v;
+}
+void
+RouteMessage::SetType (uint8_t v)
+{
+  m_type = v;
+}
+void
+RouteMessage::SetFlags (uint32_t v)
+{
+  m_flags = v;
+}
+uint8_t
+RouteMessage::GetFamily (void) const
+{
+  return m_family;
+}
+uint8_t
+RouteMessage::GetDstLength (void) const
+{
+  return m_dstLen;
+}
+uint8_t
+RouteMessage::GetSrcLength (void) const
+{
+  return m_srcLen;
+}
+uint8_t
+RouteMessage::GetTos (void) const
+{
+  return m_tos;
+}
+uint8_t
+RouteMessage::GetTableId (void) const
+{
+  return m_tableId;
+}
+uint8_t
+RouteMessage::GetProtocol (void) const
+{
+  return m_protocol;
+}
+uint8_t
+RouteMessage::GetType (void) const
+{
+  return m_type;
+}
+uint8_t
+RouteMessage::GetScope (void) const
+{
+  return m_scope;
+}
+uint32_t
+RouteMessage::GetFlags (void) const
+{
+  return m_flags;
+}
+
+TypeId 
+RouteMessage::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::RouteMessage")
+    .SetParent<GeneralMessage> ()
+    .AddConstructor<RouteMessage> ()
+    ;
+  return tid;
+}
+TypeId 
+RouteMessage::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+void 
+RouteMessage::Print (std::ostream &os) const
+{  
+  os << " ----RouteMessage ("
+     << "family: " << (uint32_t)m_family << " "
+     << "dstLen: " << (uint32_t)m_dstLen << " "
+     << "srcLen: " << (uint32_t)m_srcLen << " "
+     << "tos: " << (uint32_t)m_tos << " "
+     << "tableId: " << (uint32_t)m_tableId << " "
+     << "protocol: " << (uint32_t)m_protocol << " "
+     << "scope: " << (uint32_t)m_scope << " "
+     << "type: " << (uint32_t)m_type << " "
+     << "flags: " << m_flags<< ")" ;
+  PrintAttribute (os);
+}
+uint32_t 
+RouteMessage::GetSerializedSize (void) const
+{
+  return NETLINK_ROUTE_SIZE + GetAttributeSerializedSize ();
+}
+
+void
+RouteMessage::Serialize (Buffer::Iterator& start) const
+{
+  start.WriteU8 (m_family);
+  start.WriteU8 (m_dstLen);
+  start.WriteU8 (m_srcLen);
+  start.WriteU8 (m_tos);
+  start.WriteU8 (m_tableId);
+  start.WriteU8 (m_protocol);
+  start.WriteU8 (m_scope);
+  start.WriteU8 (m_type);
+  start.WriteU32 (m_flags);
+
+  SerializeAttribute (start);
+}
+uint32_t
+RouteMessage::Deserialize (Buffer::Iterator& start, uint32_t len)
+{
+  m_family = start.ReadU8 ();
+  m_dstLen = start.ReadU8 ();
+  m_srcLen = start.ReadU8 ();
+  m_tos = start.ReadU8 ();
+  m_tableId = start.ReadU8 ();
+  m_protocol = start.ReadU8 ();
+  m_scope = start.ReadU8 ();
+  m_type = start.ReadU8 ();
+  m_flags = start.ReadU32 ();
+
+  len -= NETLINK_ROUTE_SIZE;
+
+  while (len)
+    {
+      NetlinkAttribute attr;
+
+      len -= attr.Deserialize (start, m_attributeTypes);
+      m_attributes.push_back (attr);
+    }
+
+  return GetSerializedSize ();
+}
+}; // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-message-route.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,388 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#ifndef NETLINK_MESSAGE_ROUTE_H
+#define NETLINK_MESSAGE_ROUTE_H
+
+#include "ns3/object-base.h"
+#include "ns3/address.h"
+#include "netlink-attribute.h"
+#include <string>
+
+namespace ns3 {
+
+/*
+* this file define some netlink message of NETLINK_ROUTE protocol,
+* there are mainly three types:interface address, interface info, route entry
+* just implemented them for quagga porting.
+*/
+  
+
+
+/**
+* \Types of messages,here we only define the route message types quagga used
+*/
+enum NetlinkRtmType_e {
+  NETLINK_RTM_BASE = 16,
+
+  NETLINK_RTM_NEWLINK = 16,
+  NETLINK_RTM_DELLINK,
+  NETLINK_RTM_GETLINK,
+  NETLINK_RTM_SETLINK,
+
+  NETLINK_RTM_NEWADDR = 20,
+  NETLINK_RTM_DELADDR,
+  NETLINK_RTM_GETADDR,
+
+  NETLINK_RTM_NEWROUTE = 24,
+  NETLINK_RTM_DELROUTE,
+  NETLINK_RTM_GETROUTE,
+
+  NETLINK_RTM_MAX,
+};  
+
+/**
+* \Types of netlink groups,here we only define types quagga used
+*/
+enum NetlinkRtmGroup_e {
+  NETLINK_RTM_GRP_LINK = 1,
+  NETLINK_RTM_GRP_IPV4_IFADDR = 0x10,
+  NETLINK_RTM_GRP_IPV4_ROUTE = 0x40,
+  RTMGRP_IPV6_IFADDR = 0x100,
+  RTMGRP_IPV6_ROUTE = 0x400,
+};
+
+class NetlinkPayload :public ObjectBase
+{
+public:
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const = 0;
+  virtual void Serialize (Buffer::Iterator& start) const = 0;
+  virtual void Print (std::ostream &os) const = 0;
+  virtual uint32_t GetSerializedSize (void) const = 0;
+};
+
+/***
+ General form of address family dependent message.
+
+  struct rtgenmsg
+  {
+    unsigned char		rtgen_family;
+  };
+**/
+
+class GeneralMessage : public NetlinkPayload
+{
+public:
+  GeneralMessage ();
+  virtual ~GeneralMessage ();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual void Serialize (Buffer::Iterator& start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator& start);
+  virtual uint32_t Deserialize (Buffer::Iterator& start, uint32_t len);
+  virtual void Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize (void) const;
+
+  
+  virtual uint32_t GetNNetlinkAttribute (void)const;
+  virtual NetlinkAttribute GetNetlinkAttribute (uint32_t index)const;
+  virtual void AppendAttribute (NetlinkAttribute v);
+  virtual void SerializeAttribute (Buffer::Iterator& start) const;
+  virtual void PrintAttribute (std::ostream &os) const;
+  virtual uint32_t GetAttributeSerializedSize (void) const;
+  virtual bool GetAttributeByType (NetlinkAttribute& attr, uint16_t type);
+
+
+  void SetFamily (uint8_t v);
+  uint8_t GetFamily (void) const;
+
+private:
+  static const int NETLINK_GENMSG_SIZE = 1; /* size of the struct rtgenmsg */  
+protected:
+  uint8_t m_family;   //always set to AF_UNSPEC
+  //attribute can exist or not
+  std::vector<NetlinkAttribute> m_attributes;
+};
+
+
+
+/**
+* \brief Link layer specific messages
+*
+* struct ifinfomsg
+* passes link level specific information, not dependent
+* on network protocol.
+*
+  struct ifinfomsg
+  {
+    unsigned char	ifi_family;
+    unsigned char	__ifi_pad;
+    unsigned short	ifi_type;
+    int		ifi_index;	
+    unsigned	ifi_flags;
+    unsigned	ifi_change;
+  };
+*/
+class InterfaceInfoMessage : public GeneralMessage
+{
+public:
+  InterfaceInfoMessage ();
+  virtual ~InterfaceInfoMessage ();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual void Serialize (Buffer::Iterator& start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator& start, uint32_t len);
+  virtual void Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize (void) const;
+
+  enum IflAttr_e {
+    IFL_A_UNSPEC,
+    IFL_A_ADDRESS,
+    IFL_A_BROADCAST,
+    IFL_A_IFNAME,
+    IFL_A_MTU,
+    IFL_A_LINK,
+    IFL_A_QDISC,
+    IFL_A_STATS,
+    IFL_A_COST,
+    IFL_A_PRIORITY,
+    IFL_A_MASTER,
+    IFL_A_WIRELESS,		
+    IFL_A_PROTINFO,
+    IFL_A_TXQLEN,
+    IFL_A_MAP,
+    IFL_A_WEIGHT,
+    IFL_A_OPERSTATE,
+    IFL_A_LINKMODE,
+    IFL_A_MAX,
+  };
+
+  enum Type_e {
+    UP = 1,
+    BROADCAST = 2,
+    DBG = 4,
+  };
+
+  void SetDeviceType (uint16_t type);
+  void SetInterfaceIndex (int32_t index);
+  void SetDeviceFlags (uint32_t index);
+  void SetChangeMask (uint32_t mask);
+
+  uint16_t GetDeviceType (void) const;
+  int32_t GetInterfaceIndex (void) const;
+  uint32_t GetDeviceFlags (void) const;
+  uint32_t GetChangeMask (void) const;
+private:
+  static const int NETLINK_INTERFACE_SIZE = 16; /* size of the struct ifinfomsg */
+  uint8_t m_reserved; //not used
+  uint16_t m_deviceType;
+  int32_t m_interfaceIndex;
+  uint32_t m_deviceFlags;
+  uint32_t m_changeMask;
+  NetlinkAttributeValueType m_attributeTypes[IFL_A_MAX];
+};
+
+
+
+
+/**
+* \brief Interface address.
+*
+  struct ifaddrmsg
+  {
+  unsigned char	ifa_family;
+  unsigned char	ifa_prefixlen;
+  unsigned char	ifa_flags;
+  unsigned char	ifa_scope;
+  int		ifa_index;
+  };
+*/
+
+class InterfaceAddressMessage : public GeneralMessage
+{
+public:
+  InterfaceAddressMessage ();
+  virtual ~InterfaceAddressMessage ();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual void Serialize (Buffer::Iterator& start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator& start, uint32_t len);
+  virtual void Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize (void) const;
+
+  enum IfAttr_e {
+    IF_A_UNSPEC,
+    IF_A_ADDRESS,
+    IF_A_LOCAL,
+    IF_A_LABEL,
+    IF_A_BROADCAST,
+    IF_A_ANYCAST,
+    IF_A_CACHEINFO,
+    IF_A_MULTICAST,
+    IF_A_MAX
+  };
+
+  enum {
+    F_SECONDARY = 0x01,
+    F_PERMANENT = 0x80,
+    F_DEPRECATED = 0x20,
+    F_TENTATIVE = 0x40
+  };
+  enum {
+    SCOPE_UNIVERSE = 0,
+    SCOPE_SITE = 200,
+    SCOPE_LINK = 253,
+    SCOPE_HOST = 254
+  };
+
+
+  void SetFamily (uint8_t family);
+  void SetLength (uint8_t length);
+  void SetFlags (uint8_t flags);
+  void SetScope (uint8_t scope);
+  void SetInterfaceIndex (int32_t index);
+
+  uint8_t GetFamily (void) const;
+  uint8_t GetLength (void) const;
+  uint8_t GetFlags (void) const;
+  uint8_t GetScope (void) const;
+  int32_t GetInterfaceIndex (void) const;
+
+private:
+  static const int NETLINK_ADDRESS_SIZE = 8; /* size of the struct ifaddrmsg */
+  uint8_t m_length;
+  uint8_t m_flags;
+  uint8_t m_scope;
+  int32_t m_index;
+  NetlinkAttributeValueType m_attributeTypes[IF_A_MAX];
+};
+
+
+/**
+* \brief Definitions used in routing table administration.
+*
+  struct rtmsg
+  {
+    unsigned char		rtm_family;
+    unsigned char		rtm_dst_len;
+    unsigned char		rtm_src_len;
+    unsigned char		rtm_tos;
+
+    unsigned char		rtm_table;	// Routing table id 
+    unsigned char		rtm_protocol;	//Routing protocol; 
+    unsigned char		rtm_scope;	
+    unsigned char		rtm_type;	
+
+    unsigned		rtm_flags;
+  };
+*/
+
+class RouteMessage : public GeneralMessage
+{
+public:
+  RouteMessage ();
+  virtual ~RouteMessage ();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual void Serialize (Buffer::Iterator& start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator& start, uint32_t len);
+  virtual void Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize (void) const;
+
+  uint8_t GetFamily (void) const;
+  uint8_t GetDstLength (void) const;
+  uint8_t GetSrcLength (void) const;
+  uint8_t GetTos (void) const;
+  uint8_t GetTableId (void) const;
+  uint8_t GetProtocol(void) const;
+  uint8_t GetType (void) const;
+  uint8_t GetScope (void) const;
+  uint32_t GetFlags (void) const;
+  void SetFamily (uint8_t v);
+  void SetDstLength (uint8_t v);
+  void SetSrcLength (uint8_t v);
+  void SetTos (uint8_t v);
+  void SetTableId (uint8_t v);
+  void SetProtocol (uint8_t v);
+  void SetScope (uint8_t v);
+  void SetType (uint8_t v);
+  void SetFlags (uint32_t v);
+
+  enum RtProtocol_e {
+    RT_PROT_UNSPEC = 0,
+  };
+
+  enum RtFlags_e {
+    RT_F_CLONED = 0x200,
+  };
+
+  enum RtScope_e {
+    RT_SCOPE_UNIVERSE = 0,
+    RT_SCOPE_LINK = 253,
+  };
+
+  enum RtClass_e {
+    RT_TABLE_UNSPEC = 0,
+    RT_TABLE_MAIN = 254,
+  };
+
+  enum RtAttr_e {
+    RT_A_UNSPEC,
+    RT_A_DST,
+    RT_A_SRC,
+    RT_A_IIF,
+    RT_A_OIF,
+    RT_A_GATEWAY,
+    RT_A_PRIORITY,
+    RT_A_PREFSRC,
+    RT_A_METRICS,
+    RT_A_MULTIPATH,
+    RT_A_PROTOINFO,
+    RT_A_FLOW,
+    RT_A_CACHEINFO,
+    RT_A_SESSION,
+    RT_A_MP_ALGO,
+    RT_A_TABLE,
+    RT_A_MAX
+  };
+
+
+private:
+  static const int NETLINK_ROUTE_SIZE = 12; /* size of the struct rtmsg */
+  uint8_t m_dstLen;
+  uint8_t m_srcLen;
+  uint8_t m_tos;
+  uint8_t m_tableId;
+  uint8_t m_protocol;
+  uint8_t m_scope;
+  uint8_t m_type;
+  uint32_t m_flags;
+  NetlinkAttributeValueType m_attributeTypes[RT_A_MAX];
+};
+
+}; // namespace ns3
+
+#endif /* NETLINK_MESSAGE_ROUTE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-message.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,672 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#include "netlink-message.h"
+#include "ns3/address-utils.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("NetlinkMessage");
+
+namespace ns3 {
+
+/***********************************************************************************
+* \ NetlinkMessageHeader
+***********************************************************************************/
+NS_OBJECT_ENSURE_REGISTERED (NetlinkMessageHeader);
+NS_OBJECT_ENSURE_REGISTERED (NetlinkMessage);
+
+NetlinkMessageHeader::NetlinkMessageHeader ()
+  : m_nlmsgLen (16),
+    m_nlmsgType (0),
+    m_nlmsgFlags (0),
+    m_nlmsgSeq (0),
+    m_nlmsgPid (0)
+{}
+
+NetlinkMessageHeader::NetlinkMessageHeader (uint16_t type, uint16_t flags, uint32_t seq, uint32_t pid)
+  : m_nlmsgLen (16),
+    m_nlmsgType (type),
+    m_nlmsgFlags (flags),
+    m_nlmsgSeq (seq),
+    m_nlmsgPid (pid)
+{}
+
+void
+NetlinkMessageHeader::SetMsgLen (uint32_t v)
+{
+  m_nlmsgLen = v;
+}
+void
+NetlinkMessageHeader::SetMsgFlags (uint16_t v)
+{
+  m_nlmsgFlags = v;
+}
+void
+NetlinkMessageHeader::SetMsgType (uint16_t v)
+{
+  m_nlmsgType = v;
+}
+void
+NetlinkMessageHeader::SetMsgSeq (uint32_t v)
+{
+  m_nlmsgSeq = v;
+}
+void
+NetlinkMessageHeader::SetMsgPid (uint32_t v)
+{
+  m_nlmsgPid = v;
+}
+uint16_t
+NetlinkMessageHeader::GetMsgFlags (void) const
+{
+  return m_nlmsgFlags;
+}
+uint32_t 
+NetlinkMessageHeader::GetMsgLen (void) const
+{
+  return m_nlmsgLen;
+}
+uint16_t 
+NetlinkMessageHeader::GetMsgType (void) const
+{
+  return m_nlmsgType;
+}
+uint32_t
+NetlinkMessageHeader::GetMsgSeq (void) const
+{
+  return m_nlmsgSeq;
+}
+uint32_t 
+NetlinkMessageHeader::GetMsgPid (void) const
+{
+  return m_nlmsgPid;
+}
+uint32_t
+NetlinkMessageHeader::GetHeaderSize ()
+{
+  return NETLINK_MSG_HEADER_SIZE;
+}
+uint32_t
+NetlinkMessageHeader::GetPayloadSize (void) const
+{
+  return NETLINK_MSG_ALIGN (m_nlmsgLen - NETLINK_MSG_HEADER_SIZE);
+}
+
+TypeId 
+NetlinkMessageHeader::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::NetlinkMessageHeader")
+    .SetParent<Header> ()
+    .AddConstructor<NetlinkMessageHeader> ()
+    ;
+  return tid;
+}
+TypeId 
+NetlinkMessageHeader::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+void 
+NetlinkMessageHeader::Print (std::ostream &os) const
+{
+  os << "NetlinkMessageHeader "
+     << "len: " << m_nlmsgLen << " "
+     << "flags: " << m_nlmsgFlags << " "
+     << "type: " << m_nlmsgType << " "
+     << "seq: " << m_nlmsgSeq << " "
+     << "pid: " << m_nlmsgPid;
+}
+
+uint32_t 
+NetlinkMessageHeader::GetSerializedSize (void) const
+{
+  /* this is the size of an nlmsghdr payload. */
+  return NETLINK_MSG_HEADER_SIZE;
+}
+
+void
+NetlinkMessageHeader::Serialize (Buffer::Iterator& start) const
+{
+  start.WriteU32 (m_nlmsgLen);
+  start.WriteU16 (m_nlmsgType);
+  start.WriteU16 (m_nlmsgFlags);
+  start.WriteU32 (m_nlmsgSeq);
+  start.WriteU32 (m_nlmsgPid);
+}
+
+uint32_t
+NetlinkMessageHeader::Deserialize (Buffer::Iterator& start)
+{
+  m_nlmsgLen = start.ReadU32 ();
+  m_nlmsgType = start.ReadU16 ();
+  m_nlmsgFlags = start.ReadU16 ();
+  m_nlmsgSeq = start.ReadU32 ();
+  m_nlmsgPid = start.ReadU32 ();
+
+  return GetSerializedSize ();
+}
+
+
+
+
+/***********************************************************************************
+* \ NetlinkMessageError
+***********************************************************************************/
+
+NetlinkMessageError::NetlinkMessageError ()
+  : m_error (0)
+{
+}
+NetlinkMessageError::~NetlinkMessageError ()
+{}
+void 
+NetlinkMessageError::SetError (int32_t v)
+{
+  m_error = v;
+}
+int32_t
+NetlinkMessageError::GetError (void) const
+{
+  return m_error;
+}
+void
+NetlinkMessageError::SetMsg (NetlinkMessageHeader v)
+{
+  m_msg = v;
+}
+NetlinkMessageHeader
+NetlinkMessageError::GetMsg (void) const
+{
+  return m_msg;
+}
+
+TypeId 
+NetlinkMessageError::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::NetlinkMessageError")
+    .SetParent<NetlinkPayload> ()
+    .AddConstructor<NetlinkMessageError> ()
+    ;
+  return tid;
+}
+
+TypeId 
+NetlinkMessageError::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+void 
+NetlinkMessageError::Print (std::ostream &os) const
+{  
+  os << "----NetlinkMessageError "
+     << "error: " << m_error << " "
+     << "msg:( ";
+  m_msg.Print(os);
+  os << " )";
+}
+
+uint32_t 
+NetlinkMessageError::GetSerializedSize (void) const
+{
+  /* this is the size of an nlmsgerr payload. */
+  return NETLINK_MSG_ERROR_SIZE;
+}
+
+void
+NetlinkMessageError::Serialize (Buffer::Iterator& start) const
+{
+  start.WriteU32 (m_error);
+  m_msg.Serialize (start);
+}
+
+uint32_t
+NetlinkMessageError::Deserialize (Buffer::Iterator& start)
+{  
+  m_error = start.ReadU32 ();
+  m_msg.Deserialize (start);
+  
+  return GetSerializedSize ();
+}
+
+
+
+
+/***********************************************************************************
+* \ NetlinkMessage
+***********************************************************************************/
+NetlinkMessage::NetlinkMessage ()
+{}
+
+void
+NetlinkMessage::SetHeader (NetlinkMessageHeader hdr)
+{
+  m_hdr = hdr;
+}
+NetlinkMessageHeader
+NetlinkMessage::GetHeader (void)const
+{
+  return m_hdr;
+}
+void
+NetlinkMessage::SetGeneralMessage (GeneralMessage genmsg)
+{
+  m_genmsg = genmsg;
+  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + genmsg.GetSerializedSize ());
+}
+void
+NetlinkMessage::SetErrorMessage (NetlinkMessageError errmsg)
+{
+  m_errorMessage = errmsg;
+  m_hdr.SetMsgLen(m_hdr.GetSerializedSize () + errmsg.GetSerializedSize ());
+}
+// the type is one of RTM_NEWLINK,RTM_DELLINK,RTM_GETLINK
+void
+NetlinkMessage::SetInterfaceInfoMessage (InterfaceInfoMessage v)
+{
+  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + v.GetSerializedSize ());
+  m_interfaceTemplate = v;
+}
+// the type is one of RTM_NEWADDR,RTM_DELADDR,RTM_GETADDR
+void NetlinkMessage::SetInterfaceAddressMessage (InterfaceAddressMessage v)
+{
+  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + v.GetSerializedSize ());
+  m_addressTemplate = v;
+}
+// the type  is one of RTM_NEWROUTE,RTM_DELROUTE,RTM_GETROUTE
+void NetlinkMessage::SetRouteMessage (RouteMessage v)
+{
+  m_hdr.SetMsgLen (m_hdr.GetSerializedSize () + v.GetSerializedSize ());
+  m_routeTemplate = v;
+}
+GeneralMessage
+NetlinkMessage::GetGeneralMessage (void) const
+{
+  return m_genmsg;
+}
+NetlinkMessageError
+NetlinkMessage::GetErrorMessage (void) const
+{
+  return m_errorMessage;
+}
+InterfaceInfoMessage
+NetlinkMessage::GetInterfaceInfoMessage (void) const
+{
+  return m_interfaceTemplate;
+}
+InterfaceAddressMessage
+NetlinkMessage::GetInterfaceAddressMessage (void) const
+{
+  return m_addressTemplate;
+}
+RouteMessage
+NetlinkMessage::GetRouteMessage (void) const
+{
+  return m_routeTemplate;
+}
+bool
+NetlinkMessage::IsMessageNetlinkControl (uint16_t type)
+{
+  return (type < NETLINK_RTM_BASE);
+}
+bool
+NetlinkMessage::IsMessageNetlinkRoute (uint16_t type)
+{
+  return (type >= NETLINK_RTM_BASE && type < NETLINK_RTM_MAX);
+}
+bool
+NetlinkMessage::IsMessageAddress (uint16_t type)
+{
+  return (type >= NETLINK_RTM_NEWADDR && type <= NETLINK_RTM_GETADDR);
+}
+bool
+NetlinkMessage::IsMessageInterface (uint16_t type)
+{
+  return (type >= NETLINK_RTM_NEWLINK && type <= NETLINK_RTM_SETLINK);
+}
+bool
+NetlinkMessage::IsMessageRoute (uint16_t type)
+{
+  return (type >= NETLINK_RTM_NEWROUTE && type <= NETLINK_RTM_GETROUTE);
+}
+bool
+NetlinkMessage::IsMessageTypeGet (uint16_t type)
+{
+  return ((( type - NETLINK_RTM_BASE)&3) == 2);
+}
+bool
+NetlinkMessage::IsMessageFlagsAck (uint16_t flags)
+{
+  return (flags & NETLINK_MSG_F_ACK) ? true : false;
+}
+bool
+NetlinkMessage::IsMessageFlagsRequest (uint16_t flags)
+{
+  return (flags & NETLINK_MSG_F_REQUEST) ? true : false;
+}
+bool
+NetlinkMessage::IsMessageFlagsDump (uint16_t flags)
+{
+  return (flags & NETLINK_MSG_F_DUMP) ? true : false;
+}
+
+NetlinkMessage::operator MultipartNetlinkMessage (void) const
+{
+  MultipartNetlinkMessage multi_nlmsg;
+  multi_nlmsg.AppendMessage (*this);
+  return multi_nlmsg;
+}
+
+TypeId 
+NetlinkMessage::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::NetlinkMessage")
+    .SetParent<Header> ()
+    .AddConstructor<NetlinkMessage> ()
+    ;
+  return tid;
+}
+TypeId 
+NetlinkMessage::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+NetlinkMessage::GetTotalSize (void) const
+{
+  return NETLINK_MSG_ALIGN (m_hdr.GetMsgLen ());
+}
+
+uint32_t
+NetlinkMessage::GetMsgSize (void) const
+{
+  return m_hdr.GetMsgLen ();
+}
+
+uint32_t
+NetlinkMessage::GetPayloadSize (void) const
+{
+  return m_hdr.GetPayloadSize ();
+}
+uint16_t
+NetlinkMessage::GetMsgType (void) const
+{
+  return m_hdr.GetMsgType ();
+}
+
+uint8_t
+NetlinkMessage::GetFamily(void) const
+{
+  if (IsMessageTypeGet (GetMsgType ()))
+    {
+      NS_LOG_DEBUG ("TypeGetMsg");
+    }
+  if (IsMessageAddress (m_hdr.GetMsgType ()))
+    {
+      return m_addressTemplate.GetFamily ();
+    }
+  else if (IsMessageInterface(m_hdr.GetMsgType ()))
+    {
+      return m_interfaceTemplate.GetFamily ();
+    }
+  else if (IsMessageRoute(m_hdr.GetMsgType ()))
+    {
+      return m_routeTemplate.GetFamily ();
+    }
+  else if (IsMessageFlagsDump (m_hdr.GetMsgFlags ()))
+    {
+      return m_genmsg.GetFamily (); //value is said to be always set to AF_UNSPEC
+    }
+  else
+    {
+      NS_LOG_WARN ("Netlink message type not supported, return AF_UNSPEC");
+      return 0;
+    }
+}
+
+void 
+NetlinkMessage::Print (std::ostream &os) const
+{
+  uint16_t type = m_hdr.GetMsgType ();
+
+  os << "NetlinkMessage  ";
+  os << " ----Header:(";
+  m_hdr.Print(os);
+  os << ")";
+
+  if (type == NETLINK_MSG_DONE )
+    {
+      os << "multipart message ends here";
+    }
+  else if (type == NETLINK_MSG_ERROR )
+    {
+      m_errorMessage.Print (os);
+    }
+  else if (type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETLINK)
+    {
+      m_genmsg.Print (os);
+    }  
+  else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE)
+    {
+      m_routeTemplate.Print (os);
+    }
+  else if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
+    {
+      m_addressTemplate.Print (os);
+    }
+  else if (type == NETLINK_RTM_NEWLINK || type == NETLINK_RTM_DELLINK)
+    {
+      m_interfaceTemplate.Print (os);
+    }
+  else
+    {
+      os << "service not supported yet( " << type <<")";
+    }
+}
+uint32_t 
+NetlinkMessage::GetSerializedSize (void) const
+{
+  return NETLINK_MSG_ALIGN (m_hdr.GetMsgLen ());
+}
+
+void
+NetlinkMessage::Serialize (Buffer::Iterator& start) const
+{
+  NS_LOG_FUNCTION (this);
+  //  Print (std::cout);
+  uint16_t type = m_hdr.GetMsgType ();
+
+  m_hdr.Serialize (start);
+
+  if (type == NETLINK_MSG_DONE)
+    {
+      //nothing done
+    }
+  else if (type == NETLINK_MSG_ERROR)
+    {
+      m_errorMessage.Serialize (start);
+    }  
+  else if (NetlinkMessage::IsMessageFlagsDump (m_hdr.GetMsgFlags ()) && 
+           (type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETLINK))
+    {
+      m_genmsg.Serialize (start);
+    }  
+  else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE || type == NETLINK_RTM_GETROUTE)
+    {
+      m_routeTemplate.Serialize (start);
+    }
+  else if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
+    {
+      m_addressTemplate.Serialize (start);
+    }
+  else if (type == NETLINK_RTM_NEWLINK || type == NETLINK_RTM_SETLINK)
+    {
+      m_interfaceTemplate.Serialize (start);
+    }
+  else
+    {
+    }  
+}
+
+
+uint32_t
+NetlinkMessage::Deserialize (Buffer::Iterator&start)
+{
+  uint32_t remaining;
+
+  m_hdr.Deserialize (start);
+  remaining = NETLINK_MSG_ALIGN (m_hdr.GetMsgLen ()) - m_hdr.GetSerializedSize ();
+  
+  //Deserialize service module
+  uint16_t type = GetMsgType ();
+  if (remaining)
+    {        
+      if (type == NETLINK_MSG_DONE)
+        {
+          //do nothing
+        }
+      else if (type == NETLINK_MSG_ERROR)
+        {
+          remaining -= m_errorMessage.Deserialize (start);
+        }      
+      else if (NetlinkMessage::IsMessageFlagsDump (m_hdr.GetMsgFlags()) &&
+               (type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETLINK))
+        {
+          remaining -= m_genmsg.Deserialize (start, remaining);
+        }
+      else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE || type == NETLINK_RTM_GETROUTE)
+        {
+          remaining -= m_routeTemplate.Deserialize (start, remaining);
+        }
+      else if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
+        {
+          remaining -= m_addressTemplate.Deserialize (start, remaining);
+        }
+      else if (type == NETLINK_RTM_NEWLINK || type == NETLINK_RTM_SETLINK)
+        {
+          remaining -= m_interfaceTemplate.Deserialize (start, remaining);
+        }
+      else
+        {
+          //do nothing
+        }
+    }
+
+  return GetSerializedSize ();
+}
+
+
+/***********************************************************************************
+* \ MultipartNetlinkMessage
+***********************************************************************************/
+MultipartNetlinkMessage::MultipartNetlinkMessage ()
+{}
+
+TypeId 
+MultipartNetlinkMessage::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::MultipartNetlinkMessage")
+    .SetParent<Header> ()
+    .AddConstructor<MultipartNetlinkMessage> ()
+    ;
+  return tid;
+}
+TypeId 
+MultipartNetlinkMessage::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+void
+MultipartNetlinkMessage::Print (std::ostream &os) const
+{
+  for (uint32_t i = 0; i <  m_netlinkMessages.size (); i ++)
+    {
+      m_netlinkMessages[i].Print (os);
+    }
+}
+uint32_t
+MultipartNetlinkMessage::GetSerializedSize (void) const
+{
+  uint32_t len = 0;
+
+  for (uint32_t i = 0; i <  m_netlinkMessages.size (); i ++)
+    {
+      len +=  m_netlinkMessages[i].GetSerializedSize ();
+    }
+  return len;
+}
+void
+MultipartNetlinkMessage::Serialize (Buffer::Iterator start) const
+{
+  NS_LOG_FUNCTION ("Multi" << this);
+  for (uint32_t i = 0; i <  m_netlinkMessages.size (); i ++)
+    {
+      m_netlinkMessages[i].Serialize (start);
+    }
+}
+uint32_t
+MultipartNetlinkMessage::Deserialize (Buffer::Iterator start)
+{
+  while (1)
+    {
+      NetlinkMessage nlmsg;
+      nlmsg.Deserialize (start);
+      AppendMessage (nlmsg);
+
+      if (!(nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_MULTI))
+        {
+          break;
+        }
+
+      if (nlmsg.GetHeader ().GetMsgType() == NETLINK_MSG_DONE)
+        {
+          break;
+        }
+    }
+  return GetSerializedSize ();
+}
+
+void
+MultipartNetlinkMessage::AppendMessage (NetlinkMessage nlmsg)
+{
+  m_netlinkMessages.push_back (nlmsg);
+}
+
+void
+MultipartNetlinkMessage::Clear ()
+{
+  m_netlinkMessages.clear ();
+}
+
+uint32_t
+MultipartNetlinkMessage::GetNMessages (void) const
+{
+  return m_netlinkMessages.size ();
+}
+NetlinkMessage
+MultipartNetlinkMessage::GetMessage (uint32_t index) const
+{
+  NS_ASSERT(index < m_netlinkMessages.size ());
+  return m_netlinkMessages[index];
+}
+
+}; // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-message.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,256 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#ifndef NETLINK_MESSAGE_H
+#define NETLINK_MESSAGE_H
+
+#include "ns3/header.h"
+#include "ns3/address.h"
+#include "netlink-message-route.h"
+#include "netlink-attribute.h"
+
+
+namespace ns3 {
+  class NetlinkPayload;
+  class GeneralMessage;
+  class InterfaceAddressMessage;
+  class InterfaceInfoMessage;
+  class RouteMessage;
+  class MultipartNetlinkMessage;
+
+/**
+* \brief The Netlink message structure for an netlink packet
+* 
+There are three levels to a Netlink message: The general Netlink
+message header, the IP service specific template, and the IP service
+specific data.
+
+0                   1                   2                   3
+0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+|                   Netlink message header                      |
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+|                  IP Service Template                          |
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+|                  IP Service specific data in TLVs             |
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+  enum NetlinkMessageFlag
+  {
+    NETLINK_MSG_F_REQUEST = 1,  // It is request message.
+    NETLINK_MSG_F_MULTI = 2,    // Multipart message, terminated by NETLINK_MSG_DONE
+    NETLINK_MSG_F_ACK = 4,      // Reply with ack, with zero or error code
+    NETLINK_MSG_F_ECHO = 8,     // Echo this request 
+
+    /* Modifiers to Get request */
+    NETLINK_MSG_F_ROOT = 0x100,        // specify tree root
+    NETLINK_MSG_F_MATCH = 0x200,       // return all matching
+    NETLINK_MSG_F_ATOMIC = 0x400,      // atomic Get =
+    NETLINK_MSG_F_DUMP = (NETLINK_MSG_F_ROOT|NETLINK_MSG_F_MATCH),
+
+    /* Modifiers to NEW request */
+    NETLINK_MSG_F_REPLACE = 0x100, // Override existing = 
+    NETLINK_MSG_F_EXCL = 0x200,   // Do not touch, if it exists
+    NETLINK_MSG_F_CREATE = 0x400,  // Create, if it does not exist
+    NETLINK_MSG_F_APPEND = 0x800,  // Add to end of list = 
+  };
+
+  enum NetlinkMessageType
+  {
+    NETLINK_MSG_NOOP = 0x1,          // Nothing.
+    NETLINK_MSG_ERROR = 0x2,         // Error
+    NETLINK_MSG_DONE = 0x3,          // End of a dump
+    NETLINK_MSG_OVERRUN = 0x4,       // Data lost
+    NETLINK_MSG_MIN_TYPE = 0x10,     // < 0x10: reserved control messages
+  };
+
+#define NETLINK_MSG_ALIGNTO 4
+#define NETLINK_MSG_ALIGN(X)    (((X)+NETLINK_MSG_ALIGNTO-1) & ~(NETLINK_MSG_ALIGNTO-1) )
+
+class NetlinkMessageHeader : public ObjectBase
+{
+public:
+  NetlinkMessageHeader ();
+  NetlinkMessageHeader (uint16_t type, uint16_t flags, uint32_t seq, uint32_t pid);
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator& start) const;
+  uint32_t Deserialize (Buffer::Iterator& start);
+
+  void SetMsgLen (uint32_t v);
+  void SetMsgFlags (uint16_t v);
+  void SetMsgType (uint16_t v);
+  void SetMsgSeq (uint32_t v);
+  void SetMsgPid (uint32_t v);
+  uint32_t GetMsgLen (void) const;
+  uint16_t GetMsgFlags (void) const;
+  uint16_t GetMsgType (void) const;
+  uint32_t GetMsgSeq (void) const;
+  uint32_t GetMsgPid (void) const;
+
+  static uint32_t GetHeaderSize ();
+  uint32_t GetPayloadSize (void) const;
+
+private:
+  static const uint32_t NETLINK_MSG_HEADER_SIZE = 16; /* size of the nlmsghdr field*/
+  uint32_t m_nlmsgLen;	/* Length of message including header */
+  uint16_t m_nlmsgType;	/* Message content */
+  uint16_t m_nlmsgFlags;	/* Additional flags */
+  uint32_t m_nlmsgSeq;	/* Sequence number */
+  uint32_t m_nlmsgPid;	/* Sending process PID */
+};
+
+/**
+* \brief The struct nlmsgerr
+*/
+class NetlinkMessageError : public NetlinkPayload
+{
+public:
+  NetlinkMessageError ();
+  virtual ~NetlinkMessageError();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual void Serialize (Buffer::Iterator& start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator& start);
+  virtual void Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize (void) const;
+
+  void SetError (int32_t v);
+  int32_t GetError (void) const;
+  void SetMsg(NetlinkMessageHeader v);
+  NetlinkMessageHeader GetMsg (void) const;
+
+private:
+  static const int NETLINK_MSG_ERROR_SIZE = 20; /* size of the nlmsgerror field*/
+  int32_t m_error;
+  NetlinkMessageHeader m_msg;        
+};
+
+
+class NetlinkMessage : public ObjectBase
+{
+public:
+  NetlinkMessage ();
+
+  static TypeId GetTypeId (void);
+  TypeId GetInstanceTypeId (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator& start) const;
+  uint32_t Deserialize (Buffer::Iterator& start);
+
+  operator MultipartNetlinkMessage (void) const;
+
+  uint32_t GetTotalSize (void) const;  //length of netlink message including padding
+  uint32_t GetMsgSize (void) const;    //length of netlink message not including padding
+  uint32_t GetPayloadSize (void) const; //length of message payload
+  uint16_t GetMsgType (void) const;
+  uint8_t GetFamily(void) const;
+
+  void SetHeader (NetlinkMessageHeader hdr);
+  NetlinkMessageHeader GetHeader (void) const;
+
+  //before set message body, should set header first
+  void SetErrorMessage (NetlinkMessageError errmsg);
+  void SetGeneralMessage (GeneralMessage genmsg);
+  void SetInterfaceInfoMessage (InterfaceInfoMessage v);
+  void SetInterfaceAddressMessage (InterfaceAddressMessage v);
+  void SetRouteMessage (RouteMessage v);
+  NetlinkMessageError GetErrorMessage (void) const;
+  GeneralMessage GetGeneralMessage (void) const;
+  InterfaceInfoMessage GetInterfaceInfoMessage (void) const;
+  InterfaceAddressMessage GetInterfaceAddressMessage (void) const;
+  RouteMessage GetRouteMessage (void) const;
+
+  /**
+  * \returns true if type was control type, false otherwise.
+  */
+  static bool IsMessageNetlinkControl (uint16_t type);
+  /**
+  * \returns true if type was netlink route, false otherwise.
+  */
+  static bool IsMessageNetlinkRoute (uint16_t type);
+  static bool IsMessageAddress (uint16_t type);
+  static bool IsMessageInterface (uint16_t type);
+  static bool IsMessageRoute (uint16_t type);
+  /**
+  * \returns true if type was GETxxx , false otherwise.
+  */
+  static bool IsMessageTypeGet (uint16_t type);
+  /**
+  * \returns true if flag has ack , false otherwise.
+  */
+  static bool IsMessageFlagsAck (uint16_t flags);
+  /**
+  * \returns true if flag has request , false otherwise.
+  */
+  static bool IsMessageFlagsRequest (uint16_t flags);
+  /**
+  * \returns true if flag has dump , false otherwise.
+  */
+  static bool IsMessageFlagsDump (uint16_t flags);
+
+private:
+  NetlinkMessageHeader m_hdr;
+
+  //only one type of messages below exists in real world application
+  NetlinkMessageError m_errorMessage;  
+  GeneralMessage m_genmsg;
+  InterfaceInfoMessage m_interfaceTemplate;
+  InterfaceAddressMessage m_addressTemplate;
+  RouteMessage m_routeTemplate;
+};
+
+class MultipartNetlinkMessage : public Header
+{
+public:
+  MultipartNetlinkMessage ();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual void Print (std::ostream &os) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+
+  void AppendMessage (NetlinkMessage nlmsg);
+  void Clear();
+  uint32_t GetNMessages (void) const;
+  NetlinkMessage GetMessage (uint32_t index) const;
+
+private:
+  std::vector<NetlinkMessage> m_netlinkMessages;
+};
+
+}; // namespace ns3
+
+#endif /* NETLINK_MESSAGE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-socket-address.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,121 @@
+/* -*-	Mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#include "netlink-socket-address.h"
+
+namespace ns3 {
+
+NetlinkSocketAddress::NetlinkSocketAddress (uint32_t pid, uint32_t groups)
+  : m_pid(pid),
+    m_groups(groups)
+{}
+
+NetlinkSocketAddress::NetlinkSocketAddress ()
+  : m_pid (0),
+    m_groups (0)
+{}
+
+NetlinkSocketAddress::~NetlinkSocketAddress ()
+{}
+
+void NetlinkSocketAddress::SetProcessID (uint32_t pid)
+{
+  m_pid = pid;
+}
+
+void NetlinkSocketAddress::SetGroupsMask (uint32_t mask)
+{
+  m_groups = mask;
+}
+
+uint32_t NetlinkSocketAddress::GetProcessID (void) const
+{
+  return m_pid;
+}
+
+uint32_t NetlinkSocketAddress::GetGroupsMask (void) const
+{
+  return m_groups;
+}
+
+NetlinkSocketAddress::operator Address (void) const
+{
+  return ConvertTo ();
+}
+
+Address NetlinkSocketAddress::ConvertTo (void) const
+{
+  uint8_t buffer[8];
+
+  buffer[0] = (m_pid >> 24) & 0xff;
+  buffer[1] = (m_pid >> 16) & 0xff;
+  buffer[2] = (m_pid >> 8) & 0xff;
+  buffer[3] = (m_pid >> 0) & 0xff;
+  buffer[4] = (m_groups >> 24) & 0xff;
+  buffer[5] = (m_groups >> 16) & 0xff;
+  buffer[6] = (m_groups >> 8) & 0xff;
+  buffer[7] = (m_groups >> 0) & 0xff;
+
+  return Address (GetType (), buffer, 8);
+}
+
+NetlinkSocketAddress NetlinkSocketAddress::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (IsMatchingType (address));
+
+  NetlinkSocketAddress nl;
+  uint8_t buf[8];
+
+  address.CopyTo (buf);
+
+  nl.m_pid = 0;
+  nl.m_pid |= buf[0];
+  nl.m_pid <<= 8;
+  nl.m_pid |= buf[1];
+  nl.m_pid <<= 8;
+  nl.m_pid |= buf[2];
+  nl.m_pid <<= 8;
+  nl.m_pid |= buf[3];
+
+  nl.m_groups = 0;
+  nl.m_groups |= buf[4];
+  nl.m_groups <<= 8;
+  nl.m_groups |= buf[5];
+  nl.m_groups <<= 8;
+  nl.m_groups |= buf[6];
+  nl.m_groups <<= 8;
+  nl.m_groups |= buf[7];
+
+  return nl;
+}
+
+bool NetlinkSocketAddress::IsMatchingType (const Address &address)
+{
+  return address.IsMatchingType (GetType ());
+}
+
+uint8_t NetlinkSocketAddress::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-socket-address.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,71 @@
+/* -*-	Mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#ifndef NETLINK_SOCKET_ADDRESS_H
+#define NETLINK_SOCKET_ADDRESS_H
+
+#include "ns3/ptr.h"
+#include "ns3/address.h"
+
+namespace ns3 {
+
+class NetlinkSocketAddress
+{
+public:
+  NetlinkSocketAddress (uint32_t pid, uint32_t groups);
+  NetlinkSocketAddress ();
+  ~NetlinkSocketAddress ();
+
+  void SetProcessID (uint32_t pid);
+  void SetGroupsMask (uint32_t mask);
+
+  uint32_t GetProcessID (void) const;
+  uint32_t GetGroupsMask (void) const;
+
+  /**
+  * \returns an Address instance which represents this
+  * NetlinkSocketAddress instance.
+  */
+  operator Address (void) const;
+  /**
+  * \param address the Address instance to convert from.
+  *
+  * Returns an NetlinkSocketAddress which corresponds to the input
+  * Address
+  */
+  static NetlinkSocketAddress ConvertFrom (const Address &address);
+  /**
+  * \returns true if the address matches, false otherwise.
+  */
+  static bool IsMatchingType (const Address &address);
+private:
+  static uint8_t GetType (void);
+  Address ConvertTo (void) const;
+
+  uint32_t m_pid;
+  uint32_t m_groups;
+
+};
+
+
+} // namespace ns3
+
+#endif /* NETLINK_SOCKET_ADDRESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-socket-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#include "netlink-socket-factory.h"
+#include "netlink-socket.h"
+#include "ns3/node.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (NetlinkSocketFactory);
+
+TypeId 
+NetlinkSocketFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::NetlinkSocketFactory")
+    .SetParent<SocketFactory> ();
+  return tid;
+}
+
+NetlinkSocketFactory::NetlinkSocketFactory ()
+{}
+
+Ptr<Socket> NetlinkSocketFactory::CreateSocket (void)
+{
+  Ptr<Node> node = GetObject<Node> ();
+  Ptr<NetlinkSocket> socket = CreateObject<NetlinkSocket> ();
+  socket->SetNode (node);
+  return socket;
+} 
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-socket-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,52 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#ifndef NETLINK_SOCKET_FACTORY_H
+#define NETLINK_SOCKET_FACTORY_H
+
+#include "ns3/socket-factory.h"
+
+namespace ns3 {
+
+class Socket;
+
+/**
+ * This can be used as an interface in a node in order for the node to
+ * generate NetlinkSockets.
+ */
+class NetlinkSocketFactory : public SocketFactory
+{
+public:
+  static TypeId GetTypeId (void);
+
+  NetlinkSocketFactory ();
+
+  /**
+   * Creates a NetlinkSocket and returns a pointer to it.
+   *
+   * \return a pointer to the created socket
+   */
+  virtual Ptr<Socket> CreateSocket (void);
+};
+
+} // namespace ns3
+
+#endif /* NETLINK_SOCKET_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-socket-test.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,589 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#include "ns3/test.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
+#include "ns3/node-container.h"
+#include "ns3/internet-stack-helper.h"
+#include "ns3/point-to-point-helper.h"
+#include "ns3/ipv4-address-helper.h"
+#include "ns3/ipv4-global-routing-helper.h"
+#include "ns3/socket-factory.h"
+#include "ns3/string.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/socket.h"
+#include "netlink-socket-factory.h"
+#include "netlink-message.h"
+#include "netlink-socket-address.h"
+#include <sys/socket.h>
+#include <string>
+#include <list>
+
+
+NS_LOG_COMPONENT_DEFINE ("NetlinkSocketTest");
+
+namespace ns3 {
+
+
+class NetlinkSocketTestCase: public TestCase
+{
+public:
+  NetlinkSocketTestCase ();
+  virtual bool DoRun (void);
+private:
+  NetlinkMessage BuildGetMessage (uint16_t type, uint16_t flags);
+  NetlinkMessage BuildAddressMessage (uint16_t type, uint16_t flags);
+  NetlinkMessage BuildLinkChangeMessage (uint16_t type, uint16_t flags);
+  NetlinkMessage BuildRouteMessage (uint16_t type, uint16_t flags);
+  MultipartNetlinkMessage BuildMultipartMessage (uint16_t type, uint16_t flags);
+
+  bool CheckIsAck (NetlinkMessage nlmsg);
+  bool CheckIsDump (MultipartNetlinkMessage nlmsg);
+  bool CheckIsEqual (NetlinkMessageHeader nhr1, NetlinkMessageHeader nhr2);
+  bool CheckIsEqual (NetlinkMessage nlmsg1, NetlinkMessage nlmsg2);
+  bool CheckIsEqual (MultipartNetlinkMessage mulmsg1, MultipartNetlinkMessage mulmsg2);
+
+  bool TestNetlinkSerilization ();
+  bool TestInterfaceAddressMessage ();
+  bool TestInferfaceInfoMessage ();
+  bool TestRouteMessage ();
+  bool TestBroadcastMessage ();
+
+  void ReceiveUnicastPacket (Ptr<Socket> socket);
+  void ReceiveMulticastPacket (Ptr<Socket> socket);
+  void SendCmdToKernel (uint16_t type);
+  void SendNetlinkMessage (NetlinkMessage nlmsg);
+  void MonitorKernelChanges ();
+
+  std::list<MultipartNetlinkMessage> m_unicastList;
+  std::list<MultipartNetlinkMessage> m_multicastList;
+  Ptr<Socket> m_cmdSock;
+  Ptr<Socket> m_groupSock;  
+  int m_pid;
+};
+
+
+
+NetlinkMessage
+NetlinkSocketTestCase::BuildGetMessage (uint16_t type, uint16_t flags)
+{
+  NS_ASSERT (type == NETLINK_RTM_GETLINK || type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETROUTE);
+
+  NetlinkMessage nlmsg;
+  flags |= (NETLINK_MSG_F_DUMP|NETLINK_MSG_F_ACK|NETLINK_MSG_F_REQUEST);
+  nlmsg.SetHeader (NetlinkMessageHeader (type, flags, 0, 0));
+  GeneralMessage genmsg;
+  genmsg.SetFamily (AF_INET);
+  nlmsg.SetGeneralMessage (genmsg);
+  //no attributes appended
+  return nlmsg;
+}
+
+NetlinkMessage
+NetlinkSocketTestCase::BuildAddressMessage (uint16_t type, uint16_t flags)
+{
+  NS_ASSERT (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR);
+
+  flags |= (NETLINK_MSG_F_ACK|NETLINK_MSG_F_REQUEST); 
+  if (type == NETLINK_RTM_NEWADDR)
+    {
+      flags |= NETLINK_MSG_F_CREATE;
+    }
+
+  NetlinkMessage nlmsg;
+  //set header
+  nlmsg.SetHeader (NetlinkMessageHeader (type, flags, 0, 0));
+
+  //set service module
+  InterfaceAddressMessage ifamsg;
+  ifamsg.SetFamily (AF_INET);
+  ifamsg.SetLength (24);
+  ifamsg.SetInterfaceIndex (3);
+
+  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL, ADDRESS, Ipv4Address("192.168.0.1")));
+  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS,ADDRESS, Ipv4Address("192.168.0.2")));
+  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LABEL, STRING, "TESTSTRING"));
+
+  nlmsg.SetInterfaceAddressMessage (ifamsg);
+  return nlmsg;
+}
+
+NetlinkMessage
+NetlinkSocketTestCase::BuildLinkChangeMessage (uint16_t type, uint16_t flags)
+{
+  NetlinkMessage nlmsg;
+  NS_LOG_WARN (this << type << flags << " not supported");
+  return nlmsg;
+}
+
+NetlinkMessage
+NetlinkSocketTestCase::BuildRouteMessage (uint16_t type, uint16_t flags)
+{
+  NS_ASSERT (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE);
+
+  flags |= (NETLINK_MSG_F_ACK|NETLINK_MSG_F_REQUEST); 
+  if (type == NETLINK_RTM_NEWROUTE)
+    {
+      flags |= NETLINK_MSG_F_CREATE;
+    }
+
+  NetlinkMessage nlmsg;
+  //set header
+  nlmsg.SetHeader (NetlinkMessageHeader (type, flags, 0, m_pid));
+
+  //set service module
+  RouteMessage rtmsg;
+  //set attribute
+  rtmsg.SetFamily (AF_INET);
+  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, Ipv4Address ("192.168.0.10")));
+  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, Ipv4Address ("192.168.2.10")));
+  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, Ipv4Address ("10.1.1.10")));
+  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, (uint32_t)2));
+
+  nlmsg.SetRouteMessage(rtmsg);
+  return nlmsg;
+}
+
+MultipartNetlinkMessage
+NetlinkSocketTestCase::BuildMultipartMessage (uint16_t type, uint16_t flags)
+{
+  //usually multi-part message used for message dump, kernel return to user space for NETLINK_RTM_GETxxx
+  //type = NETLINK_RTM_NEWxxx, flags = NETLINK_MSG_F_MULTI, terminated by NETLINK_MSG_DONE, 
+  //here this example contain 2 NETLINK_MSG_F_MULTI
+  NS_ASSERT (flags&NETLINK_MSG_F_MULTI);
+
+  MultipartNetlinkMessage nlmsg;
+  NetlinkMessage nlmsg1, nlmsg2, nlmsg3;
+  nlmsg1 = BuildAddressMessage (NETLINK_RTM_NEWADDR, NETLINK_MSG_F_MULTI);
+  nlmsg.AppendMessage (nlmsg1);
+  //the first nlmsg
+  nlmsg2 = BuildRouteMessage (NETLINK_RTM_NEWROUTE, NETLINK_MSG_F_MULTI);
+  nlmsg.AppendMessage (nlmsg2);
+  //the second nlmsg
+  nlmsg3.SetHeader (NetlinkMessageHeader (NETLINK_MSG_DONE, flags, 1, m_pid));
+  nlmsg.AppendMessage (nlmsg3);
+
+  return nlmsg;
+}
+
+
+
+
+bool
+NetlinkSocketTestCase::CheckIsAck (NetlinkMessage nlmsg)
+{
+  return (nlmsg.GetMsgType () == NETLINK_MSG_ERROR && nlmsg.GetErrorMessage ().GetError () == 0);
+}
+
+bool
+NetlinkSocketTestCase::CheckIsDump (MultipartNetlinkMessage mulmsg)
+{
+  return (mulmsg.GetNMessages () > 0 && mulmsg.GetMessage (0).GetHeader ().GetMsgFlags () & NETLINK_MSG_F_MULTI &&
+          mulmsg.GetMessage (mulmsg.GetNMessages () - 1).GetMsgType () == NETLINK_MSG_DONE); 
+}
+
+bool
+NetlinkSocketTestCase::CheckIsEqual (NetlinkMessageHeader nhr1, NetlinkMessageHeader nhr2)
+{
+  return (nhr1.GetMsgType () == nhr2.GetMsgType () && nhr1.GetMsgFlags () == nhr2.GetMsgFlags ()
+          && nhr1.GetMsgLen () == nhr2.GetMsgLen ());
+}
+
+bool
+NetlinkSocketTestCase::CheckIsEqual (NetlinkMessage nlmsg1, NetlinkMessage nlmsg2)
+{
+  return CheckIsEqual (nlmsg1.GetHeader (), nlmsg2.GetHeader ());
+}
+
+bool
+NetlinkSocketTestCase::CheckIsEqual (MultipartNetlinkMessage mulmsg1, MultipartNetlinkMessage mulmsg2)
+{
+  if (mulmsg1.GetNMessages () != mulmsg2.GetNMessages ())
+    return false;
+
+  for (uint32_t i = 0; i < mulmsg1.GetNMessages(); i ++)
+    {
+      if (!CheckIsEqual (mulmsg1.GetMessage (i), mulmsg2.GetMessage (i)))
+        {
+          return false;
+        }
+    }
+  return true;  
+}
+
+bool
+NetlinkSocketTestCase::TestNetlinkSerilization ()
+{
+  MultipartNetlinkMessage multinlmsg1, multinlmsg2;
+  Ptr<Packet> p = Create<Packet> ();
+  bool result = true;
+
+  multinlmsg1 = BuildMultipartMessage (NETLINK_RTM_NEWADDR, NETLINK_MSG_F_REQUEST|NETLINK_MSG_F_MULTI);
+  p->AddHeader (multinlmsg1);
+  p->RemoveHeader (multinlmsg2);
+  NS_TEST_ASSERT_MSG_EQ (CheckIsEqual (multinlmsg1, multinlmsg2), true, "Should be equal");
+
+  return result;
+}
+bool
+NetlinkSocketTestCase::TestInterfaceAddressMessage ()
+{
+  MultipartNetlinkMessage dump1, dump2, dump3;
+  NetlinkMessage nlmsg1,nlmsg2;
+  bool result = true;
+
+  //dump interface address
+  SendNetlinkMessage (BuildGetMessage (NETLINK_RTM_GETADDR, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue should be 1 (RTM_GETADDR)");
+  dump1 = m_unicastList.front ();
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsDump (dump1), true, "Should be dump msg");
+
+  //add interface address
+  // Not implemented yet (100325)
+#if 0
+  SendNetlinkMessage (BuildAddressMessage (NETLINK_RTM_NEWADDR,0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue should be 1 (RTM_NEWADDR)");
+  nlmsg1 = m_unicastList.front ().GetMessage (0);
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsAck (nlmsg1), true, "msg should be Ack");
+#endif
+
+  //dump interface address
+  SendNetlinkMessage (BuildGetMessage (NETLINK_RTM_GETADDR, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue should be 1 (RTM_GETADDR)");
+  dump2 = m_unicastList.front ();
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsDump (dump2), true, "msg should be dump");
+
+  //del interface address
+  // Not implemented yet (100325)
+#if 0
+  SendNetlinkMessage (BuildAddressMessage (NETLINK_RTM_DELADDR,0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_DELADDR)");
+  nlmsg2 = m_unicastList.front ().GetMessage (0);
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsAck (nlmsg2), true, "msg should be Ack");
+#endif
+
+  //dump interface address
+  SendNetlinkMessage (BuildGetMessage (NETLINK_RTM_GETADDR, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_GETADDR)");
+  dump3 = m_unicastList.front ();
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsDump (dump3), true, "msg should be dump");
+
+  NS_TEST_ASSERT_MSG_EQ (CheckIsEqual (dump1, dump3), true, "Dump msg should be same");
+
+  return result;
+}
+
+
+bool
+NetlinkSocketTestCase::TestRouteMessage ()
+{
+  MultipartNetlinkMessage dump1, dump2, dump3;
+  NetlinkMessage nlmsg1,nlmsg2;
+  bool result = true;
+
+  //dump route entry
+  SendNetlinkMessage (BuildGetMessage (NETLINK_RTM_GETROUTE, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_GETROUTE)");
+  dump1 = m_unicastList.front ();
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsDump (dump1), true, "msg should be dump");
+
+  //add route entry
+  SendNetlinkMessage (BuildRouteMessage (NETLINK_RTM_NEWROUTE,0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_NEWROUTE)");
+  nlmsg1 = m_unicastList.front ().GetMessage (0);
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsAck (nlmsg1), true, "msg should be Ack");
+
+  //dump route entry
+  SendNetlinkMessage (BuildGetMessage (NETLINK_RTM_GETROUTE, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_GETROUTE)");
+  dump2 = m_unicastList.front ();
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsDump (dump2), true, "msg should be dump");
+
+  //del route entry
+  SendNetlinkMessage (BuildRouteMessage (NETLINK_RTM_DELROUTE, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_DELROUTE)");
+  nlmsg2 = m_unicastList.front ().GetMessage (0);
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsAck (nlmsg2), true, "msg should be Ack");
+
+  //dump route entry
+  SendNetlinkMessage (BuildGetMessage (NETLINK_RTM_GETROUTE, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_GETROUTE)");
+  dump3 = m_unicastList.front ();
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsDump (dump3), true, "msg should be dump");
+
+  NS_TEST_ASSERT_MSG_EQ (CheckIsEqual (dump1, dump3), true, "msg should be same");
+
+  return result;
+}
+
+bool
+NetlinkSocketTestCase::TestInferfaceInfoMessage ()
+{
+  //now netlink not support NEWLINK/DELLINK yet
+  MultipartNetlinkMessage multinlmsg;
+  bool result = true;
+
+  //dump interface address
+  SendNetlinkMessage (BuildGetMessage (NETLINK_RTM_GETLINK, 0));
+  NS_TEST_ASSERT_MSG_EQ (m_unicastList.size (), 1, "queue size should be 1 (RTM_GETLINK)");
+  multinlmsg = m_unicastList.front ();
+  m_unicastList.pop_front ();
+  NS_TEST_ASSERT_MSG_EQ (CheckIsDump (multinlmsg), true, "msg should be dump");
+
+  NS_TEST_ASSERT_MSG_EQ ((multinlmsg.GetNMessages () > 1) && (multinlmsg.GetMessage (0).GetMsgType () == NETLINK_RTM_NEWLINK),
+                        true, "msg might be incorrect");
+
+  return result;
+}
+
+bool
+NetlinkSocketTestCase::TestBroadcastMessage ()
+{
+  bool result = true;
+  //at 2Xs, m_cmdSock send an request to kernel to add/del an interface address
+  //and an route entry,  the m_groupSock will recv the changed information
+  //through the broadcast way  
+  m_multicastList.clear();
+  Simulator::Schedule (Seconds (1), &NetlinkSocketTestCase::MonitorKernelChanges, this);
+  // Not implemented yet (100325)
+#if 0
+  Simulator::Schedule (Seconds (2), &NetlinkSocketTestCase::SendCmdToKernel, this, NETLINK_RTM_NEWADDR);
+#endif
+  Simulator::Schedule (Seconds (4), &NetlinkSocketTestCase::SendCmdToKernel, this, NETLINK_RTM_NEWROUTE);
+  // Not implemented yet (100325)
+#if 0
+  Simulator::Schedule (Seconds (6), &NetlinkSocketTestCase::SendCmdToKernel, this, NETLINK_RTM_DELADDR);
+#endif
+  Simulator::Schedule (Seconds (8), &NetlinkSocketTestCase::SendCmdToKernel, this, NETLINK_RTM_DELROUTE);
+
+  return result;
+};
+
+
+void
+NetlinkSocketTestCase::SendNetlinkMessage (NetlinkMessage nlmsg)
+{
+#if 1
+  Ptr<Packet> p = Create<Packet> ();
+  p->AddHeader (MultipartNetlinkMessage (nlmsg));
+#else
+  char buf[20] = {0x14,0x00,0x00,0x00,0x12,0x00,0x05,0x03,
+                  0x34,0xb2,0xf5,0x47,0x01,0x00,0x00,0x00,
+                  0x00,0x00,0x00,0x00};
+  uint32_t count = 20;
+  Ptr<Packet> p = ns3::Create<Packet> ((const uint8_t *)buf, (uint32_t)count);
+#endif
+  
+  m_cmdSock->Send (p);
+}
+void
+NetlinkSocketTestCase::SendCmdToKernel (uint16_t type)
+{
+  NS_LOG_INFO ("At = " <<  Simulator::Now ().GetSeconds () <<"s, user send cmd to kernel, cmd = " << type);
+
+  if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
+    {
+      SendNetlinkMessage (BuildAddressMessage (type, 0));
+    }
+  else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE)
+    {
+      SendNetlinkMessage (BuildRouteMessage (type, 0));
+    }
+  else
+    {
+      NS_LOG_ERROR ("netlink cmd not support , type = " << type);
+    }  
+}
+
+
+void
+NetlinkSocketTestCase::ReceiveUnicastPacket (Ptr<Socket> socket)
+{
+  Ptr<Packet> packet;
+  while (packet = socket->Recv ())
+    {
+      MultipartNetlinkMessage nlmsg;
+      packet->RemoveHeader (nlmsg);
+      m_unicastList.push_back (nlmsg);
+    }
+}
+
+void
+NetlinkSocketTestCase::ReceiveMulticastPacket (Ptr<Socket> socket)
+{
+  Ptr<Packet> packet;
+  while (packet = socket->Recv ())
+    {
+      MultipartNetlinkMessage nlmsg;
+      packet->RemoveHeader (nlmsg);
+      m_multicastList.push_back (nlmsg);
+    }
+}
+void
+NetlinkSocketTestCase::MonitorKernelChanges ()
+{
+  NS_LOG_INFO ("At = " << Simulator::Now ().GetSeconds () << "s, group socket check the recv list");
+
+  if (m_multicastList.size ())
+    {
+      MultipartNetlinkMessage multinlmsg = m_multicastList.front ();
+
+      if (multinlmsg.GetNMessages () == 1)
+        {
+          NetlinkMessage nlmsg = multinlmsg.GetMessage (0);
+          uint16_t type;
+          type = nlmsg.GetMsgType ();
+          NS_ASSERT (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR ||
+                     type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE);
+          NS_LOG_INFO ("group socket recv netlink message, type =" << type);          
+        }
+      else
+        {
+          NS_LOG_WARN ("group socket recv an unwanted message");
+        }
+      m_multicastList.pop_front ();
+    }
+
+  //restart this timer
+  if (Simulator::Now ().GetSeconds () < 10)
+    {
+      Simulator::Schedule (Seconds (1), &NetlinkSocketTestCase::MonitorKernelChanges, this);
+    }
+}
+
+
+
+NetlinkSocketTestCase::NetlinkSocketTestCase ()
+  : TestCase ("Netlink"),
+    m_pid(1) {}
+
+bool
+NetlinkSocketTestCase::DoRun (void)
+{
+  bool result = false;
+
+  //init nodes with stacks and device
+  // Network topology
+  //
+  //   n0
+  //     \ 5 Mb/s, 2ms
+  //      \          1.5Mb/s, 10ms
+  //       n1 -------------------------n2
+
+
+  NodeContainer nodes; 
+  nodes.Create (3);
+  NodeContainer n0n1 = NodeContainer (nodes.Get (0), nodes.Get (1));
+  NodeContainer n1n2 = NodeContainer (nodes.Get (1), nodes.Get (2));
+
+  InternetStackHelper stack;
+  stack.Install (nodes);
+
+  //add a p2p device with an ip address  
+  PointToPointHelper p2p;  
+  p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));  
+  p2p.SetChannelAttribute ("Delay", StringValue ("2ms"));  
+  NetDeviceContainer d0d1 = p2p.Install (n0n1);
+  p2p.SetDeviceAttribute ("DataRate", StringValue ("1.5Mbps"));
+  p2p.SetChannelAttribute ("Delay", StringValue ("10ms"));
+  NetDeviceContainer d1d2 = p2p.Install (n1n2);
+
+  Ipv4AddressHelper ipv4;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer i01 = ipv4.Assign (d0d1);
+  ipv4.SetBase ("10.1.2.0", "255.255.255.0");
+  Ipv4InterfaceContainer i12 = ipv4.Assign (d1d2);
+
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+
+  /*create two netlink sockets in node1 
+  one is to exchange information between userspace and kernel ,
+  one is to monitor the changes happened in kernel
+  */
+  Ptr<Node> node0 = nodes.Get (1);
+  Ptr<NetlinkSocketFactory> factory = CreateObject<NetlinkSocketFactory> ();
+  node0->AggregateObject (factory);
+  TypeId tid = TypeId::LookupByName ("ns3::NetlinkSocketFactory");
+  Ptr<SocketFactory> socketFactory = node0->GetObject<SocketFactory> (tid);
+  NetlinkSocketAddress addr;
+
+  /*creat an cmd netlink socket, it send cmd to kernel space*/
+  m_cmdSock = socketFactory->CreateSocket ();
+  m_cmdSock->SetRecvCallback (MakeCallback (&NetlinkSocketTestCase::ReceiveUnicastPacket, this)); 
+  addr.SetProcessID (m_pid);
+  addr.SetGroupsMask (0);
+  m_cmdSock->Bind (addr); 
+
+  /*creat an group netlink socket, it monitor the kernel's changes*/
+  m_groupSock = socketFactory->CreateSocket ();
+  m_groupSock->SetRecvCallback (MakeCallback (&NetlinkSocketTestCase::ReceiveMulticastPacket, this)); 
+  addr.SetProcessID (m_pid + 1);
+  addr.SetGroupsMask (NETLINK_RTM_GRP_IPV4_IFADDR|NETLINK_RTM_GRP_IPV4_ROUTE);
+  m_groupSock->Bind (addr); 
+
+  /*test 1: for Serialize and Deserialize*/
+  NS_TEST_ASSERT_MSG_EQ (TestNetlinkSerilization (), true, "test1");
+
+  /*test 2: for interface address dump/add/get message*/
+  NS_TEST_ASSERT_MSG_EQ (TestInterfaceAddressMessage (), true, "test2");
+
+  /*test 3: for interface info dump message*/
+  NS_TEST_ASSERT_MSG_EQ (TestInferfaceInfoMessage (), true, "test3");
+
+  /*test 4: for route dump/add/get message*/
+  NS_TEST_ASSERT_MSG_EQ (TestRouteMessage (), true, "test4");
+
+  /*test 5: for netlink broadcast */
+  NS_TEST_ASSERT_MSG_EQ (TestBroadcastMessage (), true, "test5");
+
+  Simulator::Run ();
+
+  return result;
+}
+
+static class NetlinkSocketTestSuite : public TestSuite
+{
+public:
+  NetlinkSocketTestSuite ();
+private:
+} g_netlinkTestSuite;
+
+NetlinkSocketTestSuite::NetlinkSocketTestSuite ()
+  : TestSuite ("netlink-socket", UNIT)
+{
+  AddTestCase (new NetlinkSocketTestCase ());
+}
+
+} // namespace ns3
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-socket.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,1566 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+
+#include "netlink-socket.h"
+#include "netlink-socket-address.h"
+#include "netlink-message.h"
+#include "netlink-message-route.h"
+#include "ns3/log.h"
+#include "ns3/node.h"
+#include "ns3/packet.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/simple-net-device.h"
+#include "ns3/uinteger.h"
+#include "ns3/trace-source-accessor.h"
+#include <iostream>
+#include <sstream>
+#include "ns3/ipv6-address.h"
+#include "ns3/ipv6.h"
+#include "ns3/ipv4-l3-protocol.h"
+#include "ns3/ipv4-static-routing-helper.h"
+#include "ns3/ipv4-routing-table-entry.h"
+#include "ns3/ipv6-l3-protocol.h"
+#include "ns3/ipv6-interface.h"
+#include "ns3/ipv6-static-routing-helper.h"
+#include "ns3/ipv6-routing-table-entry.h"
+#include "ns3/socket.h"
+#include "ns3/mac48-address.h"
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <errno.h>
+
+NS_LOG_COMPONENT_DEFINE ("NetlinkSocket");
+
+namespace ns3 {
+
+// GroupSockets store the netlinksocket with noero group value
+// it was due to the mulitcast netlink messages.
+class GroupSockets
+{
+public:
+  static uint32_t GetNSockets(void)
+  { 
+    return m_Sockets.size();
+  }
+  static Ptr<NetlinkSocket> GetSocket(uint32_t index)
+  {
+    NS_ASSERT(index < m_Sockets.size());
+    return m_Sockets[index];
+  }
+  static void AddSocket(Ptr<NetlinkSocket>sock)
+  {
+    m_Sockets.push_back(sock);
+  }
+private:
+   /*use a std::vector to store the sockets with nozero group value*/
+  static std::vector<Ptr<NetlinkSocket> >m_Sockets;
+};
+std::vector<Ptr<NetlinkSocket> >GroupSockets::m_Sockets;
+
+NS_OBJECT_ENSURE_REGISTERED (NetlinkSocket);
+
+/*
+Netlink Socket
+*/
+TypeId
+NetlinkSocket::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::NetlinkSocket")
+    .SetParent<Socket> ()
+    .AddConstructor<NetlinkSocket> ()
+    .AddTraceSource ("Drop", "Drop packet due to receive buffer overflow",
+                     MakeTraceSourceAccessor (&NetlinkSocket::m_dropTrace))
+    .AddAttribute ("RcvBufSize",
+                   "NetlinkSocket maximum receive buffer size (bytes)",
+                   UintegerValue (0xffffffffl),
+                   MakeUintegerAccessor (&NetlinkSocket::m_rcvBufSize),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("IcmpCallback", "Callback invoked whenever an icmp error is received on this socket.",
+                   CallbackValue (),
+                   MakeCallbackAccessor (&NetlinkSocket::m_icmpCallback),
+                   MakeCallbackChecker ())
+    ;
+  return tid;
+}
+
+NetlinkSocket::NetlinkSocket ()
+  : m_shutdownSend (false),
+    m_shutdownRecv (false),
+    m_rxAvailable (0),
+    m_srcPid (0),
+    m_srcGroups (0),
+    m_dstPid (0),
+    m_dstGroups (0)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_errno = ERROR_NOTERROR;
+}
+NetlinkSocket::~NetlinkSocket ()
+{
+  NS_LOG_FUNCTION (this);
+}
+void 
+NetlinkSocket::DoDispose (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+}
+
+int
+NetlinkSocket::ErrnoToSimuErrno (void)
+{
+  switch (m_errno)
+    {
+    case Socket::ERROR_ISCONN:
+      return EISCONN;
+    case Socket::ERROR_NOTCONN:
+      return ENOTCONN;
+    case Socket::ERROR_MSGSIZE:
+      return EMSGSIZE;
+    case Socket::ERROR_AGAIN:
+      return EAGAIN;
+    case Socket::ERROR_SHUTDOWN:
+      return ESHUTDOWN;
+    case Socket::ERROR_OPNOTSUPP:
+      return EOPNOTSUPP;
+    case Socket::ERROR_AFNOSUPPORT:
+      return EAFNOSUPPORT;
+    case Socket::ERROR_INVAL:
+      return EINVAL;
+    case Socket::ERROR_BADF:
+      return EBADF;
+    case Socket::ERROR_NOROUTETOHOST:
+      return EHOSTUNREACH;
+    case Socket::ERROR_NODEV:
+      return ENODEV;
+    case Socket::ERROR_ADDRNOTAVAIL:
+      return EADDRNOTAVAIL;
+    case Socket::SOCKET_ERRNO_LAST:
+    case Socket::ERROR_NOTERROR:
+    default:
+      NS_ASSERT (false);
+      return 0; // quiet compiler
+      break;
+    }
+}
+
+void 
+NetlinkSocket::SetNode (Ptr<Node> node)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_node = node;
+}
+
+
+enum Socket::SocketErrno
+NetlinkSocket::GetErrno (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_errno;
+}
+
+Ptr<Node>
+NetlinkSocket::GetNode (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_node;
+}
+
+uint32_t
+NetlinkSocket::GetSrcPid (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_srcPid;
+}
+uint32_t
+NetlinkSocket::GetSrcGroups (void)const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_srcGroups;
+}
+uint32_t
+NetlinkSocket::GetDstPid (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_dstPid;
+}
+uint32_t
+NetlinkSocket::GetDstGroups (void)const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_dstGroups;
+}
+
+int
+NetlinkSocket::Bind (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NetlinkSocketAddress address;
+  return DoBind (address);
+}
+int
+NetlinkSocket::Bind (const Address &address)
+{ 
+  NS_LOG_FUNCTION (this << address);
+
+  if (!NetlinkSocketAddress::IsMatchingType (address))
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  NetlinkSocketAddress ad = NetlinkSocketAddress::ConvertFrom (address);
+  return DoBind (ad);
+}
+int
+NetlinkSocket::DoBind (const NetlinkSocketAddress &address)
+{
+  NS_LOG_FUNCTION (this << address);
+
+  m_srcPid = address.GetProcessID ();
+  m_srcGroups = address.GetGroupsMask ();
+
+  if (m_srcGroups)
+    {
+      GroupSockets::AddSocket(this);
+    } 
+  return 0;
+}
+
+int 
+NetlinkSocket::Listen (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_errno = Socket::ERROR_OPNOTSUPP;
+  return -1;
+}
+
+uint32_t
+NetlinkSocket::GetTxAvailable (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return 0;
+}
+uint32_t
+NetlinkSocket::GetRxAvailable (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  // We separately maintain this state to avoid walking the queue 
+  // every time this might be called
+  return m_rxAvailable;
+}
+
+int
+NetlinkSocket::ShutdownSend (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_shutdownSend = true;
+  return 0;
+}
+int
+NetlinkSocket::ShutdownRecv (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_shutdownRecv = true;
+  return 0;
+}
+
+int
+NetlinkSocket::Close (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  ShutdownSend();
+  ShutdownRecv();
+  return 0;
+}
+
+int
+NetlinkSocket::Connect (const Address &address)
+{
+  NS_LOG_FUNCTION (this << address);
+  m_errno = Socket::ERROR_OPNOTSUPP;
+  return 0;
+}
+
+Ptr<Packet>
+NetlinkSocket::Recv (uint32_t maxSize, uint32_t flags)
+{
+  NS_LOG_FUNCTION (this << maxSize<< flags);
+  if (m_dataReceiveQueue.empty())
+    {
+      return 0;
+    }
+
+  Ptr<Packet> p = m_dataReceiveQueue.front ();
+  if (p->GetSize () <= maxSize) 
+    {
+      m_dataReceiveQueue.pop ();
+      m_rxAvailable -= p->GetSize ();
+    }
+  else
+    {
+      p = 0; 
+    }
+  return p;
+}
+
+Ptr<Packet>
+NetlinkSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress)
+{
+  NS_LOG_FUNCTION (this << maxSize << flags << fromAddress);
+  Ptr<Packet> packet = Recv (maxSize, flags);
+  if (packet != 0)
+    {
+      SocketAddressTag tag;
+      bool found;
+      found = packet->FindFirstMatchingByteTag (tag);
+      NS_ASSERT (found);
+      fromAddress = tag.GetAddress ();
+    }
+  return packet;
+}
+
+int
+NetlinkSocket::Send (Ptr<Packet> p,uint32_t flags)
+{
+  NS_LOG_FUNCTION (this << p << flags);
+  NetlinkSocketAddress address = NetlinkSocketAddress(m_dstPid, m_dstGroups);
+  return SendTo(p, flags, address);
+}
+
+int
+NetlinkSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &toAddress)
+{
+  NS_LOG_FUNCTION (this << p << flags << toAddress);
+  NetlinkSocketAddress ad;
+
+  if (!NetlinkSocketAddress::IsMatchingType (toAddress))
+    {
+      NS_LOG_LOGIC ("ERROR_AFNOSUPPORT");
+      m_errno = ERROR_AFNOSUPPORT;
+      return -1;
+    }
+  ad = NetlinkSocketAddress::ConvertFrom (toAddress);
+  m_dstPid = ad.GetProcessID();
+  m_dstGroups = ad.GetGroupsMask();
+  NS_LOG_INFO ("send netlink message to pid = " << m_dstPid << ", groups = " << m_dstGroups);
+  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Sending netlink message from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ());
+
+  //Ptr<NetlinkSocket>kernel_socket = GetNetlinkSocketByAddress(ad);
+  //kernel_socket->m_receivedData.push_back(p);
+  //kernel_socket->NotifyDataReceived(p);
+
+  //when netlink socket send packet, the first step is to find the dest netlink socket through address
+  //then send the packet to it. For we partly implement the netlink-family, the dest address
+  //is always the kernel(pid = 0), (Actually, there must be one static kernel netlink socket to
+  //receive/handle messages), we do not setup a kernel socket to receive packet.
+  //
+  
+  MultipartNetlinkMessage multipartnlmsg;
+  uint32_t packet_len, remain_len;
+
+  packet_len = p->GetSize ();
+  remain_len = packet_len;
+
+  while (remain_len > NetlinkMessageHeader::GetHeaderSize ())
+    {
+      remain_len -= p->RemoveHeader (multipartnlmsg);
+      NS_ASSERT (remain_len == p->GetSize ());
+
+      //actually, message to kernel contains single one netlink message
+      for (uint32_t i = 0; i < multipartnlmsg.GetNMessages(); i ++)
+        {
+          NetlinkMessage nlmsg = multipartnlmsg.GetMessage (i);
+          if (HandleMessage (nlmsg) < 0)
+            {
+              if (m_errno)
+                {
+                  SendAckMessage (nlmsg, -ErrnoToSimuErrno ());
+                }
+            }
+          else if (NetlinkMessage::IsMessageFlagsAck (nlmsg.GetHeader ().GetMsgFlags ()))
+            {
+              SendAckMessage (nlmsg, 0);
+            }
+        }
+    }
+
+  NotifyDataSent (packet_len);
+  NS_LOG_INFO ("netlink socket kernel error " << -m_errno);
+  return packet_len;
+}
+
+int
+NetlinkSocket::GetSockName (Address &address) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  NetlinkSocketAddress ad;
+
+  ad.SetProcessID (GetSrcPid ());
+  ad.SetGroupsMask (GetSrcGroups ());
+  address = ad;
+  return 0;
+}
+int
+NetlinkSocket::GetPeerName (Address &address) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  // XXX
+  NS_ASSERT (false);
+  return -1;
+}
+bool 
+NetlinkSocket::SetAllowBroadcast (bool allowBroadcast)
+{
+  NS_ASSERT (false);
+  return false;
+}
+bool 
+NetlinkSocket::GetAllowBroadcast () const
+{
+  NS_ASSERT (false);
+  return false;
+}
+
+
+void
+NetlinkSocket::ForwardUp (Ptr<Packet> packet, NetlinkSocketAddress &address)
+{
+  NS_LOG_FUNCTION (this << packet << address);
+
+  if (m_shutdownRecv)
+    {
+      return;
+    }
+  if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
+    {
+      SocketAddressTag tag;
+      tag.SetAddress (address);
+      packet->AddByteTag (tag);
+      m_dataReceiveQueue.push (packet);
+      m_rxAvailable += packet->GetSize ();
+      NotifyDataRecv ();
+    }
+  else
+    {
+      NS_LOG_WARN ("No receive buffer space available.  Drop.");
+      m_dropTrace (packet);
+    }
+}
+
+int32_t
+NetlinkSocket::SendMessageUnicast (const MultipartNetlinkMessage &nlmsg, uint32_t pid, int32_t nonblock)
+{
+  NS_LOG_FUNCTION (this << pid << nonblock);
+  //here we send message instantly
+  Ptr<Packet> p = Create<Packet> ();
+  p->AddHeader (nlmsg);
+
+  NetlinkSocketAddress address;
+  address.SetProcessID (pid);
+
+  //send packet to user space
+  ForwardUp (p, address);
+  return 0;
+}
+int32_t
+NetlinkSocket::SendMessageBroadcast (const MultipartNetlinkMessage &nlmsg, 
+                                     uint32_t pid, 
+                                     uint32_t group,
+                                     Ptr<Node> node)
+{
+  NS_LOG_FUNCTION ("SendMessageBroadcast" << pid << group);
+  //fisrt find the dest netlink socket through group value, then attach this nlmsg to its recv-queue
+  for (uint32_t i = 0; i < GroupSockets::GetNSockets (); i ++)
+    {
+      Ptr<NetlinkSocket> nlsock = GroupSockets::GetSocket (i);
+
+      if ((nlsock->GetSrcGroups () & group) &&
+          (nlsock->GetSrcPid () != pid) &&
+          node == nlsock->GetNode ())
+        {
+          //here we send message instantly
+          Ptr<Packet> p = Create<Packet> ();
+          p->AddHeader (nlmsg);
+
+          NetlinkSocketAddress address;
+          address.SetProcessID (nlsock->GetSrcPid());
+          address.SetGroupsMask (group);
+
+          //send packet to user space
+          nlsock->ForwardUp (p, address);
+        }
+    }
+  return 0;
+}
+void
+NetlinkSocket::SendAckMessage (const NetlinkMessage&nlmsg, int32_t err)
+{
+  NS_LOG_FUNCTION (this << err);
+  NetlinkMessageHeader rep;
+  NetlinkMessage ackmsg;
+  NetlinkMessageError errmsg;
+
+  rep.SetMsgPid (nlmsg.GetHeader ().GetMsgPid ());
+  rep.SetMsgSeq (nlmsg.GetHeader ().GetMsgSeq ());
+  rep.SetMsgType (NETLINK_MSG_ERROR);
+  rep.SetMsgFlags (0);
+
+  errmsg.SetError (err);
+  //kernel send the whole nlmsg back if error != 0, here we just send the header back
+  errmsg.SetMsg (nlmsg.GetHeader ());
+
+  //then send errmsg back to user space
+  ackmsg.SetHeader (rep);
+  ackmsg.SetErrorMessage (errmsg);
+
+  SendMessageUnicast (ackmsg, rep.GetMsgPid (), 1);
+}
+
+int32_t
+NetlinkSocket::HandleMessage (const NetlinkMessage&nlmsg)
+{
+  NS_LOG_FUNCTION (this);
+  uint16_t type = nlmsg.GetMsgType ();
+  NetlinkMessageHeader nhr = nlmsg.GetHeader ();
+
+  if (nhr.GetMsgLen () < NetlinkMessageHeader::GetHeaderSize ())
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+
+  if (NetlinkMessage::IsMessageNetlinkControl (type))
+    {
+      NS_LOG_INFO ("netlink control message type not parsed in kernel");
+      return 0;
+    }
+  else if (NetlinkMessage::IsMessageNetlinkRoute (type))
+    {
+      return HandleNetlinkRouteMessage (nlmsg);
+    }
+  else
+    {
+      NS_LOG_INFO ("netlink message type not parsed in kernel");
+      m_errno = ERROR_INVAL;
+      return -1;
+    }  
+}
+
+int32_t
+NetlinkSocket::HandleNetlinkRouteMessage (const NetlinkMessage &nlmsg)
+{
+  NS_LOG_FUNCTION (this);
+  uint8_t family;
+  int16_t type;
+  int32_t err;
+
+  /* Only requests are handled by kernel now */
+  if (!NetlinkMessage::IsMessageFlagsRequest (nlmsg.GetHeader ().GetMsgFlags ()))
+    return 0;
+
+  type = nlmsg.GetMsgType ();
+
+  /* A control message: ignore them */
+  if (NetlinkMessage::IsMessageNetlinkControl (type))
+    {
+      return 0;
+    }
+  else if (NetlinkMessage::IsMessageNetlinkRoute (type))
+    {
+      /* All the messages must have at least 1 byte length */
+      if (nlmsg.GetPayloadSize () < 1)
+        return 0;
+
+      family = nlmsg.GetFamily ();
+      /*here we do not deal with different family, default for AF_NET*/
+      NS_ASSERT(family == AF_INET || family == AF_UNSPEC || family == AF_PACKET || family == AF_INET6);  
+
+      /*for GET*** message, dump it to userspace*/
+      if (NetlinkMessage::IsMessageTypeGet (type) && 
+          NetlinkMessage::IsMessageFlagsDump (nlmsg.GetHeader ().GetMsgFlags ())) 
+        {
+          DumpNetlinkRouteMessage (nlmsg, type, family);
+          return -1;
+        }
+
+      /* other types of messages*/
+      return DoNetlinkRouteMessage (nlmsg, type, family);
+    }
+  else/* Unknown message: reply with EINVAL */
+    {
+      err = ERROR_INVAL;
+      return -1;
+    } 
+}
+
+int32_t
+NetlinkSocket::DumpNetlinkRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << type << family);
+
+  NS_ASSERT (type == NETLINK_RTM_GETADDR || type == NETLINK_RTM_GETROUTE || type == NETLINK_RTM_GETLINK);
+
+  MultipartNetlinkMessage nlmsg_dump;
+  NetlinkMessageHeader nhr = nlmsg.GetHeader ();
+  int32_t err;
+
+  if (type == NETLINK_RTM_GETADDR)
+    {
+      nlmsg_dump = BuildInterfaceAddressDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);
+    }
+  else if (type == NETLINK_RTM_GETLINK)
+    {
+      nlmsg_dump = BuildInterfaceInfoDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);      
+    }
+  else if (type == NETLINK_RTM_GETROUTE)
+    {
+      nlmsg_dump = BuildRouteDumpMessage (m_srcPid, nhr.GetMsgSeq(), family);
+    }
+  else
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+
+  //then append netlink message with type NLMSG_DONE
+  NetlinkMessage nlmsg_done;
+  NetlinkMessageHeader nhr2 = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 
+                                                   nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
+  nlmsg_done.SetHeader (nhr2);
+  //kernel append nlmsg_dump size to it, here we omit it
+  nlmsg_dump.AppendMessage (nlmsg_done);
+
+  err = SendMessageUnicast (nlmsg_dump, m_srcPid, 1);
+  return err;
+}
+
+/*here only for ADD/DEL/GET*** types*/
+int32_t
+NetlinkSocket::DoNetlinkRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << type <<family);
+  int32_t err;
+
+  if (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR)
+    {      
+      err = DoInterfaceAddressMessage (nlmsg, type, family);
+    }
+  else if (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE || type == NETLINK_RTM_GETROUTE)
+    {     
+      err = DoRouteMessage (nlmsg, type, family);
+    }
+  else if (type == NETLINK_RTM_GETLINK || type == NETLINK_RTM_SETLINK)
+    {     
+      err = DoInterfaceInfoMessage (nlmsg, type, family);
+    }
+  else
+    {
+      NS_LOG_LOGIC ("netlink message:type( " << type << ") not processed by ns3 now." );
+      m_errno = ERROR_INVAL;
+      err = -1;
+    } 
+  
+  return err;
+}
+
+MultipartNetlinkMessage
+NetlinkSocket::BuildInterfaceAddressDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << pid << seq <<family);
+  MultipartNetlinkMessage nlmsg_dump;
+  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
+
+  for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i ++)
+    {
+      if (!ipv4->IsUp (i))
+        continue;
+
+      Ipv4Address addri = ipv4->GetAddress (i, 0).GetLocal ();
+      Ipv4Mask maski = ipv4->GetAddress (i, 0).GetMask ();
+      Ipv4Address bcast = ipv4->GetAddress (i, 0).GetBroadcast ();
+
+      //here get the address mask length
+      uint32_t mask = maski.Get ();
+      uint8_t mask_len = 0;
+      while (mask)
+        {
+          mask = mask << 1;
+          mask_len ++;
+        }
+      
+      //next fill the message body
+      NetlinkMessage nlmsg_ifa;
+      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWADDR, NETLINK_MSG_F_MULTI, seq, pid);
+      InterfaceAddressMessage ifamsg;
+
+      ifamsg.SetInterfaceIndex (i);
+      ifamsg.SetFamily (AF_INET);//default AF_INET      
+      ifamsg.SetLength (mask_len);
+      ifamsg.SetFlags (0);
+      ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
+
+      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL,    ADDRESS, addri));
+      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS,  ADDRESS, addri));
+      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_BROADCAST,ADDRESS, bcast));
+      //      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LABEL,    STRING,  "ns3-ifaddr"));//not used in ns3
+      //ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ANYCAST,  ADDRESS, Ipv4Address("0.0.0.0")));//not used in ns3
+      //XXXother attributes not used by ns3
+
+      nlmsg_ifa.SetHeader(nhr);
+      nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
+      nlmsg_dump.AppendMessage (nlmsg_ifa);
+    }
+
+  // For IPv6
+  Ptr<Ipv6>ipv6 = m_node->GetObject<Ipv6> ();
+
+  for (uint32_t i = 0; i < ipv6->GetNInterfaces(); i ++)
+    {
+      if (!ipv6->IsUp (i))
+        continue;
+
+      for (uint32_t j = 0; j < ipv6->GetNAddresses(i); j ++)
+        {
+          Ipv6Address addri = ipv6->GetAddress (i, j).GetAddress();
+          Ipv6Prefix prefix = ipv6->GetAddress (i, j).GetPrefix ();
+
+          //here get the address mask length
+          uint8_t mask_len = prefix.GetPrefixLength();
+
+          //loopback address's prefix is wrong... FIXME
+          if (addri.IsEqual(Ipv6Address::GetLoopback()))
+            mask_len = 128;
+      
+          //next fill the message body
+          NetlinkMessage nlmsg_ifa;
+          NetlinkMessageHeader nhr = NetlinkMessageHeader(NETLINK_RTM_NEWADDR, NETLINK_MSG_F_MULTI, seq, pid);
+          InterfaceAddressMessage ifamsg;       
+
+          ifamsg.SetInterfaceIndex(i);
+          ifamsg.SetFamily(AF_INET6);
+          ifamsg.SetFlags(0);
+
+
+          if (addri.IsLinkLocal())
+            {
+              ifamsg.SetLength(64);
+              ifamsg.SetScope (RouteMessage::RT_SCOPE_LINK);
+            }
+          else
+            {
+              ifamsg.SetLength(mask_len);
+              ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
+            }
+
+
+          ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL,    ADDRESS, addri));
+          ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS,  ADDRESS, addri));
+          //XXXother attributes not used by ns3
+
+          nlmsg_ifa.SetHeader(nhr);
+          nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
+          nlmsg_dump.AppendMessage (nlmsg_ifa);
+        }
+    }
+  return nlmsg_dump;
+}
+MultipartNetlinkMessage
+NetlinkSocket::BuildInterfaceInfoDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << pid << seq <<family);
+  MultipartNetlinkMessage nlmsg_dump;
+  for (uint32_t i = 0; i < m_node->GetNDevices (); i ++)
+    {
+      Ptr<NetDevice> dev = m_node->GetDevice (i);
+      Address mac;
+      Address bcast;
+      uint32_t mtu;
+      uint32_t flags = 0;
+
+      mac = dev->GetAddress ();
+      bcast = dev->GetBroadcast ();
+      mtu = (uint32_t)dev->GetMtu ();
+
+      if (dev->IsLinkUp ())
+        {
+          flags |= IFF_RUNNING;
+          flags |= IFF_UP;
+        }
+      if (dev->IsBroadcast ())
+        {
+          flags |= IFF_BROADCAST;
+        }
+      if (dev->IsMulticast ())
+        {
+          flags |= IFF_MULTICAST;
+        }
+
+      NetlinkMessage nlmsg_ifinfo;
+      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWLINK, NETLINK_MSG_F_MULTI, seq, pid);
+      InterfaceInfoMessage ifinfomsg;     
+
+      ifinfomsg.SetFamily(0);      // AF_UNSPEC
+      ifinfomsg.SetDeviceType (0); // not clear
+      ifinfomsg.SetInterfaceIndex (i);
+      ifinfomsg.SetDeviceFlags (flags); // not clear
+      ifinfomsg.SetChangeMask (0xffffffff);
+
+      // the ns3 device have no  name, here we set "ns3-device i" for test
+      std::stringstream ss;
+      ss <<  "ns3-device" << i;
+
+      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_IFNAME,    STRING,  ss.str()));
+      //not used in ns3
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_TXQLEN,    U32,     0));
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_WEIGHT,    U32,     0));
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_OPERSTATE, U8,      0));
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_LINKMODE,  U8,      0));
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MAP,       UNSPEC,  0));
+      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_ADDRESS,   ADDRESS, mac));
+      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_BROADCAST, ADDRESS, bcast));
+      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MTU,       U32,     mtu));
+      ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_LINK,      U32,     i));
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_QDISC,     STRING,  ""));
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_MASTER,    U32,     0));
+      //ifinfomsg.AppendAttribute (NetlinkAttribute (InterfaceInfoMessage::IFL_A_STATS,     UNSPEC,  0));
+
+      nlmsg_ifinfo.SetHeader (nhr);
+      nlmsg_ifinfo.SetInterfaceInfoMessage (ifinfomsg);
+      nlmsg_dump.AppendMessage (nlmsg_ifinfo);
+    }
+  return nlmsg_dump;
+}
+MultipartNetlinkMessage
+NetlinkSocket::BuildRouteDumpMessage (uint32_t pid, uint32_t seq, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << pid << seq <<family);
+  MultipartNetlinkMessage nlmsg_dump;
+  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
+
+  // We only care about staticRouting for netlink support
+  Ipv4StaticRoutingHelper routingHelper;
+  Ptr<Ipv4StaticRouting> ipv4Static = routingHelper.GetStaticRouting (ipv4);
+  for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
+    {
+      NetlinkMessage nlmsg_rt;
+      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, NETLINK_MSG_F_MULTI, seq, pid);
+      RouteMessage rtmsg;
+      Ipv4RoutingTableEntry route = ipv4Static->GetRoute (i);
+
+      rtmsg.SetFamily (AF_INET);
+      rtmsg.SetDstLength (32);
+      rtmsg.SetSrcLength (0);
+      rtmsg.SetTos (0);//not clear
+      rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
+      rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
+      rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
+      rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
+
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
+      // ns3 use local address as the route src address
+      //      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, route.GetSource()));
+      //      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, route.GetSource()));//not used in ns3
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));      
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));
+
+      nlmsg_rt.SetHeader (nhr);
+      nlmsg_rt.SetRouteMessage (rtmsg);
+      nlmsg_dump.AppendMessage (nlmsg_rt);
+    }
+
+  Ptr<Ipv6> ipv6 = m_node->GetObject<Ipv6> ();
+  // We only care about staticRouting for netlink support
+  Ipv6StaticRoutingHelper routingHelper6;
+  Ptr<Ipv6StaticRouting> ipv6Static = routingHelper6.GetStaticRouting (ipv6);
+  for (uint32_t i = 0; i < ipv6Static->GetNRoutes (); i ++)
+    {
+      NetlinkMessage nlmsg_rt;
+      NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, NETLINK_MSG_F_MULTI, seq, pid);
+      RouteMessage rtmsg;
+      Ipv6RoutingTableEntry route = ipv6Static->GetRoute (i);
+
+      rtmsg.SetFamily (AF_INET6);
+      rtmsg.SetDstLength (128);
+      rtmsg.SetSrcLength (0);
+      rtmsg.SetTos (0);//not clear
+      rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
+      rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
+      rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
+      rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
+
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
+      //ns3 use local address as the route src address
+      // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, 
+      //                                          ipv6->GetSourceAddress(route.GetDest ())));
+      // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, 
+      //                                          ipv6->GetSourceAddress(route.GetDest ())));
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface()));
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface()));      
+      rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway()));
+
+      nlmsg_rt.SetHeader (nhr);
+      nlmsg_rt.SetRouteMessage (rtmsg);
+      nlmsg_dump.AppendMessage (nlmsg_rt);
+    }
+
+  return nlmsg_dump;
+}
+
+int32_t
+NetlinkSocket::DoInterfaceAddressMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << type << family);
+  NS_ASSERT (type == NETLINK_RTM_NEWADDR || type == NETLINK_RTM_DELADDR);
+
+  // XXX
+  NS_ASSERT_MSG (false, "Not implemented yet (RTM_NEWADDR/RTM_DELADDR)");
+
+  InterfaceAddressMessage ifamsg = nlmsg.GetInterfaceAddressMessage ();
+  Ipv4Address addri, addr_local, bcast;
+  NetlinkAttribute attr_local;
+  uint32_t index = ifamsg.GetInterfaceIndex ();
+  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
+  int flag4 = 0, flag6 = 0;
+
+  if (type == NETLINK_RTM_NEWADDR)
+    {
+      //when adding an interface address, it should check the input arguments
+      //prefix-len and local address attribute
+      if (ifamsg.GetLength () > 32 || 
+          ifamsg.GetAttributeByType (attr_local, InterfaceAddressMessage::IF_A_LOCAL) == false)
+        {
+          m_errno = ERROR_INVAL;
+          return -1;
+        }
+    }  
+
+  //get necessary information for add/del, many attributes we not used
+  for (uint32_t i = 0; i < ifamsg.GetNNetlinkAttribute (); i ++)
+    {
+      NetlinkAttribute attr = ifamsg.GetNetlinkAttribute (i);
+      uint32_t attr_type = attr.GetAttrType ();
+
+      switch(attr_type)
+        {
+        case InterfaceAddressMessage::IF_A_ADDRESS:
+          addri = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
+          break;
+        case InterfaceAddressMessage::IF_A_BROADCAST:
+          bcast = Ipv4Address::ConvertFrom(attr.GetAttrPayload ().GetAddress ());
+          break;
+        case InterfaceAddressMessage::IF_A_LOCAL:
+          addr_local = Ipv4Address::ConvertFrom(attr.GetAttrPayload ().GetAddress ());
+          break;
+        case InterfaceAddressMessage::IF_A_LABEL:
+        case InterfaceAddressMessage::IF_A_ANYCAST:
+          break;
+        }
+    }
+
+  if (type == NETLINK_RTM_NEWADDR)
+    {
+      //when adding an interface address by index, if the indexed interface was not exist,
+      //create an new NetDevice with an new index and set the address
+      //otherwise set the indexed interface directly
+      if (index >= ipv4->GetNInterfaces ())
+        {          
+          Ptr<SimpleNetDevice> dev;
+          dev = CreateObject<SimpleNetDevice> ();
+          dev ->SetAddress (Mac48Address::Allocate ());
+          m_node->AddDevice (dev);
+
+          uint32_t netdev_idx = ipv4->AddInterface (dev);
+          // FIXME!
+          Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addri, Ipv4Mask ());
+          ipv4->AddAddress (netdev_idx, ipv4Addr);
+          ipv4->SetUp (netdev_idx);
+          NS_LOG_INFO ("Add an interface address at index "<< netdev_idx << "but not the ifamsg input" << index);
+        }
+      else
+        {
+          Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addri, Ipv4Mask ());
+          ipv4->AddAddress (index, ipv4Addr);
+          if (!ipv4->IsUp (index))
+            ipv4->SetUp (index);
+        }    
+      flag4 = 1;
+    }
+  else//type == NETLINK_RTM_DELADDR
+    {
+      //when delete an interface address by index, if the indexed interface  was not exist
+      //return an error EINVAL, otherwise set down the interface which has the addri
+      if (index >= ipv4->GetNInterfaces ())
+        {
+          m_errno = ERROR_NODEV;
+          return -1;
+        }
+      else
+        {
+          for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i ++)
+            {
+              Ipv4Address ad = ipv4->GetAddress (i, 0).GetLocal ();
+              if (ad == addri && ipv4->IsUp (i))
+                {
+                  ipv4->SetDown (i);
+                  break;
+                }
+              if (i == ipv4->GetNInterfaces () - 1)
+                {
+                  m_errno = ERROR_ADDRNOTAVAIL;
+                  return -1;
+                }
+            }
+          flag4 = 1;
+        }      
+    }
+  
+  //then send an broadcast message, let all user know this operation happened
+  NetlinkMessage nlmsg_broadcast = nlmsg;
+  NetlinkMessageHeader nhr;
+  nhr.SetMsgLen (nlmsg.GetHeader ().GetMsgLen ());
+  nhr.SetMsgType (nlmsg.GetHeader ().GetMsgType ());
+  nlmsg_broadcast.SetHeader (nhr);
+  if (flag4)
+    {
+      SendMessageBroadcast (nlmsg_broadcast, 0, NETLINK_RTM_GRP_IPV4_IFADDR, GetNode ());
+    }
+  else if (flag6)
+    {
+      SendMessageBroadcast (nlmsg_broadcast, 0, RTMGRP_IPV6_IFADDR, GetNode ());
+    }
+
+  return 0;
+}
+
+int32_t
+NetlinkSocket::DoInterfaceInfoMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << type << family);
+  NS_ASSERT (type == NETLINK_RTM_GETLINK || type == NETLINK_RTM_SETLINK);
+  InterfaceInfoMessage ifinfomsg = nlmsg.GetInterfaceInfoMessage ();
+  // XXX
+  NS_ASSERT_MSG (false, "Not implemented yet (RTM_GETLINK/RTM_SETLINK)");
+  return -1;
+}
+
+Address
+NetlinkSocket::ConvertFrom (uint8_t family, const Address &address)
+{
+  Address retval;
+  if (family == AF_INET)
+    {
+      retval = Ipv4Address::ConvertFrom (address);
+    }
+  else if (family == AF_INET6)
+    {
+      retval = Ipv6Address::ConvertFrom (address);
+    }
+  return retval;
+}
+
+int32_t
+NetlinkSocket::DoRouteMessage (const NetlinkMessage &nlmsg, uint16_t type, uint8_t family)
+{
+  NS_LOG_FUNCTION (this << type << family);
+  NS_ASSERT (type == NETLINK_RTM_NEWROUTE || type == NETLINK_RTM_DELROUTE ||type == NETLINK_RTM_GETROUTE);
+
+  RouteMessage rtmsg = nlmsg.GetRouteMessage ();
+  Ipv4Address src, dest, gateway;
+  Ipv6Address src6, dest6, gateway6;
+  uint32_t index = 0;
+  int attr_flags[RouteMessage::RT_A_MAX] = {0};
+  uint8_t dstlen = rtmsg.GetDstLength ();
+
+  //get necessary information for add/del, many attributes we not used
+  for (uint32_t i = 0; i < rtmsg.GetNNetlinkAttribute (); i ++)
+    {
+      NetlinkAttribute attr = rtmsg.GetNetlinkAttribute (i);
+      uint32_t attr_type = attr.GetAttrType ();
+      attr_flags[attr_type] = 1;
+
+      switch(attr_type)
+        {
+        case RouteMessage::RT_A_DST:
+          if (family == AF_INET)
+            {
+              dest = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
+            }
+          else if (family == AF_INET6)
+            {
+              dest6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
+            }
+          break;
+        case RouteMessage::RT_A_SRC:
+          if (family == AF_INET)
+            {
+              src = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
+            }
+          else if (family == AF_INET6)
+            {
+              src6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
+            }
+          break;
+        case RouteMessage::RT_A_OIF:
+          index = attr.GetAttrPayload ().GetU32 ();
+          break;
+        case RouteMessage::RT_A_GATEWAY:
+          if (family == AF_INET)
+            {
+              gateway = Ipv4Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
+            }
+          else if (family == AF_INET6)
+            {
+              gateway6 = Ipv6Address::ConvertFrom (attr.GetAttrPayload ().GetAddress ());
+            }
+          break;
+        case RouteMessage::RT_A_IIF:
+        case RouteMessage::RT_A_PRIORITY:
+        case RouteMessage::RT_A_PREFSRC:
+        case RouteMessage::RT_A_METRICS:
+        case RouteMessage::RT_A_MULTIPATH:
+        case RouteMessage::RT_A_PROTOINFO:
+        case RouteMessage::RT_A_FLOW:
+        case RouteMessage::RT_A_CACHEINFO:
+        case RouteMessage::RT_A_SESSION:
+        case RouteMessage::RT_A_MP_ALGO:
+        case RouteMessage::RT_A_TABLE:
+          NS_LOG_INFO("route attribute not used by ns3" << attr_type);
+          //not used by ns3
+          break;
+        }
+    }
+
+  // Sigh....
+  Ptr<Ipv4>ipv4 = m_node->GetObject<Ipv4> ();
+  Ipv4StaticRoutingHelper routingHelper;
+  Ptr<Ipv4StaticRouting> ipv4Static = routingHelper.GetStaticRouting (ipv4);
+
+  Ptr<Ipv6>ipv6 = m_node->GetObject<Ipv6> ();
+  Ipv6StaticRoutingHelper routingHelper6;
+  Ptr<Ipv6StaticRouting> ipv6Static = routingHelper6.GetStaticRouting (ipv6);
+
+  NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << " Route message, type: " << type << "; from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
+      << " to " << dest<< " through " << gateway);
+
+  if (type == NETLINK_RTM_NEWROUTE)
+    {
+      //ns3 add a route entry only depends on 2 or 3 attribute
+      //other route msg attibute were ignored
+      if (attr_flags[RouteMessage::RT_A_DST])
+        {
+          if (family == AF_INET)
+            {
+              if (!attr_flags[RouteMessage::RT_A_OIF])
+                {
+                  bool found = 0;
+                  for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
+                    {
+                      for (uint32_t j = 0; j < ipv4->GetNAddresses (i); j++)
+                        {
+                          if ((attr_flags[RouteMessage::RT_A_GATEWAY]))
+                            {
+                              Ipv4Mask mask = ipv4->GetAddress (i, j).GetMask ();
+                              if (mask.IsMatch (ipv4->GetAddress (i, j).GetLocal (), gateway))
+                                {
+                                  index = i;
+                                  found = true;
+                                  break;
+                                }
+                            }
+                          if (found) break;
+                        }
+                    }
+                  if (!found)
+                    {
+                      NS_LOG_DEBUG ("No suitable interface to add an route entry");
+                      m_errno = ERROR_ADDRNOTAVAIL;
+                      return -1;
+                    }
+                }
+            if (dstlen == 32)
+              {
+                int exist_flag = 0;
+                for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
+                  {
+                    Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
+                    if (dest == rt.GetDest ())
+                      {
+                        exist_flag = 1;
+                      }
+                  }
+
+                if (exist_flag)
+                  { //route to dest already exists
+                    int delete_flag = 0;
+                    if (nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_REPLACE)
+                      {
+                        for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
+                          {
+                            Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
+                            if (dest == rt.GetDest ())
+                              {
+                                ipv4Static->RemoveRoute (i);
+                                NS_LOG_DEBUG ("Route from  " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to "
+                                    << dest << " through " << gateway << " removed");
+                                delete_flag = 1;
+                              }
+                          }
+
+                        if (!delete_flag)
+                          {
+                             NS_LOG_INFO ("no route entry removed by dest address in new route sector " << dest);
+                             m_errno = ERROR_INVAL;
+                             return -1;
+                           }
+                      }
+                    else
+                      {
+                        NS_LOG_DEBUG ("Route exists but overwriting declined!");
+                      }
+                    if ((attr_flags[RouteMessage::RT_A_GATEWAY]))
+                      {
+                        NS_LOG_DEBUG (Simulator::Now().GetSeconds() << "Overwrite route from "
+                            << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to " << dest<< " through " << gateway << " with index" << index);
+                        ipv4Static->AddHostRouteTo (dest, gateway, index);
+                      }
+                    else
+                      {
+                        NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Overwrite route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
+                            << " to " << dest<< " through " << "self" << " with index" << index);
+                        ipv4Static->AddHostRouteTo (dest, index);
+                      }
+                }
+                else
+                  { //route to dest doesn't exist
+                    if (nlmsg.GetHeader ().GetMsgFlags () & NETLINK_MSG_F_CREATE)
+                      {
+                        if (attr_flags[RouteMessage::RT_A_GATEWAY])
+                          {
+                            NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Add new route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
+                                << " to " << dest<< " through " << gateway << " with index" << index);
+                            ipv4Static->AddHostRouteTo (dest, gateway, index);
+                          }
+                        else
+                          {
+                            NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Add new route from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
+                                << " to " << dest<< " through " << "self" << " with index" << index);
+                            ipv4Static->AddHostRouteTo (dest, index);
+                          }
+                      }
+                    else
+                      {
+                        NS_LOG_ERROR ("Route doesn't exist but writing declined!");
+                      }
+                  }
+
+                NS_LOG_DEBUG ("=After change attempt=");
+                //Dump of table
+                NS_LOG_DEBUG (m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << ":");
+                for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); ++i)
+                  {
+                    Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
+                    NS_LOG_DEBUG (rt.GetDest () << " through " << rt.GetGateway ());
+                  }
+                NS_LOG_DEBUG ("= = = = = = = = = = =");
+              }
+            else // dstlen != 32
+              {
+                if (attr_flags[RouteMessage::RT_A_GATEWAY])
+                  {
+                    ipv4Static->AddNetworkRouteTo (dest, Ipv4Mask (~(1<<(32 - dstlen))+1), gateway, index);
+                  }
+                else
+                  {
+                    ipv4Static->AddNetworkRouteTo (dest, Ipv4Mask (~(1<<(32 - dstlen))+1), index);
+                  }
+              }
+          }
+          else if (family == AF_INET6)
+            {
+            if (!attr_flags[RouteMessage::RT_A_OIF])
+              {
+#ifdef FIXME
+              if (ipv6->GetIfIndexForDestination (gateway6, index) == false)
+                {
+                  NS_LOG_INFO ("No suitable interface to add an route entry");
+                  m_errno = ERROR_ADDRNOTAVAIL;
+                  return -1;
+                }
+#endif
+              }
+
+            Ipv6Prefix pref (dstlen);
+            if (attr_flags[RouteMessage::RT_A_GATEWAY])
+              {
+                ipv6Static->AddNetworkRouteTo (dest6, pref, gateway6, index);
+              }
+            else
+              {
+                ipv6Static->AddNetworkRouteTo (dest6, pref, Ipv6Address("::"), index);
+              }
+            }
+          }
+        else
+          {
+            NS_LOG_INFO("too few attributes to add an route entry");
+            m_errno = ERROR_INVAL;
+            return -1;
+          }
+    }
+  else if (type == NETLINK_RTM_DELROUTE)
+    {
+      NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "Route delete request from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal ()
+          << " to " << dest<< " through " << gateway);
+      if (attr_flags[RouteMessage::RT_A_DST])
+        {
+          int delete_flag = 0;
+
+          if (family == AF_INET)
+            {
+              for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
+                {
+                Ipv4RoutingTableEntry rt = ipv4Static->GetRoute (i);
+                if (gateway == rt.GetGateway () && dest == rt.GetDest ())
+                  {
+                    ipv4Static->RemoveRoute (i);
+                    delete_flag = 1;
+                  }
+                }
+            }
+          else if (family == AF_INET6)
+            {
+              for (uint32_t i = 0; i < ipv6Static->GetNRoutes (); i ++)
+                {
+                Ipv6RoutingTableEntry rt = ipv6Static->GetRoute (i);
+                if (gateway6 == rt.GetGateway () && dest6 == rt.GetDest ())
+                  {
+                    ipv6Static->RemoveRoute (i);
+                    delete_flag = 1;
+                  }
+                }
+            }
+
+          if (!delete_flag)
+            {
+              NS_LOG_INFO ("no route entry removed by dest address " << dest);
+              m_errno = ERROR_INVAL;
+              return -1;
+            }
+        }
+      else
+        {
+          NS_LOG_INFO ("too few attributes to add an route entry");
+          m_errno = ERROR_INVAL;
+          return -1;    
+        }
+    }
+  else// type == NETLINK_RTM_GETROUTE
+    {
+      NS_LOG_DEBUG (Simulator::Now ().GetSeconds () << "GetRoute "<< "from " << m_node->GetObject<Ipv4> ()->GetAddress (1, 0).GetLocal () << " to " << dest);
+      if (!attr_flags[RouteMessage::RT_A_DST])
+        {
+          NS_LOG_INFO ("too few attributes to get an route entry");
+          m_errno = ERROR_INVAL;
+          return -1;
+        }
+      
+      int get_flag = 0;
+      if (family == AF_INET)
+        {
+          for (uint32_t i = 0; i < ipv4Static->GetNRoutes (); i ++)
+            {
+              Ipv4RoutingTableEntry route = ipv4Static->GetRoute (i);
+              //find the route entry with same dest address and send unicast to user space
+              if (dest.IsEqual (route.GetDest ()))
+                {
+                  //                Ptr<Ipv4>ipv4 = m_node->GetObject<Ipv4> ();
+                  NetlinkMessage nlmsg_route;
+                  NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, 0, 
+                                                                   nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
+                  RouteMessage rtmsg;
+
+                  //fill rtmsg and attributes
+                  rtmsg.SetFamily (AF_INET);
+                  rtmsg.SetDstLength (32);
+                  rtmsg.SetSrcLength (0);
+                  rtmsg.SetTos (0);//not clear
+                  rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
+                  rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
+                  rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
+                  rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
+
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
+                  //ns3 use local address as the route src address
+                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, ipv4->GetSourceAddress(route.GetDest ())));
+                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, ipv4->GetSourceAddress(route.GetDest ())));
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));
+
+                  //fill an netlink message body
+                  nlmsg_route.SetHeader (nhr);
+                  nlmsg_route.SetRouteMessage (rtmsg);
+                  
+                  SendMessageUnicast (nlmsg_route, m_srcPid, 1);
+                  get_flag = 1;
+                }
+            }
+        }
+      else if (family == AF_INET6)
+        {
+          for (uint32_t i = 0; i < ipv6Static->GetNRoutes(); i ++)
+            {
+              Ipv6RoutingTableEntry route = ipv6Static->GetRoute (i);
+              //find the route entry with same dest address and send unicast to user space
+              if (dest6.IsEqual (route.GetDest ()))
+                {
+                  NetlinkMessage nlmsg_route;
+                  NetlinkMessageHeader nhr = NetlinkMessageHeader (NETLINK_RTM_NEWROUTE, 0, 
+                                                                   nlmsg.GetHeader ().GetMsgSeq (), m_srcPid);
+                  RouteMessage rtmsg;
+
+                  //fill rtmsg and attributes
+                  rtmsg.SetFamily (AF_INET6);
+                  rtmsg.SetDstLength (32);
+                  rtmsg.SetSrcLength (0);
+                  rtmsg.SetTos (0);//not clear
+                  rtmsg.SetTableId (RouteMessage::RT_TABLE_MAIN);
+                  rtmsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
+                  rtmsg.SetProtocol (RouteMessage::RT_PROT_UNSPEC);
+                  rtmsg.SetFlags (RouteMessage::RT_F_CLONED);
+
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_DST, ADDRESS, route.GetDest ()));
+                  //ns3 use local address as the route src address
+                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_SRC, ADDRESS, ipv6->GetSourceAddress(route.GetDest ())));
+                  // rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_PREFSRC, ADDRESS, ipv6->GetSourceAddress(route.GetDest ())));
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_IIF, U32, route.GetInterface ()));
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_OIF, U32, route.GetInterface ()));
+                  rtmsg.AppendAttribute (NetlinkAttribute (RouteMessage::RT_A_GATEWAY, ADDRESS, route.GetGateway ()));
+
+                  //fill an netlink message body
+                  nlmsg_route.SetHeader (nhr);
+                  nlmsg_route.SetRouteMessage (rtmsg);
+
+                  SendMessageUnicast (nlmsg_route, m_srcPid, 1);
+                  get_flag = 1;
+                }
+            }
+        }
+      
+      if (!get_flag)
+        {
+          NS_LOG_INFO ("no route entry exist by dest address" << dest);
+          m_errno = ERROR_INVAL;
+          return -1;
+        }
+    }
+
+  //then send an broadcast message, let all user know this operation happened
+  MultipartNetlinkMessage nlmsg_multi;
+  NetlinkMessage nlmsg_broadcast = nlmsg;
+  NetlinkMessage nlmsg_done;
+  NetlinkMessageHeader nhr_done = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 0, 0);
+  nlmsg_done.SetHeader (nhr_done);
+  nlmsg_multi.AppendMessage (nlmsg);
+  nlmsg_multi.AppendMessage (nlmsg_done);
+  SendMessageBroadcast (nlmsg_multi, 0, NETLINK_RTM_GRP_IPV4_ROUTE, GetNode ());
+  //   SendMessageBroadcast(nlmsg_broadcast, 0, RTMGRP_IPV6_ROUTE);
+  return 0;
+}
+
+int32_t
+NetlinkSocket::NotifyIfLinkMessage (Address address, uint16_t type, uint8_t family)
+{
+  NS_ASSERT_MSG (false, "Not implemented yet (NotifyIfLinkMessage)");
+  return 0;
+}
+
+int32_t
+NetlinkSocket::NotifyIfAddrMessage (Ipv6Interface* interface, Ipv6Address addr, int cmd)
+{
+  MultipartNetlinkMessage nlmsg_multi;
+  NetlinkMessage nlmsg_ifa;
+  NetlinkMessageHeader nhr = NetlinkMessageHeader (cmd, NETLINK_MSG_F_MULTI, 0, 0);
+  InterfaceAddressMessage ifamsg;
+
+  NS_ASSERT_MSG (false, "Not implemented yet (NotifyIfAddrMessage)");
+
+  // FIXME!
+  Ipv6Prefix prefix = Ipv6Prefix(64);
+
+  //here get the address mask length
+  uint8_t bytes[16];
+  prefix.GetBytes (bytes);
+  uint8_t mask_len = 0;
+  for (int j = 0; j < 16; j++)
+    {
+      while (bytes[j])
+        {
+          bytes[j] = bytes[j] << 1;
+          mask_len ++;
+        }
+    }
+      
+  ifamsg.SetInterfaceIndex (interface->GetDevice ()->GetIfIndex ());
+  ifamsg.SetFamily (AF_INET6);
+  ifamsg.SetLength (mask_len);
+  ifamsg.SetFlags (0);
+  ifamsg.SetScope (RouteMessage::RT_SCOPE_UNIVERSE);
+
+  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LOCAL,    ADDRESS, addr));
+  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ADDRESS,  ADDRESS, addr));
+  //  ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_BROADCAST,ADDRESS, bcast));
+  //      ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_LABEL,    STRING,  "ns3-ifaddr"));//not used in ns3
+  //ifamsg.AppendAttribute (NetlinkAttribute (InterfaceAddressMessage::IF_A_ANYCAST,  ADDRESS, Ipv4Address("0.0.0.0")));//not used in ns3
+  //XXXother attributes not used by ns3
+
+  nlmsg_ifa.SetHeader (nhr);
+  nlmsg_ifa.SetInterfaceAddressMessage (ifamsg);
+
+  NetlinkMessage nlmsg_done;
+  NetlinkMessageHeader nhr_done = NetlinkMessageHeader (NETLINK_MSG_DONE, NETLINK_MSG_F_MULTI, 0, 0);
+  nlmsg_done.SetHeader (nhr_done);
+
+  nlmsg_multi.AppendMessage (nlmsg_ifa);
+  nlmsg_multi.AppendMessage (nlmsg_done);
+
+  SendMessageBroadcast (nlmsg_multi, 0, RTMGRP_IPV6_IFADDR, interface->GetDevice ()->GetNode ());  
+  return 0;
+}
+
+#ifdef FIXME
+int32_t
+NetlinkSocket::NotifyRouteMessage(Ojbect route, uint16_t type, uint8_t family)
+{
+  NetlinkMessage nlmsg_broadcast = nlmsg;
+  NetlinkMessageHeader nhr;
+  NS_ASSERT_MSG (false, "Not implemented yet");
+
+  nhr.SetMsgLen (nlmsg.GetHeader ().GetMsgLen ());
+  nhr.SetMsgType (nlmsg.GetHeader ().GetMsgType ());
+  nlmsg_broadcast.SetHeader (nhr);
+  SendMessageBroadcast (nlmsg_broadcast, 0, RTMGRP_IPV6_ROUTE);
+  return 0;
+}
+#endif
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/netlink/netlink-socket.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,204 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 Liu Jian
+ *
+ * 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: Liu Jian <liujatp@gmail.com>
+ *         Hajime Tazaki <tazaki@sfc.wide.ad.jp>
+ */
+#ifndef NETLINK_SOCKET_H
+#define NETLINK_SOCKET_H
+
+#include <stdint.h>
+#include <queue>
+#include "netlink-message.h"
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "ns3/traced-callback.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv6-address.h"
+#include "ns3/ipv6-interface.h"
+
+namespace ns3 {
+
+class Node;
+class Packet;
+class NetlinkSocketAddress;
+
+/**
+* \brief A NetlinkSocket is  used  to transfer information 
+between kernel and userspace processes .
+*
+* here we focus on NETLINK_ROUTE: Receives routing and link
+* updates and may be used to modify  the  routing  tables 
+* (both IPv4 and IPv6), IP addresses, link parame- ters, neighbor
+* setups, queueing disciplines, traffic classes and packet 
+* classifiers (see rtnetlink (7)). This socket type is very similar
+* to the linux and BSD "packet" sockets.
+*
+* Here is a summary of the semantics of this class:
+* - Bind: Bind uses only the protocol and device fields of the 
+*       NetlinkSocketAddress.
+*
+* - Send: send the input packet to the underlying kernel space
+*       with its own address. The socket must  be bound.
+*
+* - Recv: receive packet from the kernel space.
+*
+* - Accept: not allowed
+* - Connect: not allowed
+*/
+class NetlinkSocket : public Socket
+{
+public:
+  static TypeId GetTypeId (void);
+
+  NetlinkSocket ();
+  virtual ~NetlinkSocket ();
+
+  void SetNode (Ptr<Node> node);
+
+  virtual enum SocketErrno GetErrno (void) const;
+  virtual Ptr<Node> GetNode (void) const;
+  virtual int Bind (void);
+  virtual int Bind (const Address & address);
+  virtual int Close (void);
+  virtual int ShutdownSend (void);
+  virtual int ShutdownRecv (void);
+  virtual int Connect (const Address &address);
+  virtual int Listen (void);
+  virtual uint32_t GetTxAvailable (void) const;
+  virtual int Send (Ptr<Packet> p, uint32_t flags);
+  virtual int SendTo(Ptr<Packet> p, uint32_t flags, const Address &toAddress);
+  virtual uint32_t GetRxAvailable (void) const;
+  virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags);
+  virtual Ptr<Packet> RecvFrom (uint32_t maxSize, uint32_t flags, 
+                                Address &fromAddress);
+  virtual int GetSockName (Address &address) const; 
+  virtual int GetPeerName (Address &address) const;
+  virtual bool SetAllowBroadcast (bool allowBroadcast);
+  virtual bool GetAllowBroadcast () const;
+
+  uint32_t GetSrcPid (void) const;
+  uint32_t GetSrcGroups (void)const;
+  uint32_t GetDstPid (void) const;
+  uint32_t GetDstGroups (void)const;
+  int32_t NotifyIfAddrMessage (Ipv6Interface* interface, Ipv6Address addr, int cmd);
+  int32_t NotifyIfLinkMessage (Address address, uint16_t type, uint8_t family);
+  //  int32_t NotifyRouteMessage(Ojbect route, uint16_t type, uint8_t family);
+
+private:
+  int DoBind (const NetlinkSocketAddress &address);
+  virtual void DoDispose (void);
+  void ForwardUp (Ptr<Packet> p, NetlinkSocketAddress &address);
+
+
+
+  /**
+ * the functions below were for kernel parsing netlink message,set private here
+ * when netlink msg sent to kernel through netlink socket, it was parsed in kernel
+ * space, then, kernel add/del its route/interface/link table or dump all information
+ * to user space
+ */
+
+  int32_t HandleMessage (const NetlinkMessage &nlmsg);
+  /**
+  * when kernel find the message truncated or user need an ACK response,
+  * it send ACK back to user space, with the error code(0 for ACK, > 0 for error).
+  */
+  void SendAckMessage (const NetlinkMessage &nlmsg, int32_t errorcode);
+
+  /**
+  * \brief unicast an message to user
+  * \param nlmsg the netlink message to transmit
+  * \param pid the netlink pid of destination socket
+  * \param nonbloack always true
+  */
+  int32_t SendMessageUnicast (const MultipartNetlinkMessage &nlmsg, 
+                              uint32_t pid, int32_t nonblock);
+  /**
+  * \brief spread message to netlink group user
+  * \param nlmsg the netlink message to transmit
+  * \param pid the netlink pid of the kernel, always 0
+  * \param group multicast group id
+  */
+  static int32_t SendMessageBroadcast (const MultipartNetlinkMessage &nlmsg, 
+                                       uint32_t pid, uint32_t group, Ptr<Node> node);
+
+  /**
+  * these functions below are for NETLINK_ROUTE protocol, it handle the netlink 
+  * message like linux kernel work.  this implementation follows the kernel code 
+  * linux/rtnetlink.c, focus on "interface address, interface info and route entry",
+  * now we will only simply support three types operations of  NETLINK_ROUTE 
+  * protocol
+  */
+  
+  /**
+  * \returns 0 if messge not processed, < 0 for success or an error.
+  * this function would call dumping/doing functions to  
+  */
+  int32_t HandleNetlinkRouteMessage (const NetlinkMessage &nlmsg);
+  
+  /**
+  * \returns 0 if dumping operation is OK, < 0 for an error.
+  */ 
+  int32_t DumpNetlinkRouteMessage (const NetlinkMessage &nlmsg, 
+                                   uint16_t type, uint8_t family);
+  MultipartNetlinkMessage BuildInterfaceAddressDumpMessage (uint32_t pid,
+                                                            uint32_t seq, uint8_t family);
+  MultipartNetlinkMessage BuildInterfaceInfoDumpMessage (uint32_t pid,
+                                                         uint32_t seq, uint8_t family);
+  MultipartNetlinkMessage BuildRouteDumpMessage (uint32_t pid,
+                                                 uint32_t seq, uint8_t family);
+
+  /**
+  * \returns 0 if doing operation(ADD/DEL/GET) is OK, < 0 for an error.
+  */
+  int32_t DoNetlinkRouteMessage (const NetlinkMessage &nlmsg,
+                                 uint16_t type, uint8_t family);
+  int32_t DoInterfaceAddressMessage (const NetlinkMessage &nlmsg, 
+                                     uint16_t type, uint8_t family);
+  int32_t DoInterfaceInfoMessage (const NetlinkMessage &nlmsg, 
+                                  uint16_t type, uint8_t family);
+  int32_t DoRouteMessage (const NetlinkMessage &nlmsg, 
+                          uint16_t type, uint8_t family);
+
+  int ErrnoToSimuErrno (void);
+  Address ConvertFrom (uint8_t family, const Address &address);
+
+  Ptr<Node> m_node;
+  enum SocketErrno m_errno;
+  bool m_shutdownSend;
+  bool m_shutdownRecv;
+
+  std::queue<Ptr<Packet> > m_dataReceiveQueue;
+  uint32_t m_rxAvailable;
+  TracedCallback<Ptr<const Packet> > m_dropTrace;
+  // Socket options (attributes)
+  uint32_t m_rcvBufSize;
+
+  uint32_t m_srcPid;
+  uint32_t m_srcGroups;
+  uint32_t m_dstPid;
+  uint32_t m_dstGroups;
+  Callback<void, Ipv4Address,uint8_t,uint8_t,uint8_t,uint32_t> m_icmpCallback;
+};
+
+}//namespace ns3
+
+#endif /* NETLINK_SOCKET_H */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/ns3-socket-fd-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,66 @@
+#include "ns3-socket-fd-factory.h"
+#include "unix-fd.h"
+#include "unix-socket-fd.h"
+#include "unix-datagram-socket-fd.h"
+#include "unix-stream-socket-fd.h"
+#include "netlink/netlink-socket-factory.h"
+#include "ns3/socket-factory.h"
+#include "ns3/socket.h"
+#include "ns3/uinteger.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED(Ns3SocketFdFactory);
+
+TypeId 
+Ns3SocketFdFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::Ns3SocketFdFactory")
+    .SetParent<SocketFdFactory> ()
+    .AddConstructor<Ns3SocketFdFactory> ()
+    ;
+  return tid;
+}
+
+Ns3SocketFdFactory::Ns3SocketFdFactory ()
+{
+  m_netlink = CreateObject<NetlinkSocketFactory> ();
+}
+UnixFd *
+Ns3SocketFdFactory::CreateSocket (int domain, int type, int protocol)
+{
+  NS_ASSERT (domain == PF_INET || domain == PF_NETLINK || domain == PF_INET6);
+
+  UnixSocketFd *socket = 0;
+  Ptr<Socket> sock;
+
+  switch (type) {
+  case SOCK_DGRAM: {
+    TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
+    Ptr<SocketFactory> factory = GetObject<SocketFactory> (tid);
+    sock = factory->CreateSocket ();
+    socket = new UnixDatagramSocketFd (sock);
+  } break;
+  case SOCK_RAW: {
+    TypeId tid = TypeId::LookupByName ("ns3::Ipv4RawSocketFactory");
+    Ptr<SocketFactory> factory = GetObject<SocketFactory> (tid);
+    sock = factory->CreateSocket ();
+    sock->SetAttribute ("Protocol", UintegerValue (protocol));
+    socket = new UnixDatagramSocketFd (sock);
+  } break;
+  case SOCK_STREAM: {
+    TypeId tid = TypeId::LookupByName ("ns3::TcpSocketFactory");
+    Ptr<SocketFactory> factory = GetObject<SocketFactory> (tid);
+    sock = factory->CreateSocket ();
+    socket = new UnixStreamSocketFd (sock);
+  } break;
+    default:
+      // XXX insert netlink creation here.
+      NS_FATAL_ERROR ("missing socket type");
+      break;
+  }
+
+  return socket;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/ns3-socket-fd-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,22 @@
+#ifndef NS3_SOCKET_FD_FACTORY_H
+#define NS3_SOCKET_FD_FACTORY_H
+
+#include "socket-fd-factory.h"
+
+namespace ns3 {
+
+class NetlinkSocketFactory;
+
+class Ns3SocketFdFactory : public SocketFdFactory
+{
+public:
+  static TypeId GetTypeId (void);
+  Ns3SocketFdFactory ();
+  virtual UnixFd *CreateSocket (int domain, int type, int protocol);
+ private:
+  Ptr<NetlinkSocketFactory> m_netlink;
+};
+
+} // namespace ns3
+
+#endif /* NS3_SOCKET_FD_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/process.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,188 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 PROCESS_H
+#define PROCESS_H
+
+#include <signal.h>
+#include <vector>
+#include <list>
+#include <stdio.h>
+#include "ns3/callback.h"
+#include "ns3/event-id.h"
+#include "ns3/nstime.h"
+#include "unix-fd.h"
+#include "ns3/random-variable.h"
+
+class Alloc;
+
+extern "C" {
+struct SimTask;
+}
+
+
+namespace ns3 {
+
+struct Process;
+struct Thread;
+class DceManager;
+class UnixFd;
+class Loader;
+class Task;
+
+struct Mutex
+{
+  uint32_t mid; // mutex id
+  enum {
+    NORMAL,
+    RECURSIVE
+  } type;
+  uint32_t count;
+  std::list<Thread *> waiting;
+  Thread *current;
+};
+struct Semaphore
+{
+  uint32_t sid; // semaphore id
+  uint32_t count;
+  std::list<Thread *> waiting;
+};
+struct Condition
+{
+  uint32_t cid; // condition var id
+  std::list<Thread *> waiting;
+};
+struct SignalHandler
+{
+  int signal;
+  int flags;
+  sigset_t mask;
+  void (*handler) (int);
+  void (*sigaction) (int, siginfo_t *, void *);
+};
+enum ThreadState_e {
+  // the thread is executing
+  THREAD_RUNNING,
+  // the thread is in the run queue, not executing yet
+  THREAD_ACTIVE,
+  // the thread is blocked, is not in the run queue, is not executing
+  THREAD_BLOCKED,
+  // the thread is dead: it will never move back to any other state
+  // and will be deleted soon.
+  THREAD_DEAD
+};
+
+struct AtExitHandler
+{
+  enum {
+    NORMAL,
+    CXA
+  } type;
+  union {
+    void (*normal) (void);
+    struct {
+      void (*fn) (void *);
+      void *arg;
+      void *d;
+    } cxa;
+  } value;
+};
+
+struct Process 
+{
+  uid_t euid;
+  uid_t ruid;
+  uid_t suid;
+  gid_t egid;
+  gid_t rgid;
+  gid_t sgid;
+  uint16_t ppid;
+  uint16_t pid;
+  std::string name;
+  std::vector<std::pair<int,UnixFd *> > openFiles;
+  std::vector<FILE *> openStreams;
+  std::vector<SignalHandler> signalHandlers;
+  std::vector<Thread *> threads;
+  std::vector<Mutex *> mutexes;
+  std::vector<Semaphore *> semaphores;
+  std::vector<Condition *> conditions;
+  std::vector<struct AtExitHandler> atExitHandlers;
+  sigset_t pendingSignals;
+  Time itimerInterval;
+  EventId itimer;
+  uint32_t nextMid;
+  uint32_t nextSid;
+  uint32_t nextCid;
+  pthread_key_t nextThreadKey;
+  int exitValue;
+  DceManager *manager;
+  Loader *loader;
+  void *mainHandle;
+  std::string cwd;
+  Alloc *alloc;
+  Callback<void,uint16_t,int> finished;
+  // the values specified by the user
+  char **originalEnvp;
+  char **originalArgv;
+  int originalArgc;
+  // pointers to the global variables present in the libc loader 
+  // in the corresponding process.
+  FILE **pstdin;
+  FILE **pstdout;
+  FILE **pstderr;
+  char ***penvp;
+  // an array of memory buffers which must be freed upon process 
+  // termination to avoid memory leaks. We stick in there a bunch
+  // of buffers we allocate but for which we cannot control the 
+  // lifetime due to weirdness in the posix API.
+  std::vector<void *> allocated;
+  //random variable for rand and random implementation
+  RandomVariable rndVarible;
+};
+
+struct ThreadKeyValue
+{
+  pthread_key_t key;
+  void (*destructor) (void*);
+  void *value;
+};
+
+struct Thread
+{
+  /* true: this thread has been detached with pthread_detach. */
+  bool isDetached;
+  /* true: exitValue field is valid */
+  bool hasExitValue;
+  /* value passed to pthread_exit or returned from thread function */
+  void *exitValue;
+  /* errno of the thread. */
+  int err;
+  /* thread id. */
+  uint16_t tid;
+  Task *task;
+  Thread *joinWaiter;
+  Process *process;
+  std::list<struct ThreadKeyValue> keyValues;
+  sigset_t signalMask;
+  sigset_t pendingSignals;
+};
+
+} // namespace ns3
+
+#endif /* PROCESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/pthread-fiber-manager.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2008 Sam Jansen
+ *
+ * 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: Sam Jansen <sam.jansen@gmail.com>
+ */
+#include "pthread-fiber-manager.h"
+#include "ns3/assert.h"
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+#include <setjmp.h>
+
+namespace ns3 {
+
+enum PthreadFiberState {
+  RUNNING,
+  SLEEP,
+  DESTROY
+};
+
+struct PthreadFiber : public Fiber
+{
+  pthread_t thread;
+  pthread_mutex_t mutex;
+  pthread_cond_t condvar;
+  enum PthreadFiberState state;
+  bool thread_started;
+  size_t stack_size;
+  void (*func) (void *);
+  void *context;
+  jmp_buf initial_env;
+};
+
+
+PthreadFiberManager::PthreadFiberManager ()
+  : m_notifySwitch (0)
+{}
+PthreadFiberManager::~PthreadFiberManager ()
+{}
+
+void
+PthreadFiberManager::Start (struct PthreadFiber *fiber)
+{
+  int error;
+  pthread_attr_t attr;
+  error = pthread_attr_init (&attr);
+  NS_ASSERT_MSG (error == 0, "error=" << strerror (error));
+  error = pthread_attr_setstacksize (&attr, std::max (fiber->stack_size, 
+						      (size_t)PTHREAD_STACK_MIN));
+  NS_ASSERT_MSG (error == 0, "error=" << strerror (error));
+  error = pthread_create (&fiber->thread, &attr, &PthreadFiberManager::Run, 
+                          (void*) fiber);
+  NS_ASSERT_MSG (error == 0, "error=" << strerror (error));
+  error = pthread_attr_destroy (&attr);
+  NS_ASSERT_MSG (error == 0, "error=" << strerror (error));
+  fiber->thread_started = true;
+}
+
+void
+PthreadFiberManager::Wakeup (struct PthreadFiber *fiber)
+{
+  pthread_mutex_lock (&fiber->mutex);
+  fiber->state = RUNNING;
+
+  if (fiber->thread_started) 
+    {
+      pthread_cond_signal (&fiber->condvar);
+    } 
+  else 
+    {
+      Start (fiber);
+    }
+
+  while (fiber->state == RUNNING)
+    {
+      pthread_cond_wait (&fiber->condvar, &fiber->mutex);
+    }
+
+  pthread_mutex_unlock (&fiber->mutex);
+}
+
+void
+PthreadFiberManager::Yield (struct PthreadFiber *fiber)
+{
+  fiber->state = SLEEP;
+  pthread_cond_signal (&fiber->condvar);
+  while (fiber->state != RUNNING)
+    {
+      if (fiber->state == DESTROY)
+        {
+          pthread_mutex_unlock (&fiber->mutex);
+          // now, we jump back to the creator of the thread
+          // i.e., we unwind the stack without invoking the
+          // destructors of its local variables
+          longjmp (fiber->initial_env, 1);
+        }
+      else
+        {
+          pthread_cond_wait (&fiber->condvar, &fiber->mutex);
+        }
+    }
+}
+
+void *
+PthreadFiberManager::Run (void *arg)
+{
+  struct PthreadFiber *fiber = (struct PthreadFiber *) arg;
+  pthread_mutex_lock (&fiber->mutex);
+  if (setjmp (fiber->initial_env) == 0)
+    {
+      fiber->func (fiber->context);
+      fiber->state = DESTROY;
+      pthread_cond_signal (&fiber->condvar);
+      pthread_mutex_unlock (&fiber->mutex);
+    }
+  else
+    {
+      // oops, we are returning from a Delete
+      // we can easily return and we are done !
+    }
+  pthread_detach (fiber->thread);
+  return 0;
+}
+
+struct Fiber *
+PthreadFiberManager::Create (void (*callback) (void *),
+			     void *context,
+			     uint32_t stackSize)
+{
+  struct PthreadFiber *fiber = (struct PthreadFiber *)CreateFromCaller ();
+  fiber->func = callback;
+  fiber->context = context;
+  fiber->state = SLEEP;
+  fiber->thread_started = false;
+  fiber->stack_size = stackSize;
+  return fiber;
+}
+struct Fiber *
+PthreadFiberManager::CreateFromCaller (void)
+{
+  struct PthreadFiber *fiber = new PthreadFiber ();
+  pthread_mutex_init (&fiber->mutex, NULL);
+  pthread_cond_init (&fiber->condvar, NULL);
+  fiber->state = RUNNING;
+  fiber->thread_started = true;
+  fiber->func = NULL;
+  fiber->stack_size = 0;
+  return fiber;
+}
+void 
+PthreadFiberManager::Delete (struct Fiber *fib)
+{
+  struct PthreadFiber *fiber = (struct PthreadFiber *)fib;
+  if (fiber->func != 0)
+    {
+      pthread_mutex_lock (&fiber->mutex);
+      if (fiber->state != DESTROY && fiber->thread_started)
+        {
+	  fiber->state = DESTROY;
+          pthread_cond_signal (&fiber->condvar);
+          pthread_mutex_unlock (&fiber->mutex);
+          pthread_join (fiber->thread, 0);
+        }
+      else
+        {
+          pthread_mutex_unlock (&fiber->mutex);
+        }
+    }
+  int status = pthread_mutex_destroy (&fiber->mutex);
+  NS_ASSERT (status == 0);
+  status = pthread_cond_destroy (&fiber->condvar);
+  NS_ASSERT (status == 0);
+  delete fiber;
+}
+void 
+PthreadFiberManager::SwitchTo (struct Fiber *fromFiber,
+			       const struct Fiber *toFiber)
+{
+  struct PthreadFiber *from = (struct PthreadFiber *)fromFiber;
+  struct PthreadFiber *to = (struct PthreadFiber *)toFiber;
+  if (from->func != NULL) 
+    {
+      // We're in an application thread, and we know our mutexes are locked
+      Yield (from);
+    } 
+  else 
+    {
+      // We're the controller (main) thread
+      Wakeup (to);
+    }
+  if (m_notifySwitch != 0)
+    {
+      m_notifySwitch ();
+    }
+}
+uint32_t 
+PthreadFiberManager::GetStackSize (struct Fiber *fib) const
+{
+  struct PthreadFiber *fiber = (struct PthreadFiber *)fib;
+  return fiber->stack_size;
+}
+void 
+PthreadFiberManager::SetSwitchNotification (void (*fn) (void))
+{
+  m_notifySwitch = fn;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/pthread-fiber-manager.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,37 @@
+#ifndef PTHREAD_FIBER_MANAGER_H
+#define PTHREAD_FIBER_MANAGER_H
+
+#include "fiber-manager.h"
+#include <signal.h>
+#include <list>
+
+namespace ns3 {
+
+struct PthreadFiber;
+
+class PthreadFiberManager : public FiberManager
+{
+public:
+  PthreadFiberManager ();
+  virtual ~PthreadFiberManager ();
+
+  virtual struct Fiber *Create (void (*callback) (void *),
+				void *context,
+				uint32_t stackSize);
+  virtual struct Fiber *CreateFromCaller (void);
+  virtual void Delete (struct Fiber *fiber);
+  virtual void SwitchTo (struct Fiber *from, 
+			 const struct Fiber *to);
+  virtual uint32_t GetStackSize (struct Fiber *fiber) const;
+  virtual void SetSwitchNotification (void (*fn) (void));
+private:
+  static void *Run (void *arg);
+  void Yield (struct PthreadFiber *fiber);
+  void Wakeup (struct PthreadFiber *fiber);
+  void Start (struct PthreadFiber *fiber);
+  void (*m_notifySwitch) (void);
+};
+
+} // namespace ns3
+
+#endif /* PTHREAD_FIBER_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/readversiondef.c	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,109 @@
+#include <elf.h>
+#include <link.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+int main (int argc, char *argv[])
+{
+  const char *filename = argv[1];
+  int fd = open (filename, O_RDONLY);
+  struct stat buf;
+  fstat (fd, &buf);
+  unsigned long file = (unsigned long)mmap (0, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+  if (file == (unsigned long)MAP_FAILED)
+    {
+      exit (1);
+    }
+  ElfW(Ehdr) *header = (ElfW(Ehdr) *)file;
+  ElfW(Shdr) *sh = (ElfW(Shdr)*)(file + header->e_shoff);
+  ElfW(Sym) *symtab = 0;
+  unsigned long n_symtab = 0;
+  ElfW(Half) *versym = 0;
+  ElfW(Verdef) *verdef = 0;
+  char *strtab = 0;
+  int i;
+  for (i = 0; i < header->e_shnum; i++)
+    {
+      if (sh[i].sh_type == SHT_DYNSYM)
+	{
+	  symtab = (ElfW(Sym)*)(file + sh[i].sh_offset);
+	  n_symtab = sh[i].sh_size / sh[i].sh_entsize;
+	}
+      else if (sh[i].sh_type == SHT_STRTAB && strtab == 0)
+	{
+	  // XXX: should check the section name.
+	  strtab = (char*)(file+sh[i].sh_offset);
+	}
+      else if (sh[i].sh_type == SHT_GNU_versym)
+	{
+	  versym = (ElfW(Half)*)(file+sh[i].sh_offset);
+	}
+      else if (sh[i].sh_type == SHT_GNU_verdef)
+	{
+	  verdef = (ElfW(Verdef)*)(file+sh[i].sh_offset);
+	}
+    }
+  if (strtab == 0 || verdef == 0 || 
+      symtab == 0 || n_symtab == 0 || versym == 0)
+    {
+      exit (3);
+    }
+  ElfW(Verdef) *cur, *prev;
+  int local_passthru_printed = 0;
+  for (prev = 0, cur = verdef;
+       cur != prev; 
+       prev = cur, cur = (ElfW(Verdef)*)(((unsigned long)cur)+cur->vd_next))
+    {
+      assert (cur->vd_version == 1);
+      assert (cur->vd_cnt == 2 || cur->vd_cnt == 1);
+      ElfW(Verdaux) *first = (ElfW(Verdaux)*)(((unsigned long)cur)+cur->vd_aux);
+      if (cur->vd_flags & VER_FLG_BASE)
+	{
+	  continue;
+	}
+      printf ("%s {\n", strtab + first->vda_name);
+      int has_one_symbol = 0;
+      for (i = 0; i < n_symtab; i++)
+	{
+	  if (symtab[i].st_name == 0 || symtab[i].st_value == 0)
+	    {
+	      continue;
+	    }
+	  ElfW(Half) ver = versym[i];
+	  if (cur->vd_ndx == ver)
+	    {
+	      if (!has_one_symbol)
+		{
+		  has_one_symbol = 1;
+		  printf ("global:\n");
+		}
+	      printf ("\t%s;\n", strtab + symtab[i].st_name);
+	    }
+	}
+      if (cur->vd_cnt == 1)
+	{
+	  if (!local_passthru_printed)
+	    {
+	      local_passthru_printed = 1;
+	      printf ("local:*;\n};\n");
+	    }
+	  else
+	    {
+	      printf ("};\n");
+	    }
+	}
+      else
+	{
+	  ElfW(Verdaux) *parent = (ElfW(Verdaux)*)(((unsigned long)first)+first->vda_next);
+	  printf ("} %s;\n", strtab + parent->vda_name);
+	}
+    }
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/rr-task-scheduler.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,72 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2008 INRIA
+ *
+ * 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 "rr-task-scheduler.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE("RrTaskScheduler");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (RrTaskScheduler);
+
+TypeId 
+RrTaskScheduler::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::RrTaskScheduler")
+    .SetParent<TaskScheduler> ()
+    .AddConstructor<RrTaskScheduler> ()
+    ;
+  return tid;
+}
+RrTaskScheduler::RrTaskScheduler ()
+{}
+
+struct Task *
+RrTaskScheduler::PeekNext (void)
+{
+  if (m_active.empty ())
+    {
+      return 0;
+    }
+  struct Task *task = m_active.front ();
+  NS_LOG_DEBUG ("next=" << task);
+  return task;
+}
+void 
+RrTaskScheduler::DequeueNext (void)
+{
+  NS_LOG_FUNCTION (this);
+  NS_ASSERT (!m_active.empty ());
+  m_active.pop_front ();
+}
+void 
+RrTaskScheduler::Enqueue (struct Task *task)
+{
+  NS_LOG_FUNCTION (this << task);
+  m_active.push_back (task);
+}
+void 
+RrTaskScheduler::Dequeue (struct Task *task)
+{
+  NS_LOG_FUNCTION (this << task);
+  m_active.remove (task);
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/rr-task-scheduler.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,47 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005,2008 INRIA
+ *
+ * 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 RR_TASK_SCHEDULER_H
+#define RR_TASK_SCHEDULER_H
+
+#include "task-scheduler.h"
+#include <list>
+
+namespace ns3 {
+
+/**
+ * \brief Round Robin scheduler
+ */
+class RrTaskScheduler : public TaskScheduler
+{
+public:
+  static TypeId GetTypeId (void);
+  RrTaskScheduler ();
+
+  virtual Task *PeekNext (void);
+  virtual void DequeueNext (void);
+  virtual void Enqueue (Task *task);
+  virtual void Dequeue (Task *task);
+private:
+  std::list<struct Task *> m_active;
+};
+
+} // namespace ns3
+
+#endif /* RR_TASK_SCHEDULER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-alloc.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,66 @@
+#include "simu-stdlib.h"
+#include "utils.h"
+#include "process.h"
+#include "alloc.h"
+#include "ns3/log.h"
+#include <string.h>
+
+NS_LOG_COMPONENT_DEFINE ("SimuAlloc");
+
+using namespace ns3;
+
+void *simu_calloc(size_t nmemb, size_t size)
+{
+  GET_CURRENT (nmemb << size);
+  void *ptr = simu_malloc (nmemb * size);
+  memset (ptr, 0, nmemb * size);
+  return ptr;
+}
+void *simu_malloc(size_t size)
+{
+  GET_CURRENT (size);
+  size += sizeof (size_t);
+  uint8_t *buffer = current->process->alloc->Malloc (size);
+  memcpy (buffer, &size, sizeof (size_t));
+  buffer += sizeof (size_t);
+  NS_LOG_DEBUG ("alloc=" << (void*)buffer);
+  return buffer;  
+}
+void simu_free(void *ptr)
+{
+  GET_CURRENT (ptr);
+  if (ptr == 0)
+    {
+      return;
+    }
+  uint8_t *buffer = (uint8_t*)ptr;
+  size_t size;
+  buffer -= sizeof (size_t);
+  memcpy (&size, buffer, sizeof (size_t));
+  current->process->alloc->Free (buffer, size);
+}
+void *simu_realloc(void *ptr, size_t size)
+{
+  GET_CURRENT (ptr << size);
+  if (ptr == 0 && size == 0)
+    {
+      return 0;
+    }
+  if (ptr == 0)
+    {
+      return simu_malloc (size);
+    }
+  size_t oldSize;
+  uint8_t *buffer = (uint8_t*)ptr;
+  buffer -= sizeof (size_t);
+  size += sizeof (size_t);
+  memcpy (&oldSize, buffer, sizeof (size_t));
+  if (size <= oldSize)
+    {
+      return ptr;
+    }
+  buffer = current->process->alloc->Realloc (buffer, oldSize, size);
+  memcpy (buffer, &size, sizeof (size_t));
+  buffer += sizeof (size_t);
+  return buffer;  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-clock.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#ifndef SIMU_CLOCK_H
+#define SIMU_CLOCK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SIMU_CLOCKS_PER_SEC (1000000)
+
+typedef int simu_clock_t;
+
+simu_clock_t simu_clock (void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_CLOCK_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-cxa.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,54 @@
+#include "simu-cxa.h"
+#include "utils.h"
+#include "process.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("SimuCxa");
+
+using namespace ns3;
+
+int 
+simu__cxa_atexit (void (*func) (void *), void *arg, void *d)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << func << arg << d);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  struct AtExitHandler handler;
+  handler.type = AtExitHandler::CXA;
+  handler.value.cxa.fn = func;
+  handler.value.cxa.arg = arg;
+  handler.value.cxa.d = d;
+  current->process->atExitHandlers.push_back (handler);
+  return 0;
+}
+void simu__cxa_finalize (void *d)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << d);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  // from back to front to ensure that we process all this in the right order
+  // which is from last registered to first registered.
+  // and that we handle the case where one of the atexit handlers
+  // recursively calls atexit or __cxa_atexit.
+  while (!current->process->atExitHandlers.empty ())
+    {
+      struct AtExitHandler handler = current->process->atExitHandlers.back ();
+      current->process->atExitHandlers.pop_back ();
+      switch (handler.type)
+	{
+	case AtExitHandler::CXA:
+	  if (d == 0 || handler.value.cxa.d == d)
+	    {
+	      handler.value.cxa.fn (handler.value.cxa.arg);
+	    }
+	  break;
+	case AtExitHandler::NORMAL:
+	  if (d == 0)
+	    {
+	      handler.value.normal ();
+	    }
+	  break;
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-cxa.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,15 @@
+#ifndef SIMU_CXA_H
+#define SIMU_CXA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu__cxa_atexit (void (*func) (void *), void *arg, void *d);
+void simu__cxa_finalize (void *d);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_CXA_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-debug.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,70 @@
+#include "utils.h"
+#include "process.h"
+#include "loader-factory.h"
+#include "task-manager.h"
+#include "ns3/log.h"
+#include "ns3/breakpoint.h"
+#include <list>
+#include <algorithm>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SimuDebug");
+
+static std::list<uint32_t> g_simu_debug_nodes;
+
+void * simu_debug_lookup (char *str)
+{
+  Thread *current = Current ();
+  if (current == 0)
+    {
+      return 0;
+    }
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << str);
+  NS_ASSERT (current != 0);
+  return current->process->loader->Lookup (current->process->mainHandle, str);
+}
+uint32_t simu_debug_nodeid (void)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId ());
+  NS_ASSERT (Current () != 0);
+  return UtilsGetNodeId ();
+}
+const char *simu_debug_processname (void)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId ());
+  NS_ASSERT (current != 0);
+  return current->process->name.c_str ();
+}
+bool simu_debug_is_node (uint32_t node)
+{
+  return std::find (g_simu_debug_nodes.begin (), 
+		    g_simu_debug_nodes.end (), 
+		    node) != g_simu_debug_nodes.end ();
+}
+static void simu_debug_switch_notify (void)
+{
+  if (Current () != 0 &&
+      simu_debug_is_node (simu_debug_nodeid ()))
+    {
+      NS_BREAKPOINT ();
+    }
+}
+void simu_debug_monitor (uint32_t node)
+{
+  if (simu_debug_is_node (node))
+    {
+      return;
+    }
+  g_simu_debug_nodes.push_back (node);
+  TaskManager::Current ()->SetSwitchNotify (simu_debug_switch_notify);
+}
+void simu_debug_unmonitor (uint32_t node)
+{
+  g_simu_debug_nodes.remove (node);
+  if (g_simu_debug_nodes.empty ())
+    {
+      TaskManager::Current ()->SetSwitchNotify (0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-env.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,154 @@
+#include "simu-stdlib.h"
+#include "utils.h"
+#include "process.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <string.h>
+
+NS_LOG_COMPONENT_DEFINE ("SimuEnv");
+
+using namespace ns3;
+
+char *simu_getenv(const char *name)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << name);
+  NS_ASSERT (Current () != 0);
+  struct Thread *current = Current ();
+  int namelen = strlen (name);
+  char ***penvp = current->process->penvp;
+  char **cur;
+  for (cur = *penvp; *cur != 0; cur++)
+    {
+      char *equal = strchr (*cur, '=');
+      if (equal == 0)
+	{
+	  continue;
+	}
+      if (strncmp (*cur, name, namelen) != 0)
+	{
+	  continue;
+	}
+      return equal+1;
+    }
+  return 0;
+}
+int simu_putenv(char *string)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << string);
+  NS_ASSERT (Current () != 0);
+  struct Thread *current = Current ();
+  char ***penvp = current->process->penvp;
+  // first, locate '=' sign.
+  char *name = strchr (string, '=');
+  if (name == 0)
+    {
+      // no '=' so, this is a request to clear the corresponding
+      // entry in the env array
+      return simu_unsetenv (string);
+    }
+  size_t namelen = ((unsigned long)name) - ((unsigned long)string) + 1;
+  // try to find requested name in env array
+  char **cur;
+  int len = 0;
+  bool found = false;
+  for (cur = *penvp; *cur != 0; cur++)
+    {
+      if (strncmp (string, *cur, namelen) == 0)
+	{
+	  // found it, and replace.
+	  *cur = string;
+	  found = true;
+	}
+      len++;
+    }
+  if (found)
+    {
+      return 0;
+    }
+  // not found: we are going to add it now.
+  char **newEnvp = (char**)malloc (sizeof(char*)*(len+1+1));
+  current->process->allocated.push_back (newEnvp);
+  memcpy (newEnvp, *penvp, sizeof(char*)*(len));
+  newEnvp[len] = string;
+  newEnvp[len+1] = 0;
+  *penvp = newEnvp;
+  return 0;
+}
+int simu_setenv(const char *name, const char *value, int overwrite)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << name << value << overwrite);
+  NS_ASSERT (Current () != 0);
+  struct Thread *current = Current ();
+  char ***penvp = current->process->penvp;
+  if (overwrite != 0)
+    {
+      simu_unsetenv (name);
+    }
+  int namelen = strlen (name);
+  char **cur;
+  int len = 0;
+  for (cur = *penvp; *cur != 0; cur++)
+    {
+      if (overwrite == 0 && strncmp (*cur, name, namelen) == 0)
+	{
+	  // there is already an entry which matches this name and
+	  // we cannot remove it so, we are done.
+	  return 0;
+	}
+      len++;
+    }
+  char **newEnvp = (char**)malloc (sizeof(char*)*(len+1+1));
+  current->process->allocated.push_back (newEnvp);
+  memcpy (newEnvp, *penvp, sizeof(char*)*(len));
+  int valuelen = strlen (value);
+  char *str = (char*)malloc (namelen + 1 + valuelen + 1);
+  current->process->allocated.push_back (str);
+  memcpy (str, name, namelen);
+  str[namelen] = '=';
+  memcpy (str+namelen+1,value, valuelen);
+  str[namelen+1+valuelen] = 0;
+  newEnvp[len] = str;
+  newEnvp[len+1] = 0;
+  *penvp = newEnvp;
+  return 0;
+}
+int simu_unsetenv(const char *name)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << name);
+  NS_ASSERT (Current () != 0);
+  struct Thread *current = Current ();
+  char ***penvp = current->process->penvp;
+  int namelen = strlen (name);
+  char **cur;
+  for (cur = *penvp; *cur != 0;)
+    {
+      char *equal = strchr (*cur, '=');
+      if (equal == 0)
+	{
+	  continue;
+	}
+      if (strncmp (*cur, name, namelen) != 0)
+	{
+	  cur++;
+	  continue;
+	}
+      char **i, **prev;
+      *cur = *(cur+1);
+      for (i = cur+1, prev = cur; *i != 0; i++, prev++)
+	{
+	  *prev = *i;
+	}
+    }
+  return 0;
+}
+int simu_clearenv(void)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId ());
+  NS_ASSERT (Current () != 0);
+  struct Thread *current = Current ();
+  char ***penvp = current->process->penvp;
+  *penvp = (char**)malloc (sizeof (char *));
+  current->process->allocated.push_back (*penvp);
+  **penvp = 0;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-errno.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#ifndef ERRNO_H
+#define ERRNO_H
+
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define simu_errno (*simu_get_errno ())
+
+int *simu_get_errno (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ERRNO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-fcntl.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,20 @@
+#ifndef SIMU_FCNTL_H
+#define SIMU_FCNTL_H
+
+#include <stdarg.h>
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_open (const char *path, int flags, mode_t mode);
+int simu_creat (const char *path, mode_t mode);
+int simu_fcntl(int fd, int cmd, unsigned long arg);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_FCNTL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,823 @@
+#define _LARGEFILE64_SOURCE 1
+#include "dce-manager.h"
+#include "process.h"
+#include "utils.h"
+#include "unix-fd.h"
+#include "unix-file-fd.h"
+#include "socket-fd-factory.h"
+#include "waiter.h"
+#include "simu-fcntl.h"
+#include "simu-unistd.h"
+#include "simu-poll.h"
+#include "simu-stdio.h"
+#include "sys/simu-socket.h"
+#include "sys/simu-ioctl.h"
+#include "sys/simu-stat.h"
+#include "sys/simu-mman.h"
+#include "sys/simu-select.h"
+#include "ns3/log.h"
+#include "ns3/event-id.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include <fcntl.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include "ns3/node.h"
+
+NS_LOG_COMPONENT_DEFINE ("SimuFd");
+
+
+#ifdef _K_SS_MAXSIZE
+#define SOCK_MAX_ADDRESS_SIZE _K_SS_MAXSIZE
+#else
+#define SOCK_MAX_ADDRESS_SIZE 128
+#endif
+
+#define DEFINE_FORWARDER_PATH(name, pathname, ...)			\
+  {									\
+    Thread *current = Current ();					\
+    NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << pathname);	\
+    NS_ASSERT (Current () != 0);						\
+    									\
+    if (std::string (pathname) == std::string(""))			\
+      {									\
+        current->err = ENOENT;						\
+	return -1;							\
+      }									\
+    std::string fullpath = UtilsGetRealFilePath (pathname);	\
+    int status = ::name (fullpath.c_str (), ##__VA_ARGS__);		\
+    if (status == -1)							\
+      {									\
+	current->err = errno;						\
+	return -1;							\
+      }									\
+    return status;							\
+  }
+
+
+using namespace ns3;
+
+int simu_open (const char *path, int flags, mode_t mode)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << path << flags);
+  NS_ASSERT (current != 0);
+
+  if (std::string (path) == "")
+    {
+      current->err = ENOENT;
+      return -1;
+    }
+
+  int fd = UtilsAllocateFd ();
+  if (fd == -1)
+    {
+      current->err = EMFILE;
+      return -1;
+    }
+
+  std::string fullpath = UtilsGetRealFilePath (path);
+  int realFd = ::open (fullpath.c_str (), flags, mode);
+  if (realFd == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  UnixFd *unixFd = new UnixFileFd (realFd);
+  current->process->openFiles.push_back (std::make_pair(fd,unixFd));
+  return fd;
+}
+int simu_creat (const char *path, mode_t mode)
+{
+  return simu_open (path, O_CREAT|O_WRONLY|O_TRUNC, mode);
+}
+
+int simu_unlink (const char *pathname)
+{
+  DEFINE_FORWARDER_PATH (unlink, pathname);
+}
+int simu_mkdir(const char *pathname, mode_t mode)
+{
+  DEFINE_FORWARDER_PATH (mkdir, pathname, mode);
+}
+int simu_rmdir(const char *pathname)
+{
+  DEFINE_FORWARDER_PATH (rmdir, pathname);
+}
+int simu_close (int fd)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fd);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = 0;
+  if (unixFd->GetReferenceCount () == 1)
+    {
+      retval = unixFd->Close ();
+    }
+  unixFd->Unref ();
+  current->process->openFiles[index].second = 0;
+  current->process->openFiles[index].first = -1;
+  current->process->openFiles.erase(current->process->openFiles.begin() + index);
+  return retval;
+}
+int simu_isatty(int fd)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Isatty ();
+  return retval;
+}
+ssize_t simu_send(int fd, const void *buf, size_t len, int flags)
+{
+  NS_LOG_FUNCTION (fd << buf << len << flags);
+  return simu_sendto (fd, buf, len, flags, 0, 0);
+}
+ssize_t simu_sendto(int fd, const void *buf, size_t len, int flags,
+		    const struct sockaddr *to, socklen_t tolen)
+{
+  NS_LOG_FUNCTION (Current () << fd << buf << len << flags << to << tolen);
+  NS_ASSERT (Current () != 0);
+  struct msghdr msg;
+  struct iovec iov;
+  msg.msg_control = 0;
+  msg.msg_controllen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iov;
+  iov.iov_len = len;
+  iov.iov_base = (void *)buf;
+  msg.msg_name = (void *)to;
+  msg.msg_namelen = tolen;
+  ssize_t retval = simu_sendmsg (fd, &msg, flags);
+  return retval;
+}
+ssize_t simu_sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << msg << flags);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  ssize_t retval = unixFd->Sendmsg (msg, flags);
+  return retval;
+}
+int simu_ioctl (int fd, int request, char *argp)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << request << argp);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Ioctl (request, argp);
+  return retval;
+}
+int simu_poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fds << nfds << timeout);
+  NS_ASSERT (current != 0);
+  for (uint32_t i = 0; i < nfds; ++i)
+    {
+      // initialize all outgoing events.
+      fds[i].revents = 0;
+    }
+  for (uint32_t i = 0; i < nfds; ++i)
+    {
+      int index = UtilsSearchOpenFd (fds[i].fd);
+      if (index == -1)
+	{
+	  current->err = EBADF;
+	  return -1;
+	}
+    }
+  bool mustWait = false;
+  Waiter waiter;
+  for (uint32_t i = 0; i < nfds; ++i)
+    {
+      int index = UtilsSearchOpenFd (fds[i].fd);
+      NS_ASSERT (index != -1);
+      UnixFd *unixFd = current->process->openFiles[index].second;
+      if (fds[i].events & POLLIN && !unixFd->CanRecv ())
+	{
+	  unixFd->SetRecvWaiter (&waiter);
+	  mustWait = true;
+	}
+      if (fds[i].events & POLLOUT && !unixFd->CanSend ())
+	{
+	  unixFd->SetSendWaiter (&waiter);
+	  mustWait = true;
+	}
+    }
+  if (mustWait)
+    {
+      waiter.SetTimeout (MilliSeconds (timeout));
+      if (!waiter.WaitDoSignal ())
+	{
+	  // current->err set by call above.
+	  for (uint32_t i = 0; i < nfds; ++i)
+	    {
+	      // make sure we remove all waiters we setup earlier.
+	      int index = UtilsSearchOpenFd (fds[i].fd);
+	      NS_ASSERT (index != -1);
+	      UnixFd *unixFd = current->process->openFiles[index].second;
+	      if (fds[i].events & POLLOUT)
+		{
+		  unixFd->SetSendWaiter (0);
+		}
+	      if (fds[i].events & POLLIN)
+		{
+		  unixFd->SetRecvWaiter (0);
+		}
+	    }
+	  return -1;
+	}
+    }
+  int retval = 0;
+  for (uint32_t i = 0; i < nfds; ++i)
+    {
+      int index = UtilsSearchOpenFd (fds[i].fd);
+      NS_ASSERT (index != -1);
+      UnixFd *unixFd = current->process->openFiles[index].second;
+      if (fds[i].events & POLLOUT && unixFd->CanSend ())
+	{
+	  unixFd->SetSendWaiter (0);
+	  fds[i].revents |= POLLOUT;
+	  retval++;
+	}
+      if (fds[i].events & POLLIN && unixFd->CanRecv ())
+	{
+	  unixFd->SetRecvWaiter (0);
+	  fds[i].revents |= POLLIN;
+	  retval++;
+	}
+    }
+  return retval;
+}
+int simu_select(int nfds, fd_set *readfds, fd_set *writefds,
+                  fd_set *exceptfds, struct timeval *timeout)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << nfds << timeout);
+  NS_ASSERT (current != 0);
+
+  if (nfds == -1)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  if (readfds == 0 && writefds == 0 && exceptfds == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  if (timeout)
+    {
+      if(timeout->tv_sec < 0 || timeout->tv_usec < 0)
+        {
+          current->err = EINVAL;
+          return -1;
+        }
+    }
+  for (int fd = 0; fd < nfds; fd++)
+    {
+      if ((readfds != 0 && FD_ISSET(fd, readfds))
+	  ||(writefds != 0 &&  FD_ISSET (fd, writefds))
+	  ||(exceptfds != 0 && FD_ISSET (fd, exceptfds)))
+        {
+          int index = UtilsSearchOpenFd (fd);
+          if (index == -1)
+            {
+              current->err = EBADF;
+              return -1;
+            }
+	}
+    }
+
+  bool mustWait = false;
+  Waiter waiter;
+  for (int fd = 0; fd < nfds; fd++)
+    {
+      if (readfds != 0 && FD_ISSET(fd, readfds))
+	{
+          int index = UtilsSearchOpenFd (fd);
+	  NS_ASSERT (index != -1);
+	  UnixFd *unixFd = current->process->openFiles[index].second;
+	  if (!unixFd->CanRecv ())
+	    {
+              unixFd->SetRecvWaiter (&waiter);
+              mustWait = true;
+	    }
+	}
+      else if (writefds != 0 &&  FD_ISSET (fd, writefds))
+	{
+          int index = UtilsSearchOpenFd (fd);
+	  NS_ASSERT (index != -1);
+	  UnixFd *unixFd = current->process->openFiles[index].second;
+	  if (!unixFd->CanSend ())
+	    {
+              unixFd->SetSendWaiter (&waiter);
+              mustWait = true;
+	    }
+
+	}
+    }
+  if (timeout && (timeout->tv_sec == 0) && (timeout->tv_usec == 0))
+    {
+      mustWait = false;
+    }
+
+  Time timeoutLeft = Seconds (0.0);
+  if (mustWait)
+    {
+      waiter.SetTimeout (UtilsTimevalToTime(timeout));
+      if (!waiter.WaitDoSignal ())
+	{
+	  // current->err set by call above
+	  for (int fd = 0; fd < nfds; fd++)
+	    {
+	      // cleanup all waiters setup previously
+	      if (readfds != 0 && FD_ISSET(fd, readfds))
+		{
+		  int index = UtilsSearchOpenFd (fd);
+		  NS_ASSERT (index != -1);
+		  UnixFd *unixFd = current->process->openFiles[index].second;
+		  unixFd->SetRecvWaiter (0);
+		}
+	      else if (writefds != 0 &&  FD_ISSET (fd, writefds))
+		{
+		  int index = UtilsSearchOpenFd (fd);
+		  NS_ASSERT (index != -1);
+		  UnixFd *unixFd = current->process->openFiles[index].second;
+		  unixFd->SetSendWaiter (0);
+		}
+	    }
+	  return -1;
+	}
+      timeoutLeft = waiter.GetTimeoutLeft ();
+    }
+
+  int retval = 0;
+  fd_set rd, wt;
+  FD_ZERO(&rd);
+  FD_ZERO(&wt);
+
+   for (int fd = 0; fd < nfds; fd++)
+    {    
+      int index = UtilsSearchOpenFd (fd);
+      if (index == -1)
+        continue;
+      UnixFd *unixFd = current->process->openFiles[index].second;
+      if (readfds != 0 && FD_ISSET(fd, readfds))
+        {
+	  unixFd->SetRecvWaiter (0);
+	  if (unixFd->CanRecv ())
+	    {
+	      FD_SET(fd, &rd);
+	      retval++;
+	    }
+        }
+      if (writefds != 0 && FD_ISSET(fd, writefds))
+        {
+	  unixFd->SetSendWaiter (0);
+	  if (unixFd->CanSend ())
+	    {
+	      FD_SET(fd, &wt);
+	      retval ++;
+	    }
+        }
+    }
+
+  if (readfds != 0)
+    {
+      memcpy(readfds, &rd, sizeof(rd));
+    }
+  if (writefds != 0)
+    {
+      memcpy(writefds, &wt, sizeof(wt));
+    }
+  if (exceptfds != 0)
+    {
+      FD_ZERO(exceptfds);
+    }
+  if (timeout != 0)
+    {
+      *timeout = UtilsTimeToTimeval (timeoutLeft);
+    }
+  return retval;
+}
+
+ssize_t simu_write (int fd, const void *buf, size_t count)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fd << buf << count);
+  Thread *current = Current ();
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      NS_LOG_DEBUG ("write error");
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Write (buf, count);
+  NS_LOG_DEBUG ("write " << retval << "bytes");
+  return retval;
+}
+
+ssize_t simu_writev (int fd, const struct iovec *iov, int iovcnt)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << iov << iovcnt);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+
+  size_t count = 0;
+  for (int i = 0; i < iovcnt; ++i)
+    count += iov[i].iov_len;
+
+  if (count == 0) 
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+
+  char buf[count], *bufp = buf;
+  for (int i = 0; i < iovcnt; ++i)
+    {
+      memcpy (bufp, iov[i].iov_base, iov[i].iov_len);
+      bufp += iov[i].iov_len;
+    }
+
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Write (buf, count);
+
+  return retval;
+}
+
+ssize_t simu_read (int fd, void *buf, size_t count)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << buf << count);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Read (buf, count);
+  return retval;
+}
+int simu_socket (int domain, int type, int protocol)
+{
+  Thread *current = Current ();
+  DceManager *manager = current->process->manager;
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << domain << type << protocol);
+  NS_ASSERT (current != 0);
+  NS_ASSERT (manager != 0);
+
+  int fd = UtilsAllocateFd ();
+  if (fd == -1)
+    {
+      current->err = EMFILE;
+      return -1;
+    }
+
+  Ptr<SocketFdFactory>  factory = manager->GetObject<SocketFdFactory> ();
+  UnixFd *socket = factory->CreateSocket (domain, type, protocol);
+  current->process->openFiles.push_back (std::make_pair (fd, socket));
+  return fd;
+}
+int simu_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << my_addr << addrlen);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Bind (my_addr, addrlen);
+  return retval;
+}
+int simu_connect (int fd, const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << my_addr << addrlen);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Connect (my_addr, addrlen);
+  return retval;
+}
+int simu_listen (int sockfd, int backlog)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sockfd << backlog);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (sockfd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Listen (backlog);
+  return retval;
+}
+int simu_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sockfd << addr << addrlen);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (sockfd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Accept (addr, addrlen);
+  return retval;  
+}
+int simu_shutdown(int s, int how)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << s << how);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (s);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Shutdown (how);
+  return retval;
+}
+ssize_t simu_recv (int fd, void *buf, size_t count, int flags)
+{
+  NS_LOG_FUNCTION (fd << buf << count << flags);
+  return simu_recvfrom (fd, buf, count, flags, 0, 0);
+}
+ssize_t simu_recvfrom(int fd, void *buf, size_t len, int flags,
+		      struct sockaddr *from, socklen_t *fromlen)
+{
+  NS_LOG_FUNCTION (fd << buf << len << flags << from << fromlen);
+  uint8_t address[SOCK_MAX_ADDRESS_SIZE];
+  struct msghdr msg;
+  struct iovec iov;
+  msg.msg_control = 0;
+  msg.msg_controllen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iov;
+  iov.iov_len = len;
+  iov.iov_base = buf;
+  msg.msg_name = address;
+  msg.msg_namelen = SOCK_MAX_ADDRESS_SIZE;
+  ssize_t retval = simu_recvmsg (fd, &msg, flags);
+  if (retval != -1 && from != 0)
+    {
+      if (*fromlen < msg.msg_namelen)
+	{
+	  Thread *current = Current ();
+	  current->err = EINVAL;
+	  return -1;
+	}
+      else
+	{
+	  *fromlen = msg.msg_namelen;
+	  memcpy (from, msg.msg_name, msg.msg_namelen);
+	}
+    }
+  return retval;
+}
+ssize_t simu_recvmsg(int fd, struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << msg << flags);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  ssize_t retval = unixFd->Recvmsg (msg, flags);
+  return retval;
+}
+int simu_setsockopt(int fd, int level, int optname,
+		    const void *optval, socklen_t optlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << level << optname << optval << optlen);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Setsockopt (level, optname, optval, optlen);
+  return retval;
+}
+int simu_getsockopt(int fd, int level, int optname,
+		    void *optval, socklen_t *optlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd << level << optname << optval << optlen);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Getsockopt (level, optname, optval, optlen);
+  return retval;
+}
+int simu_getsockname(int fd, struct sockaddr *name, socklen_t *namelen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << name << namelen);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Getsockname (name, namelen);
+  return retval;
+}
+int simu_getpeername(int fd, struct sockaddr *name, socklen_t *namelen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << name << namelen);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Getpeername (name, namelen);
+  return retval;
+}
+int simu_dup(int oldfd)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << oldfd);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (oldfd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  int fd = UtilsAllocateFd ();
+  if (fd == -1)
+    {
+      current->err = EMFILE;
+      return -1;
+    }
+
+  current->process->openFiles.push_back 
+    (std::make_pair (fd, current->process->openFiles[index].second));
+  return fd;
+}
+int simu_dup2(int oldfd, int newfd)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << oldfd << newfd);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (oldfd);
+  if (index == -1 || 
+      newfd > MAX_FDS)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  if (UtilsSearchOpenFd (newfd) != -1)
+    {
+      simu_close (newfd);
+    }
+
+  current->process->openFiles.push_back 
+    (std::make_pair (newfd, current->process->openFiles[index].second));
+  return newfd;
+}
+void *simu_mmap64 (void *start, size_t length, int prot, int flags,
+		   int fd, off64_t offset)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << start << length << prot << flags << fd << offset);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return MAP_FAILED;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  void * retval = unixFd->Mmap (start, length, prot, flags, offset);
+  return retval;  
+}
+int simu_munmap(void *start, size_t length)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << start << length);
+  NS_ASSERT (current != 0);
+  int retval = ::munmap (start, length);
+  if (retval == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return 0;
+}
+off_t simu_lseek(int fildes, off_t offset, int whence)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fildes << offset << whence);
+  return simu_lseek64 (fildes, offset, whence);
+}
+off64_t simu_lseek64(int fildes, off64_t offset, int whence)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fildes << offset << whence);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fildes);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  off64_t retval = unixFd->Lseek (offset, whence);
+  NS_LOG_DEBUG (retval);
+  return retval;    
+}
+int simu_fcntl(int fd, int cmd, unsigned long arg)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fd << cmd << arg);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  // XXX: we should handle specially some fcntl commands.
+  // For example, FD_DUP, etc.
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Fcntl (cmd, arg);
+  return retval;    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-global-variables.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,26 @@
+#include "simu-global-variables.h"
+#include "process.h"
+#include "utils.h"
+#include "simu-stdio.h"
+
+using namespace ns3;
+
+void simu_global_variables_setup (struct SimuGlobalVariables *variables)
+{
+  struct Process *process = Current ()->process;
+  if (process->pstdin != 0)
+    {
+      // protect against multiple calls to this function.
+      return;
+    }
+  process->pstdin = variables->pstdin;
+  process->pstdout = variables->pstdout;
+  process->pstderr = variables->pstderr;
+  process->penvp = variables->penvp;
+  // Now, we initialize the process variables
+  *process->pstdin = simu_fdopen (0, "r");
+  *process->pstdout = simu_fdopen (1, "w");
+  *process->pstderr = simu_fdopen (2, "w");
+  *process->penvp = process->originalEnvp;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-global-variables.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,26 @@
+#ifndef SIMU_GLOBAL_VARIABLES_H
+#define SIMU_GLOBAL_VARIABLES_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct SimuGlobalVariables
+{
+  FILE **pstdin;
+  FILE **pstdout;
+  FILE **pstderr;
+  char ***penvp;
+};
+
+void simu_global_variables_setup (struct SimuGlobalVariables *variables);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_GLOBAL_VARIABLES_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-netdb.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,116 @@
+#include "simu-netdb.h"
+#include "utils.h"
+#include "simu-stdlib.h"
+#include "simu-string.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/ipv4-address.h"
+#include <string.h>
+
+NS_LOG_COMPONENT_DEFINE ("SimuNetDb");
+
+using namespace ns3;
+
+struct hostent *simu_gethostbyname(const char *name)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << name);
+  NS_ASSERT (Current () != 0);
+  static struct hostent host;
+  static uint32_t addr;
+  static char *alias_end = 0;
+  static char *addr_list[2];
+
+
+  Ipv4Address ipv4 = Ipv4Address (name);
+  addr = htonl (ipv4.Get ());
+
+  //XXX: We do not implement dns lookup here for now. We just 
+  // interpret simple ip strings.
+
+  host.h_name = (char *)name;
+  host.h_addrtype = AF_INET;
+  host.h_aliases = &alias_end;
+  host.h_length = 4;
+  host.h_addr_list = addr_list;
+  addr_list[0] = (char *)&addr;
+  addr_list[1] = 0;
+  return &host;
+}
+struct hostent *simu_gethostbyname2(const char *name, int af)
+{
+  NS_ASSERT (af == AF_INET);
+  return simu_gethostbyname (name);
+}
+int simu_getaddrinfo(const char *node, const char *service,
+		     const struct addrinfo *hints,
+		     struct addrinfo **res)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << node << service << hints << res);
+  NS_ASSERT (Current () != 0);
+  struct addrinfo *tmp = 0;
+  int status = ::getaddrinfo (node, service, hints, &tmp);
+  // copy outgoing data structure so that the memory is allocated from the calling process memory pool.
+  struct addrinfo *cur, *prev, *head;
+  head = 0;
+  prev = 0;
+  for (cur = tmp; cur != 0; cur = cur->ai_next)
+    {
+      struct addrinfo *copy = (struct addrinfo*)simu_malloc (sizeof(struct addrinfo));
+      memcpy (copy, cur, sizeof (struct addrinfo));
+      copy->ai_addr = (struct sockaddr*)simu_malloc (cur->ai_addrlen);
+      if (cur->ai_canonname != 0)
+	{
+	  copy->ai_canonname = simu_strdup (cur->ai_canonname);
+	}
+      else
+	{
+	  copy->ai_canonname = 0;
+	}
+      memcpy (copy->ai_addr, cur->ai_addr, cur->ai_addrlen);
+      if (prev != 0)
+	{
+	  prev->ai_next = copy;
+	}
+      else
+	{
+	  head = copy;
+	}
+      prev = copy;
+    }
+  if (prev != 0)
+    {
+      prev->ai_next = 0;
+    }
+  if (status == 0)
+    {
+      *res = head;
+    }
+  else
+    {
+      memset (*res, 0, sizeof (struct addrinfo));
+    }
+  ::freeaddrinfo (tmp);
+  return status;
+}
+void simu_freeaddrinfo(struct addrinfo *res)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << res);
+  NS_ASSERT (Current () != 0);
+  struct addrinfo *cur, *next;
+  for (cur = res; cur != 0; cur = next)
+    {
+      next = cur->ai_next;
+      simu_free (cur->ai_addr);
+      if (cur->ai_canonname != 0)
+	{
+	  simu_free (cur->ai_canonname);
+	}
+      simu_free (cur);
+    }
+}
+const char *simu_gai_strerror(int errcode)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << errcode);
+  NS_ASSERT (Current () != 0);
+  return ::gai_strerror (errcode);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-netdb.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,22 @@
+#ifndef SIMU_NETDB_H
+#define SIMU_NETDB_H
+
+#include <netdb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct hostent *simu_gethostbyname(const char *name);
+struct hostent *simu_gethostbyname2(const char *name, int af);
+int simu_getaddrinfo(const char *node, const char *service,
+		     const struct addrinfo *hints,
+		     struct addrinfo **res);
+void simu_freeaddrinfo(struct addrinfo *res);
+const char *simu_gai_strerror(int errcode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_NETDB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-poll.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,16 @@
+#ifndef SIMU_POLL_H
+#define SIMU_POLL_H
+
+#include <poll.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_poll(struct pollfd *fds, nfds_t nfds, int timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_POLL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-pthread-cond.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,207 @@
+#include "simu-pthread.h"
+#include "process.h"
+#include "utils.h"
+#include "dce-manager.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <errno.h>
+
+NS_LOG_COMPONENT_DEFINE ("SimuPthreadCond");
+
+using namespace ns3;
+
+
+static uint32_t
+CondToCid (const pthread_cond_t *cond)
+{
+  NS_ASSERT (sizeof (pthread_cond_t) >= 4);
+  if (cond != 0)
+    {
+      const uint32_t *pcid = (const uint32_t *)cond;
+      return *pcid;
+    }
+  return 0;
+}
+static void 
+CidToCond (uint32_t cid, pthread_cond_t *cond)
+{
+  uint32_t *pcid = (uint32_t *)cond;
+  *pcid = cid;
+}
+static struct Condition *
+PthreadCondInitStatic (pthread_cond_t *cond)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (cond);
+  // This method initializes the condition variable fully when it has been
+  // initialized with PTHREAD_COND_INITIALIZER.
+  struct Condition *condition = new Condition ();
+  condition->cid = current->process->nextCid;
+  current->process->nextCid++;
+  current->process->conditions.push_back (condition);
+  CidToCond (condition->cid, cond);
+  return condition;
+}
+
+static struct Condition *
+SearchCondition (pthread_cond_t *cond)
+{
+  Thread *current = Current ();
+  if (cond == 0)
+    {
+      return 0;
+    }
+  uint32_t cid = CondToCid (cond);
+  if (cid == 0)
+    {
+      struct Condition *condition = PthreadCondInitStatic (cond);
+      return condition;
+    }
+  for (uint32_t i = 0; i < current->process->conditions.size (); ++i)
+    {
+      struct Condition *condition = current->process->conditions[i];
+      if (condition->cid == cid)
+        {
+          return condition;
+        }
+    }
+  return 0;
+}
+
+
+int simu_pthread_cond_init (pthread_cond_t *cond,
+			    const pthread_condattr_t *attr)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << cond << attr);
+  NS_ASSERT (Current () != 0);
+
+  if (cond == 0)
+    {
+      return EINVAL;
+    }
+  PthreadCondInitStatic (cond);
+
+  return 0;
+}
+int simu_pthread_cond_destroy (pthread_cond_t *cond)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << cond);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+
+  struct Condition *condition = SearchCondition (cond);
+  if (condition == 0)
+    {
+      return EINVAL;
+    }
+
+  for (std::vector<struct Condition *>::iterator i = current->process->conditions.begin (); 
+       i != current->process->conditions.end (); ++i)
+    {
+      if (condition == *i)
+        {
+          delete condition;
+          condition = 0;
+          current->process->conditions.erase (i);
+          break;
+        }
+    }
+  NS_ASSERT (condition == 0);
+  CidToCond (2, cond);
+  
+  return 0;
+}
+int simu_pthread_cond_broadcast (pthread_cond_t *cond)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << cond);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+
+  struct Condition *condition = SearchCondition (cond);
+  if (condition == 0)
+    {
+      return EINVAL;
+    }
+
+  for (std::list<Thread *>::const_iterator i = condition->waiting.begin ();
+       i != condition->waiting.end (); i++)
+    {
+      current->process->manager->Wakeup (*i);
+    }
+  condition->waiting.clear ();
+  return 0;
+}
+int simu_pthread_cond_signal (pthread_cond_t *cond)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << cond);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+
+  struct Condition *condition = SearchCondition (cond);
+  if (condition == 0)
+    {
+      return EINVAL;
+    }
+  if (!condition->waiting.empty ())
+    {
+      Thread *thread = condition->waiting.front ();
+      current->process->manager->Wakeup (thread);
+      condition->waiting.pop_front ();
+    }
+  return 0;
+}
+int simu_pthread_cond_timedwait(pthread_cond_t * cond,
+				pthread_mutex_t * mutex,
+				const struct timespec * abstime)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << cond << mutex);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+
+  struct Condition *condition = SearchCondition (cond);
+  if (condition == 0)
+    {
+      return EINVAL;
+    }
+  Time timeout = UtilsTimeToSimulationTime (UtilsTimespecToTime (*abstime));
+  timeout -= Simulator::Now ();
+  timeout = Max (Seconds (0.0), timeout);
+
+  simu_pthread_mutex_unlock (mutex);
+  condition->waiting.push_back (current);
+  Time timeLeft = current->process->manager->Wait (timeout);
+  simu_pthread_mutex_lock (mutex);
+  if (timeLeft.IsZero ())
+    {
+      return ETIMEDOUT;
+    }
+  return 0;
+}
+int simu_pthread_cond_wait(pthread_cond_t * cond,
+			   pthread_mutex_t * mutex)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << cond << mutex);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+
+  struct Condition *condition = SearchCondition (cond);
+  if (condition == 0)
+    {
+      return EINVAL;
+    }
+  simu_pthread_mutex_unlock (mutex);
+  condition->waiting.push_back (current);
+  current->process->manager->Wait ();
+  simu_pthread_mutex_lock (mutex);
+  return 0;
+}
+
+// we don't implement any attribute for condition variables
+int simu_pthread_condattr_init(pthread_condattr_t *attr)
+{
+  return 0;
+}
+int simu_pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-pthread-mutex.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,336 @@
+#include "simu-pthread.h"
+#include "utils.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include <stdint.h>
+#include <errno.h>
+
+NS_LOG_COMPONENT_DEFINE ("PthreadMutex");
+
+using namespace ns3;
+
+struct PthreadMutexAttr
+{
+  uint8_t type;
+};
+
+static uint32_t
+MutexToMid (const pthread_mutex_t *mutex)
+{
+  NS_ASSERT (sizeof (pthread_mutex_t) >= 4);
+  if (mutex != 0)
+    {
+      const uint32_t *pmid = (const uint32_t *)mutex;
+      return *pmid;
+    }
+  return 0;
+}
+static void 
+MidToMutex (uint32_t mid, pthread_mutex_t *mutex)
+{
+  uint32_t *pmid = (uint32_t *)mutex;
+  *pmid = mid;
+}
+
+static void 
+PthreadMutexInitStatic (pthread_mutex_t *mutex)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (mutex);
+  // This method initializes the mutex fully when it has been
+  // initialized with PTHREAD_MUTEX_INITIALIZER.
+  struct Mutex *mtx = new Mutex ();
+  switch (mutex->__data.__kind)
+    {
+    case PTHREAD_MUTEX_RECURSIVE:
+      NS_LOG_DEBUG ("recursive");
+      mtx->type = Mutex::RECURSIVE;
+      break;
+    default:
+      NS_LOG_DEBUG ("normal");
+      mtx->type = Mutex::NORMAL;
+      break;
+    }
+  mtx->mid = current->process->nextMid;
+  current->process->nextMid++;
+  mtx->count = 0;
+  mtx->waiting.clear ();
+  mtx->current = 0;
+  current->process->mutexes.push_back (mtx);  
+  MidToMutex (mtx->mid, mutex);
+}
+
+static struct Mutex *
+SearchMutex (pthread_mutex_t *mutex)
+{
+  Thread *current = Current ();
+  if (mutex == 0)
+    {
+      return 0;
+    }
+  if (MutexToMid (mutex) == 0)
+    {
+      // this is a mutex initialized with PTHREAD_MUTEX_INITIALIZER
+      PthreadMutexInitStatic (mutex);
+    }
+  uint32_t mid = MutexToMid (mutex);
+  for (uint32_t i = 0; i < current->process->mutexes.size (); ++i)
+    {
+      struct Mutex *mtx = current->process->mutexes[i];
+      if (mtx->mid == mid)
+        {
+          return mtx;
+        }
+    }
+  return 0;
+}
+
+int simu_pthread_mutex_init (pthread_mutex_t *mutex,
+			     const pthread_mutexattr_t *attribute)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex << attribute);
+  NS_ASSERT (current != 0);
+  if (mutex == 0)
+    {
+      return EINVAL;
+    }
+  struct PthreadMutexAttr *attr = (struct PthreadMutexAttr *)attribute;
+  if (attr != 0 && 
+      attr->type != PTHREAD_MUTEX_RECURSIVE &&
+      attr->type != PTHREAD_MUTEX_NORMAL)
+    {
+      return EINVAL;
+    }
+  /* Note: there is no way to detect a second attempt to initialize 
+   * a mutex because there is no way to detect the difference between
+   * a mutex initialized correctly and a mutex un-initialized but filled
+   * with random garbage which happens to look like correctly-initialized
+   * data. So, we don't even try to return EBUSY.
+   */
+  struct Mutex *mtx = new Mutex ();
+  mtx->mid = current->process->nextMid;
+  current->process->nextMid++;
+  if (attr == 0 || attr->type != PTHREAD_MUTEX_RECURSIVE)
+    {
+      mtx->type = Mutex::NORMAL;
+    }
+  else if (attr != 0 || attr->type == PTHREAD_MUTEX_RECURSIVE)
+    {
+      mtx->type = Mutex::RECURSIVE;
+    }
+  else
+    {
+      NS_ASSERT (false);
+    }
+  mtx->count = 0;
+  mtx->waiting.clear ();
+  mtx->current = 0;
+  current->process->mutexes.push_back (mtx);
+
+  MidToMutex (mtx->mid, mutex);
+  
+  return 0;
+}
+int simu_pthread_mutex_destroy (pthread_mutex_t *mutex)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
+  NS_ASSERT (current != 0);
+  struct Mutex *mtx = SearchMutex (mutex);
+  if (mtx == 0)
+    {
+      return EINVAL;
+    }
+  if (mtx->current != 0 || !mtx->waiting.empty ())
+    {
+      /* Someone (potentially us) is holding this mutex
+       * or someone is waiting for this mutex.
+       */
+      return EBUSY;
+    }
+  // If no one is holding this mutex, its count should be zero.
+  NS_ASSERT (mtx->count == 0);
+
+  for (std::vector<struct Mutex *>::iterator i = current->process->mutexes.begin (); 
+       i != current->process->mutexes.end (); ++i)
+    {
+      if (mtx == *i)
+        {
+          delete mtx;
+          mtx = 0;
+          current->process->mutexes.erase (i);
+          break;
+        }
+    }
+  NS_ASSERT (mtx == 0);
+  MidToMutex (2, mutex);
+  
+  return 0;
+}
+int simu_pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
+  NS_ASSERT (current != 0);
+  struct Mutex *mtx = SearchMutex (mutex);
+  if (mtx == 0)
+    {
+      return EINVAL;
+    }
+  if (current == mtx->current)
+    {
+      if (mtx->type == Mutex::RECURSIVE)
+        {
+          mtx->count++;
+          return 0;
+        }
+      else if (mtx->type == Mutex::NORMAL)
+        {
+          return EDEADLK;
+        }
+      else
+        {
+          NS_ASSERT (false);
+        }
+    }
+  while (mtx->current != 0)
+    {
+      mtx->waiting.push_back (current);
+      current->process->manager->Wait ();
+      mtx->waiting.remove (current);
+    }
+  NS_ASSERT (mtx->current == 0);
+  mtx->current = current;
+  mtx->count++;
+
+  return 0;
+}
+int simu_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
+  NS_ASSERT (current != 0);
+  struct Mutex *mtx = SearchMutex (mutex);
+  if (mtx == 0)
+    {
+      return EINVAL;
+    }
+  if (mtx->type == Mutex::RECURSIVE)
+    {
+      if (mtx->current == 0)
+        {
+          mtx->current = current;
+          mtx->count++;
+          return 0;
+        }
+      else if (mtx->current == current)
+        {
+          mtx->count++;
+          return 0;
+        }
+      else
+        {
+          return EBUSY;
+        }
+    }
+  else if (mtx->type == Mutex::NORMAL)
+    {
+      if (mtx->current == 0)
+        {
+          mtx->count++;
+          mtx->current = current;
+          return 0;
+        }
+      else
+        {
+          // even if mtx->current == current
+          // according to IEEE Std 1003.1, 2004
+          return EBUSY;
+        }
+    }
+  else
+    {
+      NS_ASSERT (false);
+    }
+  // quiet compiler.
+  return 0;
+}
+int simu_pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << mutex);
+  NS_ASSERT (current != 0);
+  struct Mutex *mtx = SearchMutex (mutex);
+  if (mtx == 0)
+    {
+      return EINVAL;
+    }
+  if (mtx->current == 0 || 
+      mtx->current != current)
+    {
+      return EPERM;
+    }
+  mtx->count--;
+  if (mtx->count == 0)
+    {
+      mtx->current = 0;
+      // Now, we tell the first waiting thread that 
+      // it can potentially take the lock. Note that
+      // there are lots of different possible policies 
+      // here. We could wake up everybody and let the
+      // process scheduler pick the highest priority 
+      // thread, we could attempt to find a better candidate
+      // here locally to avoid waking up lots of threads only
+      // to bring them back to sleep after they wake up because
+      // they just realized that someone stole the lock from
+      // them, etc. What we do, instead, is implement the simplest
+      // "fair" policy by ensuring that every thread
+      // is woken up in FIFO order.
+      Thread *waiting = mtx->waiting.front ();
+      if (waiting != 0)
+        {
+	  current->process->manager->Wakeup (waiting);
+	  // give them a chance to run.
+	  current->process->manager->Yield ();
+        }
+    }
+  return 0;
+}
+int simu_pthread_mutexattr_init (pthread_mutexattr_t *attribute)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << attribute);
+  NS_ASSERT (Current () != 0);
+  if (attribute == 0)
+    {
+      return EINVAL;
+    }
+  NS_ASSERT (sizeof(struct PthreadMutexAttr) <= sizeof (pthread_mutexattr_t));
+  struct PthreadMutexAttr *attr = (struct PthreadMutexAttr *)attribute;
+  attr->type = PTHREAD_MUTEX_NORMAL;
+  return 0;
+}
+int simu_pthread_mutexattr_destroy (pthread_mutexattr_t *attribute)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << attribute);
+  NS_ASSERT (Current () != 0);
+  if (attribute == 0)
+    {
+      return EINVAL;
+    }
+  return 0;
+}
+int simu_pthread_mutexattr_settype (pthread_mutexattr_t *attribute, int kind)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << attribute << kind);
+  NS_ASSERT (Current () != 0);
+  if (attribute == 0)
+    {
+      return EINVAL;
+    }
+  struct PthreadMutexAttr *attr = (struct PthreadMutexAttr *)attribute;
+  attr->type = kind;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-pthread.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,406 @@
+#include "simu-pthread.h"
+#include "simu-signal.h"
+#include "simu-unistd.h"
+#include "dce-manager.h"
+#include "process.h"
+#include "utils.h"
+#include "simu-cxa.h"
+#include "simu-stdio.h"
+#include "loader-factory.h"
+#include "task-manager.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include <errno.h>
+#include <signal.h>
+#include <list>
+
+NS_LOG_COMPONENT_DEFINE ("SimuPthread");
+
+using namespace ns3;
+
+static uint16_t
+PthreadToTid (pthread_t thread_handle)
+{
+  NS_ASSERT (sizeof (pthread_t) >= 4);
+  return (thread_handle >> 16) & 0xffff;
+}
+
+static uint16_t
+PthreadToPid (pthread_t thread_handle)
+{
+  NS_ASSERT (sizeof (pthread_t) >= 4);
+  return thread_handle & 0xffff;
+}
+
+static pthread_t
+PidTidToPthread (uint16_t pid, uint16_t tid)
+{
+  NS_ASSERT (sizeof (pthread_t) >= 4);
+  uint32_t th = tid;
+  th <<= 16;
+  th |= pid;
+  return th;
+}
+
+static void
+CleanupPthreadKeys (void)
+{
+  Thread *current = Current ();
+  // From this function, we perform process cleanup which _requires_
+  // a user context. here delete the keys of each thread which might
+  // require calling a key destructor in the process.
+  for (std::list<ThreadKeyValue>::iterator j = current->keyValues.begin (); 
+       j != current->keyValues.end (); ++j)
+    {
+      NS_LOG_DEBUG ("destroy key " << j->key << " " << j->destructor << " " << j->value);
+      if (j->destructor != 0 && j->value != 0)
+        {
+          void *v = j->value;
+          // according to the posix spec, we must
+          // set the value to zero before invoking the
+          // destructor.
+          j->value = 0;
+          j->destructor (v);
+        }
+    }
+  current->keyValues.clear ();
+}
+
+
+void simu_exit (int status)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << status);
+  NS_ASSERT (current != 0);
+  CleanupPthreadKeys ();
+  simu__cxa_finalize (0);
+  simu_fflush (0);
+  current->process->exitValue = status;
+  current->task->SetSwitchNotifier (0, 0);
+  current->process->loader->UnloadAll ();
+  current->process->manager->DeleteProcess (current->process);
+  TaskManager::Current ()->Exit ();
+}
+
+struct PthreadStartContext
+{
+  void *(*start_routine)(void*);
+  void *arg;
+};
+
+static void pthread_do_start (void *context)
+{
+  struct PthreadStartContext *pctx = (struct PthreadStartContext *)context;
+  struct PthreadStartContext ctx = *pctx;
+  delete pctx;
+  void *retval = ctx.start_routine (ctx.arg);
+  simu_pthread_exit (retval);
+}
+
+static void PthreadTaskSwitch (enum Task::SwitchType type, void *context)
+{
+  Loader *loader = (Loader *)context;
+  switch (type)
+    {
+    case Task::TO:
+      loader->NotifyStartExecute ();
+      break;
+    case Task::FROM:
+      loader->NotifyEndExecute ();
+      break;
+    }
+}
+
+int simu_pthread_create(pthread_t *thread_handle,
+			const pthread_attr_t *attr,
+			void *(*start_routine)(void*), 
+			void *arg)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << arg);
+  NS_ASSERT (current != 0);
+  Thread *thread = current->process->manager->CreateThread (current->process);
+  *thread_handle = PidTidToPthread (thread->process->pid, thread->tid);
+  TaskManager *manager = TaskManager::Current ();
+  PthreadStartContext *startContext = new PthreadStartContext ();
+  startContext->start_routine = start_routine;
+  startContext->arg = arg;
+  uint32_t mainStackSize = manager->GetStackSize (current->process->threads[0]->task);
+  Task *task = manager->Start (&pthread_do_start, startContext, mainStackSize);
+  task->SetContext (thread);
+  task->SetSwitchNotifier (&PthreadTaskSwitch, current->process->loader);
+  thread->task = task;
+  manager->Yield ();
+  return 0;
+}
+void simu_pthread_exit (void *arg)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << arg);
+  NS_ASSERT (current != 0);
+  Process *process = current->process;
+  if (process->threads.size () == 1)
+    {
+      // call below does not return
+      simu_exit (0);
+    }
+  CleanupPthreadKeys ();
+  if (!current->isDetached)
+    {
+      current->hasExitValue = true;
+      current->exitValue = arg;
+      if (current->joinWaiter != 0)
+	{
+	  current->process->manager->Wakeup (current->joinWaiter);
+	}
+      // thread will be deleted by joining thread.
+      // but we clear this up to make sure that DeleteThread
+      // does not try to 'Stop' the task because the call to
+      // Exit below will effectively delete the task.
+      current->task = 0;
+    }
+  else
+    {
+      current->process->manager->DeleteThread (current);
+    }
+  TaskManager::Current ()->Exit ();
+}
+int simu_pthread_join(pthread_t thread_handle, void **value_ptr)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << PthreadToPid (thread_handle) << PthreadToTid (thread_handle));
+  NS_ASSERT (current != 0);
+  NS_ASSERT (current->process->pid == PthreadToPid (thread_handle));
+  if (current->tid == PthreadToTid (thread_handle))
+    {
+      return EDEADLK;
+    }
+  
+  Thread *thread = current->process->manager->SearchThread (PthreadToPid (thread_handle),
+							    PthreadToTid (thread_handle));
+  if (thread == 0)
+    {
+      return ESRCH;
+    }
+  if (thread->isDetached || thread->joinWaiter != 0)
+    {
+      /* If someone has already joined this thread, we do not
+       * allow joining it again.
+       */
+      return EINVAL;
+    }
+
+  while (!thread->hasExitValue)
+    {
+      thread->joinWaiter = current;
+      current->process->manager->Wait ();
+      thread->joinWaiter = 0;
+    }
+  NS_ASSERT (!thread->isDetached);
+  NS_ASSERT (thread->hasExitValue);
+  if (value_ptr != NULL)
+    {
+      *value_ptr = thread->exitValue;
+    }
+  thread->isDetached = true;
+  current->process->manager->DeleteThread (thread);
+  return 0;
+}
+int simu_pthread_detach(pthread_t thread_handle)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << PthreadToPid (thread_handle) << PthreadToTid (thread_handle));
+  NS_ASSERT (current != 0);
+  Thread *thread = current->process->manager->SearchThread (PthreadToPid (thread_handle),
+							    PthreadToTid (thread_handle));
+  if (thread == 0)
+    {
+      return ESRCH;
+    }
+  if (thread->isDetached)
+    {
+      return EINVAL;
+    }
+  if (thread->joinWaiter != 0)
+    {
+      // the standard does not specify what should happen in this case
+      // but this is the behavior chosen by nptl so, we mimick it
+      // to minimize application behavior changes.
+      return 0;
+    }
+  thread->isDetached = true;
+  return 0;
+}
+int simu_pthread_cancel(pthread_t thread)
+{
+  // XXX
+  return 0;
+}
+pthread_t simu_pthread_self(void)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId ());
+  NS_ASSERT (current != 0);
+  return PidTidToPthread (current->process->pid, current->tid);
+}
+
+int simu_pthread_once (pthread_once_t *once_control, void (*init_routine)(void))
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << once_control << init_routine);
+  NS_ASSERT (Current () != 0);
+  if (once_control == 0 || init_routine == 0)
+    {
+      return EINVAL;
+    }
+  if (*once_control == 1)
+    {
+      return 0;
+    }
+  *once_control = 1;
+  (*init_routine) ();
+  return 0;
+}
+
+static bool
+IsKeyValid (pthread_key_t key)
+{
+  Thread *current = Current ();
+  for (std::list<struct ThreadKeyValue>::const_iterator i = current->keyValues.begin ();
+       i != current->keyValues.end (); ++i)
+    {
+      if (i->key == key)
+        {
+          return true;
+        }
+    }
+  return false;
+}
+void *simu_pthread_getspecific (pthread_key_t key)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key);
+  NS_ASSERT (current != 0);
+  for (std::list<struct ThreadKeyValue>::const_iterator i = current->keyValues.begin ();
+       i != current->keyValues.end (); ++i)
+    {
+      if (i->key == key)
+        {
+          return i->value;
+        }
+    }
+  return 0;
+}
+int simu_pthread_setspecific (pthread_key_t key, const void *value)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key << value);
+  NS_ASSERT (current != 0);
+  for (std::list<struct ThreadKeyValue>::iterator i = current->keyValues.begin ();
+       i != current->keyValues.end (); ++i)
+    {
+      if (i->key == key)
+        {
+          i->value = const_cast<void *> (value);
+          return 0;
+        }
+    }
+  // invalid key
+  return EINVAL;
+}
+int simu_pthread_key_create (pthread_key_t *key, void (*destructor)(void*))
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key << destructor);
+  NS_ASSERT (current != 0);
+  pthread_key_t tmp = 2;
+  // this is a totally arbitrary limit on the total number of thread keys per process.
+  while (tmp < 100000)
+    {
+      if (!IsKeyValid (tmp))
+        {
+          struct ThreadKeyValue value;
+          value.key = tmp;
+          value.destructor = destructor;
+          value.value = 0;
+          // store the key in each thread of the process.
+          struct Process *process = current->process;
+          for (std::vector<struct Thread *>::const_iterator i = process->threads.begin (); 
+               i != process->threads.end (); ++i)
+            {
+              struct Thread *thread = *i;
+              thread->keyValues.push_back (value);
+            }
+          *key = tmp;
+          return 0;
+        }
+      tmp++;
+    }
+  return EAGAIN;
+}
+int simu_pthread_key_delete (pthread_key_t key)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << key);
+  NS_ASSERT (current != 0);
+  if (!IsKeyValid (key))
+    {
+      return EINVAL;
+    }
+  struct Process *process = current->process;
+  for (std::vector<struct Thread *>::const_iterator i = process->threads.begin (); 
+       i != process->threads.end (); ++i)
+    {
+      struct Thread *thread = *i;
+      bool found = false;
+      for (std::list<struct ThreadKeyValue>::iterator j = thread->keyValues.begin ();
+           j != thread->keyValues.end (); ++j)
+        {
+          if (j->key == key)
+            {
+              found = true;
+              thread->keyValues.erase (j);
+              break;
+            }
+        }
+      NS_ASSERT (found);
+    }
+  return 0;
+}
+int simu_pthread_kill(pthread_t th, int sig)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << PthreadToPid (th) << PthreadToTid (th) << sig);
+  NS_ASSERT (current != 0);
+  Thread *thread = current->process->manager->SearchThread (PthreadToPid (th),
+							    PthreadToTid (th));
+  if (thread == 0)
+    {
+      return ESRCH;
+    }
+  
+  sigaddset (&thread->pendingSignals, sig);
+  if (sigismember (&thread->signalMask, sig) == 0)
+    {
+      // signal not blocked by thread.
+      if (thread->task->IsBlocked ())
+	{
+	  thread->process->manager->Wakeup (thread);
+	}
+    }
+
+  return 0;
+}
+#if 0
+int simu_pthread_sigmask(int how, const sigset_t *restrict set,
+			 sigset_t *restrict oset)
+{
+  // XXX implement
+  return 0;
+}
+int simu_sigprocmask(int how, const sigset_t *restrict set,
+		     sigset_t *restrict oset)
+{
+  // XXX implement
+  return 0;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-pthread.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,57 @@
+#ifndef SIMU_PTHREAD_H
+#define SIMU_PTHREAD_H
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_pthread_create(pthread_t *thread,
+			const pthread_attr_t *attr,
+			void *(*start_routine)(void*), 
+			void *arg);
+void simu_pthread_exit (void *arg);
+int simu_pthread_join(pthread_t thread, void **value_ptr);
+int simu_pthread_detach(pthread_t thread);
+int simu_pthread_cancel(pthread_t thread);
+pthread_t simu_pthread_self(void);
+
+int simu_pthread_mutex_init (pthread_mutex_t *mutex,
+			     const pthread_mutexattr_t *attr);
+int simu_pthread_mutex_destroy (pthread_mutex_t *mutex);
+int simu_pthread_mutex_lock(pthread_mutex_t *mutex);
+int simu_pthread_mutex_trylock(pthread_mutex_t *mutex);
+int simu_pthread_mutex_unlock(pthread_mutex_t *mutex);
+int simu_pthread_mutexattr_init (pthread_mutexattr_t *attr);
+int simu_pthread_mutexattr_destroy (pthread_mutexattr_t *attr);
+int simu_pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind);
+
+int simu_pthread_once (pthread_once_t *once_control, void (*init_routine)(void));
+void *simu_pthread_getspecific (pthread_key_t key);
+int simu_pthread_setspecific (pthread_key_t key, const void *value);
+int simu_pthread_key_create (pthread_key_t *key, void (*destructor)(void*));
+int simu_pthread_key_delete (pthread_key_t key);
+
+int simu_pthread_cond_destroy (pthread_cond_t *cond);
+int simu_pthread_cond_init (pthread_cond_t *cond,
+			    const pthread_condattr_t *attr);
+int simu_pthread_cond_broadcast (pthread_cond_t *cond);
+int simu_pthread_cond_signal (pthread_cond_t *cond);
+int simu_pthread_cond_timedwait(pthread_cond_t * cond,
+				pthread_mutex_t * mutex,
+				const struct timespec * abstime);
+int simu_pthread_cond_wait(pthread_cond_t * cond,
+			   pthread_mutex_t * mutex);
+int simu_pthread_condattr_destroy(pthread_condattr_t *attr);
+int simu_pthread_condattr_init(pthread_condattr_t *attr);
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_PTHREAD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-random.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#ifndef SIMU_RANDOM_H
+#define SIMU_RANDOM_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+long int simu_random (void);
+int simu_rand (void);
+void simu_srandom (unsigned int seed);
+void simu_srand (unsigned int seed);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_RANDOM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-sched.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,14 @@
+#ifndef SIMU_SCHED_H
+#define SIMU_SCHED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_sched_yield (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_SCHED_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-semaphore.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,232 @@
+#include "simu-semaphore.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "utils.h"
+#include <stdint.h>
+#include <errno.h>
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/simulator.h"
+
+NS_LOG_COMPONENT_DEFINE ("Semaphore");
+
+using namespace ns3;
+
+
+static uint32_t AllocateSid (struct Process *process)
+{
+  // check that semaphore structure is big enough to store our semaphore id
+  NS_ASSERT (sizeof (sem_t) > sizeof(uint16_t));
+  uint32_t sid = process->nextSid;
+  process->nextSid++;
+  return sid;
+}
+static void SidToSem (uint32_t sid, sem_t *sem)
+{
+  uint32_t *psid = (uint32_t *)sem;
+  *psid = sid;
+}
+static uint32_t SemToSid (const sem_t *sem)
+{
+  if (sem == 0)
+    {
+      return 0;
+    }
+  const uint32_t *psid = (const uint32_t *)sem;
+  return *psid;
+}
+static struct Semaphore *
+SearchSemaphore (const sem_t *sem)
+{
+  Thread *current = Current ();
+  if (sem == 0)
+    {
+      return 0;
+    }
+  uint32_t sid = SemToSid (sem);
+  for (uint32_t i = 0; i < current->process->semaphores.size (); ++i)
+    {
+      struct Semaphore *semaphore = current->process->semaphores[i];
+      if (semaphore->sid == sid)
+        {
+          return semaphore;
+        }
+    }
+  return 0;
+}
+
+int simu_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << sem << pshared << value);
+  NS_ASSERT (current != 0);
+  
+  if (pshared != 0)
+    {
+      current->err = ENOSYS;
+      return -1;
+    }
+  Semaphore *semaphore = new Semaphore ();
+  semaphore->sid = AllocateSid (current->process);
+  semaphore->count = value;
+  semaphore->waiting.clear ();
+  current->process->semaphores.push_back (semaphore);
+  SidToSem (semaphore->sid, sem);
+  return 0;
+}
+int simu_sem_destroy(sem_t *sem)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sem);
+  NS_ASSERT (current != 0);
+  struct Semaphore *semaphore = SearchSemaphore (sem);
+  if (semaphore == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  if (!semaphore->waiting.empty ())
+    {
+      NS_FATAL_ERROR ("Trying to destroy a semaphore on which someone else is waiting.");
+    }
+  for (std::vector<struct Semaphore *>::iterator i = current->process->semaphores.begin (); 
+       i != current->process->semaphores.end (); ++i)
+    {
+      if (semaphore == *i)
+        {
+          delete semaphore;
+          semaphore = 0;
+          current->process->semaphores.erase (i);
+          break;
+        }
+    }
+  NS_ASSERT (semaphore == 0);
+  SidToSem (2, sem);
+  return 0;
+}
+int simu_sem_post(sem_t *sem)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sem);
+  NS_ASSERT (current != 0);
+
+  struct Semaphore *semaphore = SearchSemaphore (sem);
+  if (semaphore == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+
+  semaphore->count++;
+
+  if (!semaphore->waiting.empty ())
+    {
+      // FIFO order for threads blocked on the semaphore waiting for it.
+      Thread *waiting = semaphore->waiting.front ();
+      current->process->manager->Wakeup (waiting);
+      // give them a chance to run.
+      current->process->manager->Yield ();
+    }
+  
+  return 0;
+}
+int simu_sem_wait(sem_t *sem)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sem);
+  NS_ASSERT (current != 0);
+
+  struct Semaphore *semaphore = SearchSemaphore (sem);
+  if (semaphore == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  while (semaphore->count == 0)
+    {
+      semaphore->waiting.push_back (current);
+      current->process->manager->Wait ();
+      semaphore->waiting.remove (current);
+    }
+  semaphore->count--;
+  return 0;
+}
+int simu_sem_trywait(sem_t *sem)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sem);
+  NS_ASSERT (current != 0);
+
+  struct Semaphore *semaphore = SearchSemaphore (sem);
+  if (semaphore == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  if (semaphore->count == 0)
+    {
+      current->err = EAGAIN;
+      return -1;
+    }
+  semaphore->count--;
+  return 0;
+}
+int simu_sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sem);
+  NS_ASSERT (current != 0);
+
+  struct Semaphore *semaphore = SearchSemaphore (sem);
+  if (semaphore == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  
+  if (semaphore->count > 0)
+    {
+      // fast path
+      semaphore->count--;
+      return 0;
+    }
+  Time expirationTime = UtilsTimeToSimulationTime (UtilsTimespecToTime (*abs_timeout));
+  if (expirationTime <= Simulator::Now ())
+    {
+      // timer already expired when we start.
+      current->err = ETIMEDOUT;
+      return -1;
+    }
+  // setup timer.
+  Time timeoutLeft = expirationTime - Simulator::Now ();
+  while (semaphore->count == 0)
+    {
+      semaphore->waiting.push_back (current);
+      timeoutLeft = current->process->manager->Wait (timeoutLeft);
+      semaphore->waiting.remove (current);
+      if (timeoutLeft.IsZero ())
+	{
+	  // timer expired
+	  current->err = ETIMEDOUT;
+	  return -1;
+	}
+    }
+  semaphore->count--;
+  return 0;
+}
+int simu_sem_getvalue(sem_t *sem, int *sval)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << sem);
+  NS_ASSERT (current != 0);
+
+  struct Semaphore *semaphore = SearchSemaphore (sem);
+  if (semaphore == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  *sval = semaphore->count;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-semaphore.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,22 @@
+#ifndef SIMU_SEMAPHORE_H
+#define SIMU_SEMAPHORE_H
+
+#include <semaphore.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_sem_init(sem_t *sem, int pshared, unsigned int value);
+int simu_sem_destroy(sem_t *sem);
+int simu_sem_post(sem_t *sem);
+int simu_sem_wait(sem_t *sem);
+int simu_sem_trywait(sem_t *sem);
+int simu_sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
+int simu_sem_getvalue(sem_t *sem, int *sval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_SEMAPHORE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-signal.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,93 @@
+#include "simu-signal.h"
+#include "utils.h"
+#include "process.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <vector>
+
+NS_LOG_COMPONENT_DEFINE ("SimuSignal");
+
+using namespace ns3;
+
+sighandler_t simu_signal(int signum, sighandler_t handler)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << signum << handler);
+  NS_ASSERT (Current () != 0);
+  struct sigaction action, old_action;
+  action.sa_handler = handler;
+  sigemptyset (&action.sa_mask);
+  action.sa_flags = 0;
+  int status = simu_sigaction (signum, &action, &old_action);
+  if (status != 0)
+    {
+      return SIG_ERR;
+    }
+  if (old_action.sa_flags & SA_SIGINFO)
+    {
+      return (sighandler_t)old_action.sa_sigaction;
+    }
+  else
+    {
+      return old_action.sa_handler;
+    }
+}
+int simu_sigaction (int signum, const struct sigaction *act,
+		   struct sigaction *oldact)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << signum << act << oldact);
+  NS_ASSERT (current != 0);
+
+  for (std::vector<SignalHandler>::iterator i = current->process->signalHandlers.begin (); 
+       i != current->process->signalHandlers.end (); ++i)
+    {
+      if (i->signal == signum)
+	{
+	  if (oldact != 0)
+	    {
+	      oldact->sa_flags = i->flags;
+	      oldact->sa_mask = i->mask;
+	      if (oldact->sa_flags & SA_SIGINFO)
+		{
+		  oldact->sa_sigaction = i->sigaction;
+		}
+	      else
+		{
+		  oldact->sa_handler = i->handler;
+		}
+	    }
+	  if (act != 0)
+	    {
+	      i->flags = act->sa_flags;
+	      i->mask = act->sa_mask;
+	      if (act->sa_flags & SA_SIGINFO)
+		{
+		  i->sigaction = act->sa_sigaction;
+		}
+	      else
+		{
+		  i->handler = act->sa_handler;
+		}
+	    }
+	  return 0;
+	}
+    }
+  if (act != 0)
+    {
+      struct SignalHandler handler;
+      handler.signal = signum;
+      handler.flags = act->sa_flags;
+      handler.mask = act->sa_mask;
+      if (act->sa_flags & SA_SIGINFO)
+	{
+	  handler.sigaction = act->sa_sigaction;
+	}
+      else
+	{
+	  handler.handler = act->sa_handler;
+	}
+      current->process->signalHandlers.push_back (handler);
+    }
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-signal.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,24 @@
+#ifndef SIMU_SIGNAL_H
+#define SIMU_SIGNAL_H
+
+#include "simu-clock.h"
+#include "simu-pthread.h"
+#include <signal.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+sighandler_t simu_signal (int signum, sighandler_t handler);
+int simu_sigaction (int signum, const struct sigaction *act,
+		   struct sigaction *oldact);
+int simu_kill (pid_t pid, int sig);
+int simu_pthread_kill(pthread_t thread, int sig);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* SIMU_SIGNAL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-stat.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,113 @@
+#include "sys/simu-stat.h"
+#include "utils.h"
+#include "process.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <errno.h>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SimuStat");
+
+int simu_xstat (int ver, const char *path, struct stat *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << path << buf);
+  NS_ASSERT (current != 0);
+  if (std::string (path) == "")
+    {
+      current->err = ENOENT;
+      return -1;
+    }
+  int retval = ::__xstat (ver, UtilsGetRealFilePath (path).c_str (), buf);
+  if (retval == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return retval;
+}
+int simu_xstat64 (int ver, const char *path, struct stat64 *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << path << buf);
+  NS_ASSERT (current != 0);
+  if (std::string (path) == "")
+    {
+      current->err = ENOENT;
+      return -1;
+    }
+  int retval = ::__xstat64 (ver, UtilsGetRealFilePath (path).c_str (), buf);
+  if (retval == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return retval;
+}
+int simu_fxstat (int ver, int fd, struct stat *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Fxstat (ver, buf);
+  return retval;
+}
+int simu_fxstat64 (int ver, int fd, struct stat64 *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << fd);
+  NS_ASSERT (current != 0);
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Fxstat64 (ver, buf);
+  return retval;
+}
+int simu_lxstat (int ver, const char *pathname, struct stat *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << pathname << buf);
+  NS_ASSERT (current != 0);
+  if (std::string (pathname) == "")
+    {
+      current->err = ENOENT;
+      return -1;
+    }
+  int retval = ::__lxstat (ver, UtilsGetRealFilePath (pathname).c_str (), buf);
+  if (retval == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return retval;
+}
+int simu_lxstat64 (int ver, const char *pathname, struct stat64 *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << pathname << buf);
+  NS_ASSERT (current != 0);
+  if (std::string (pathname) == "")
+    {
+      current->err = ENOENT;
+      return -1;
+    }
+  int retval = ::__lxstat64 (ver, UtilsGetRealFilePath (pathname).c_str (), buf);
+  if (retval == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-stdarg.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,18 @@
+#ifndef SIMU_STDARG_H
+#define SIMU_STDARG_H
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_vfprintf(FILE *stream, const char *format, va_list ap);
+int simu_vsprintf(char *str, const char *format, va_list ap);
+int simu_vsnprintf(char *str, size_t size, const char *format, va_list ap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_STDARG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-stdio.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,392 @@
+#include "simu-stdio.h"
+#include "simu-stdarg.h"
+#include "simu-fcntl.h"
+#include "simu-unistd.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "utils.h"
+#include "unix-fd.h"
+#include "system-wrappers.h"
+#include "ns3/log.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <sys/mman.h>
+
+NS_LOG_COMPONENT_DEFINE ("SimuStdio");
+
+using namespace ns3;
+
+
+FILE *simu_fdopen(int fildes, const char *mode)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fildes << mode);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  FILE *file = fdopen (fildes, mode);
+  SystemWrappersDisable ();
+  if (file == 0)
+    {
+      current->err = errno;
+      return 0;
+    }
+  current->process->openStreams.push_back (file);
+  return file;
+}
+
+
+FILE *simu_fopen(const char *path, const char *mode)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << path << mode);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  FILE *file = fopen (path, mode);
+  SystemWrappersDisable ();
+  if (file == 0)
+    {
+      current->err = errno;
+      return 0;
+    }
+  current->process->openStreams.push_back (file);
+  return file;
+}
+FILE *simu_freopen(const char *path, const char *mode, FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << path << mode << stream);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  FILE *file = freopen (path, mode, stream);
+  SystemWrappersDisable ();
+  if (file == 0)
+    {
+      current->err = errno;
+      return 0;
+    }
+  return file;
+}
+int simu_fcloseall (void)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId ());
+  NS_ASSERT (Current () != 0);
+  struct Process *process = Current ()->process;
+  bool error = false;
+  for (uint32_t i =  0; i < process->openStreams.size (); i++)
+    {
+      int status = simu_fclose (process->openStreams[i]);
+      if (status != 0)
+	{
+	  error = true;
+	}
+    }
+  return error?EOF:0;
+}
+static void
+remove_stream (FILE *fp)
+{
+  Thread *current = Current ();
+  bool found = false;
+  for (std::vector<FILE*>::iterator  i = current->process->openStreams.begin (); 
+       i != current->process->openStreams.end (); ++i)
+    {
+      if (*i == fp)
+	{
+	  current->process->openStreams.erase (i);
+	  found = true;
+	  break;
+	}
+    }
+  if (!found)
+    {
+      // not found
+      NS_FATAL_ERROR ("invalid FILE * closed=" << fp);
+    }
+}
+int simu_fclose(FILE *fp)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fp);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+
+  if (fp == *current->process->pstdout ||
+      fp == *current->process->pstderr ||
+      fp == *current->process->pstdin)
+    {
+      return 0;
+    }
+
+  remove_stream (fp);
+
+  SystemWrappersEnable ();
+  int status = fclose (fp);
+  SystemWrappersDisable ();
+  NS_LOG_DEBUG ("fclose=" << status << " errno=" << errno);
+  if (status != 0)
+    {
+      current->err = errno;
+      return status;
+    }
+  return status;
+}
+size_t simu_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << ptr << size << nmemb << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I believe that fread does not set errno ever
+  size_t status = fread (ptr, size, nmemb, stream);
+  SystemWrappersDisable ();
+  return status;
+}
+size_t simu_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << ptr << size << nmemb << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I believe that fwrite does not set errno ever
+  size_t status = fwrite (ptr, size, nmemb, stream);
+  SystemWrappersDisable ();
+  return status;
+}
+int simu_fflush(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  if (stream == 0)
+    {
+      // only flush the streams of the current process
+      for (std::vector<FILE *>::const_iterator i = current->process->openStreams.begin ();
+	   i != current->process->openStreams.end (); ++i)
+	{
+	  SystemWrappersEnable ();
+	  int status = fflush (*i);
+	  SystemWrappersDisable ();
+	  if (status != 0)
+	    {
+	      current->err = errno;
+	      return status;
+	    }
+	}
+    }
+  else
+    {
+      SystemWrappersEnable ();
+      int status = fflush (stream);
+      SystemWrappersDisable ();
+      if (status != 0)
+	{
+	  current->err = errno;
+	  return status;
+	}
+    }
+  return 0;
+}
+void simu_clearerr(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  clearerr (stream);
+  SystemWrappersDisable ();
+}
+int simu_feof(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  int status = feof (stream);
+  SystemWrappersDisable ();
+  return status;
+}
+int simu_ferror(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  int status = ferror (stream);
+  SystemWrappersDisable ();
+  return status;
+}
+int simu_fileno(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  int status = fileno (stream);
+  SystemWrappersDisable ();
+  if (status == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return status;
+}
+
+int simu_vfprintf(FILE *stream, const char *format, va_list ap)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream << format);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I don't believe that this function sets errno
+  int status = vfprintf (stream, format, ap);
+  SystemWrappersDisable ();
+  return status;
+}
+int simu_fputc(int c, FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << c << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I don't believe that this function sets errno
+  int status = fputc (c, stream);
+  SystemWrappersDisable ();
+  return status;
+}
+int simu_fgetc(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I don't believe that this function sets errno
+  int status = fgetc (stream);
+  SystemWrappersDisable ();
+  return status;
+}
+int simu_fputs(const char *s, FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << s << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I don't believe that this function sets errno
+  int status = fputs (s, stream);
+  SystemWrappersDisable ();
+  return status;
+}
+char* simu_fgets(char *s, int size, FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << s << size << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I don't believe that this function sets errno
+  char *status = fgets (s, size, stream);
+  SystemWrappersDisable ();
+  return status;
+}
+int simu_ungetc(int c, FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << c << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  // Note: I don't believe that this function sets errno
+  int status = ungetc (c, stream);
+  SystemWrappersDisable ();
+  return status;  
+}
+int simu_fseek(FILE *stream, long offset, int whence)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream << offset << whence);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  int status = fseek (stream, offset, whence);
+  SystemWrappersDisable ();
+  if (status == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return status;
+}
+long simu_ftell(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  long status = ftell (stream);
+  SystemWrappersDisable ();
+  if (status == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return status;
+}
+int simu_fgetpos(FILE *stream, fpos_t *pos)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream << pos);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  int status = fgetpos (stream, pos);
+  SystemWrappersDisable ();
+  if (status == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return status;
+}
+int simu_fsetpos(FILE *stream, const fpos_t *pos)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream << pos);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  int status = fsetpos (stream, pos);
+  SystemWrappersDisable ();
+  if (status == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return status;
+}
+
+void simu_rewind(FILE *stream)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream);
+  NS_ASSERT (Current () != 0);
+  SystemWrappersEnable ();
+  rewind (stream);
+  SystemWrappersDisable ();
+}
+int simu_setvbuf(FILE *stream, char *buf, int mode, size_t size)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << stream << buf << mode << size);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  SystemWrappersEnable ();
+  int status = setvbuf (stream, buf, mode, size);
+  SystemWrappersDisable ();
+  if (status == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  return status;
+}
+
+int simu_remove (const char *pathname)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << pathname);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  if (std::string (pathname) == "")
+    {
+      current->err = ENOENT;
+      return -1;
+    }
+  std::string fullpath = UtilsGetRealFilePath (pathname);
+  int status = ::remove (fullpath.c_str ());
+  if (status == -1)
+    {
+      current->err = errno;
+    }
+  return status;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-stdio.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,46 @@
+#ifndef SIMU_STDIO_H
+#define SIMU_STDIO_H
+
+#include <stdio.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+FILE *simu_fopen(const char *path, const char *mode);
+FILE *simu_fdopen(int fildes, const char *mode);
+FILE *simu_freopen(const char *path, const char *mode, FILE *stream);
+int simu_fclose(FILE *fp);
+int simu_fcloseall (void);
+
+int simu_fflush(FILE *stream);
+void simu_clearerr(FILE *stream);
+int simu_feof(FILE *stream);
+int simu_ferror(FILE *stream);
+int simu_fileno(FILE *stream);
+
+int simu_fseek(FILE *stream, long offset, int whence);
+long simu_ftell(FILE *stream);
+int simu_fgetpos(FILE *stream, fpos_t *pos);
+int simu_fsetpos(FILE *stream, const fpos_t *pos);
+void simu_rewind(FILE *stream);
+
+int simu_setvbuf(FILE *stream, char *buf, int mode, size_t size);
+
+size_t simu_fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
+size_t simu_fwrite(const void *ptr, size_t size, size_t nmemb,
+		   FILE *stream);
+int simu_fputc(int c, FILE *stream);
+int simu_fputs(const char *s, FILE *stream);
+int simu_fgetc(FILE *stream);
+char* simu_fgets(char *s, int size, FILE *stream);
+int simu_ungetc(int c, FILE *stream);
+
+int simu_remove (const char *pathname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_STDIO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-stdlib.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,88 @@
+#include "simu-stdlib.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "utils.h"
+#include "ns3/log.h"
+#include <errno.h>
+#include <limits.h>
+
+
+NS_LOG_COMPONENT_DEFINE ("SimuStdlib");
+
+using namespace ns3;
+
+long int simu_strtol(const char *nptr, char **endptr, int base)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << nptr << endptr << base);
+  NS_ASSERT (current != 0);
+  long int retval = strtol (nptr, endptr, base);
+  if (retval == LONG_MAX || retval == LONG_MIN)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+long long int simu_strtoll(const char *nptr, char **endptr, int base)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << nptr << endptr << base);
+  NS_ASSERT (current != 0);
+  long long int retval = strtoll (nptr, endptr, base);
+  if (retval == LLONG_MAX || retval == LLONG_MIN)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+
+unsigned long int simu_strtoul(const char *nptr, char **endptr, int base)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << nptr << endptr << base);
+  NS_ASSERT (current != 0);
+  unsigned long int retval = strtol (nptr, endptr, base);
+  if (retval == ULONG_MAX)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+unsigned long long int simu_strtoull(const char *nptr, char **endptr, int base)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << nptr << endptr << base);
+  NS_ASSERT (current != 0);
+  unsigned long long int retval = strtoull (nptr, endptr, base);
+  if (retval == ULLONG_MAX)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+double simu_strtod(const char *nptr, char **endptr)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << nptr << endptr);
+  NS_ASSERT (current != 0);
+  double retval = strtod (nptr, endptr);
+  if (retval == 0.0)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+
+int simu_atexit(void (*function)(void))
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << function);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  struct AtExitHandler handler;
+  handler.type = AtExitHandler::NORMAL;
+  handler.value.normal = function;
+  current->process->atExitHandlers.push_back (handler);
+  return 0;
+}
+
+// XXX: run function to runall atexit functions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-stdlib.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,30 @@
+#ifndef SIMU_STDLIB_H
+#define SIMU_STDLIB_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+long int simu_strtol(const char *nptr, char **endptr, int base);
+long long int simu_strtoll(const char *nptr, char **endptr, int base);
+long unsigned int simu_strtoul(const char *nptr, char **endptr, int base);
+long long unsigned int simu_strtoull(const char *nptr, char **endptr, int base);
+double simu_strtod(const char *nptr, char **endptr);
+void *simu_calloc(size_t nmemb, size_t size);
+void *simu_malloc(size_t size);
+void simu_free(void *ptr);
+void *simu_realloc(void *ptr, size_t size);
+int simu_atexit(void (*function)(void));
+char *simu_getenv(const char *name);
+int simu_putenv(char *string);
+int simu_setenv(const char *name, const char *value, int overwrite);
+int simu_unsetenv(const char *name);
+int simu_clearenv(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_STDLIB_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-string.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,20 @@
+#include "simu-string.h"
+#include "simu-stdlib.h"
+#include <string.h>
+
+char *simu_strdup(const char *s)
+{
+  size_t len = strlen (s);
+  char *str = (char*)simu_malloc (len+1);
+  memcpy (str, s, len+1);
+  return str;
+}
+char *simu_strndup(const char *s, size_t n)
+{
+  size_t len = strlen (s);
+  len = (len < n)?len:n;
+  char *str = (char*)simu_malloc (len+1);
+  memcpy (str, s, len);
+  str[len] = 0;
+  return str;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-string.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,17 @@
+#ifndef SIMU_STRING_H
+#define SIMU_STRING_H
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char *simu_strdup(const char *s);
+char *simu_strndup(const char *s, size_t n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_STRING_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-time.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,18 @@
+#ifndef SIMU_TIME_H
+#define SIMU_TIME_H
+
+#include "sys/simu-time.h"
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+time_t simu_time (time_t *t);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_TIME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-timerfd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,63 @@
+#include "sys/simu-timerfd.h"
+#include "utils.h"
+#include "process.h"
+#include "unix-timer-fd.h"
+#include "ns3/log.h"
+#include <errno.h>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("SimuTimerFd");
+
+int simu_timerfd_create(int clockid, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << clockid << flags);
+  NS_ASSERT (current != 0);
+
+  int fd = UtilsAllocateFd ();
+  if (fd == -1)
+    {
+      current->err = EMFILE;
+      return -1;
+    }
+
+  UnixFd *unixFd = new UnixTimerFd (clockid, flags);
+  current->process->openFiles.push_back (std::make_pair(fd,unixFd));
+  return fd;
+}
+
+int simu_timerfd_settime(int fd, int flags,
+			 const struct itimerspec *new_value,
+			 struct itimerspec *old_value)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fd << flags << new_value << old_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Settime (flags, new_value, old_value);
+  return retval;
+}
+
+int simu_timerfd_gettime(int fd, struct itimerspec *cur_value)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << fd << cur_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  int index = UtilsSearchOpenFd (fd);
+  if (index == -1)
+    {
+      current->err = EBADF;
+      return -1;
+    }
+  UnixFd *unixFd = current->process->openFiles[index].second;
+  int retval = unixFd->Gettime (cur_value);
+  return retval;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu-unistd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,53 @@
+#ifndef SIMU_UNISTD_H
+#define SIMU_UNISTD_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ssize_t simu_write (int fd, const void *buf, size_t count);
+ssize_t simu_writev (int fd, const struct iovec *iov, int iovcnt);
+ssize_t simu_read (int fd, void *buf, size_t count);
+void simu_exit (int status);
+unsigned int simu_sleep(unsigned int seconds);
+pid_t simu_getpid (void);
+pid_t simu_getppid (void);
+int simu_pause (void);
+int simu_getopt_r (int argc, char * const argv[], const char *optstring, 
+		   char **poptarg, int *poptind, int *popterr, int *poptopt);
+int simu_getopt_long_r (int argc, char * const argv[], const char *optstring, 
+		   const struct option *longopts, int *longindex,
+		   char **poptarg, int *poptind, int *popterr, int *poptopt);
+uid_t simu_getuid(void);
+uid_t simu_geteuid(void);
+int simu_setuid(uid_t uid);
+int simu_setgid(gid_t gid);
+int simu_seteuid(uid_t euid);
+int simu_setegid(gid_t egid);
+int simu_setreuid(uid_t ruid, uid_t euid);
+int simu_setregid(gid_t rgid, gid_t egid);
+int simu_setresuid(uid_t ruid, uid_t euid, uid_t suid);
+int simu_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+
+int simu_isatty(int desc);
+char *simu_getcwd (char *buf, size_t size);
+char *simu_getwd (char *buf);
+char *simu_get_current_dir_name (void);
+
+int simu_chdir(const char *path);
+int simu_fchdir(int fd);
+int simu_dup(int oldfd);
+int simu_dup2(int oldfd, int newfd);
+int simu_close (int fd);
+off_t simu_lseek(int fildes, off_t offset, int whence);
+off64_t simu_lseek64(int fildes, off64_t offset, int whence);
+int simu_unlink (const char *pathname);
+int simu_rmdir(const char *pathname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_UNISTD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/simu.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,557 @@
+#include "dce-manager.h"
+#include "process.h"
+#include "utils.h"
+#include "simu-errno.h"
+#include "simu-signal.h"
+#include "simu-netdb.h"
+#include "simu-unistd.h"
+#include "simu-time.h"
+#include "sys/simu-socket.h"
+#include "simu-pthread.h"
+#include "simu-stdio.h"
+#include "simu-stdarg.h"
+#include "simu-stdlib.h"
+#include "sys/simu-ioctl.h"
+#include "simu-sched.h"
+#include "arpa/simu-inet.h"
+#include "ns3/node.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <limits.h>
+#include <fcntl.h>
+#include "simu-random.h"
+#include "net/simu-if.h"
+#include "ns3/names.h"
+#include "ns3/random-variable.h"
+#include "ns3/ipv4-l3-protocol.h"
+
+
+NS_LOG_COMPONENT_DEFINE ("Simu");
+
+using namespace ns3;
+
+int *simu_get_errno (void)
+{
+  GET_CURRENT_NOLOG ();
+  return &current->err;
+}
+pid_t simu_getpid (void)
+{
+  GET_CURRENT_NOLOG ();
+  return current->process->pid;
+}
+pid_t simu_getppid (void)
+{
+  GET_CURRENT_NOLOG ();
+  return current->process->ppid;
+}
+uid_t simu_getuid (void)
+{
+  GET_CURRENT_NOLOG ();
+  return current->process->ruid;
+}
+uid_t simu_geteuid (void)
+{
+  GET_CURRENT_NOLOG ();
+  return current->process->euid;
+}
+static bool is_ucapable (void)
+{
+  GET_CURRENT_NOLOG ();
+  return current->process->euid == 0;
+}
+static bool is_gcapable (void)
+{
+  GET_CURRENT_NOLOG ();
+  return current->process->egid == 0;
+}
+static bool is_set_ucapable (uid_t uid)
+{
+  GET_CURRENT (uid);
+  return is_ucapable () ||
+    current->process->euid == uid ||
+    current->process->ruid == uid ||
+    current->process->suid == uid;
+}
+static bool is_set_gcapable (gid_t gid)
+{
+  GET_CURRENT (gid);
+  return is_gcapable () ||
+    current->process->egid == gid ||
+    current->process->rgid == gid ||
+    current->process->sgid == gid;
+}
+
+int simu_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+  GET_CURRENT (ruid << euid << suid);
+  if (ruid != (uid_t)-1 &&
+      !is_set_ucapable (ruid))
+    {
+      current->err = EPERM;
+      return -1;
+    }
+  if (euid != (uid_t)-1 &&
+      !is_set_ucapable (euid))
+    {
+      current->err = EPERM;
+      return -1;
+    }
+  if (suid != (uid_t)-1 &&
+      !is_set_ucapable (suid))
+    {
+      current->err = EPERM;
+      return -1;
+    }
+  if (ruid != (uid_t)-1)
+    {
+      current->process->ruid = ruid;
+    }
+  if (euid != (uid_t)-1)
+    {
+      current->process->euid = euid;
+    }
+  if (suid != (uid_t)-1)
+    {
+      current->process->suid = suid;
+    }
+
+  return 0;
+}
+int simu_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+  GET_CURRENT (rgid << egid << sgid);
+  if (rgid != (gid_t)-1 &&
+      !is_set_ucapable (rgid))
+    {
+      current->err = EPERM;
+      return -1;
+    }
+  if (egid != (gid_t)-1 &&
+      !is_set_ucapable (egid))
+    {
+      current->err = EPERM;
+      return -1;
+    }
+  if (sgid != (gid_t)-1 ||
+      !is_set_ucapable (sgid))
+    {
+      current->err = EPERM;
+      return -1;
+    }
+  if (rgid != (gid_t)-1)
+    {
+      current->process->rgid = rgid;
+    }
+  if (egid != (gid_t)-1)
+    {
+      current->process->egid = egid;
+    }
+  if (sgid != (gid_t)-1)
+    {
+      current->process->sgid = sgid;
+    }
+  return 0;
+}
+int simu_setreuid(uid_t ruid, uid_t euid)
+{
+  GET_CURRENT (ruid << euid);
+  return simu_setresuid (ruid,euid,-1);
+}
+int simu_setregid(gid_t rgid, gid_t egid)
+{
+  GET_CURRENT (rgid << egid);
+  return simu_setresgid (rgid,egid,-1);
+}
+
+int simu_seteuid(uid_t euid)
+{
+  GET_CURRENT (euid);
+  return simu_setresuid (-1, euid, -1);
+}
+int simu_setegid(gid_t egid)
+{
+  GET_CURRENT (egid);
+  return simu_setresgid (-1, egid, -1);
+}
+int simu_setuid(uid_t uid)
+{
+  GET_CURRENT (uid);
+  if (is_set_ucapable (uid))
+    {
+      current->process->ruid = uid;
+      if (current->process->euid == 0)
+	{
+	  current->process->euid = uid;
+	  current->process->suid = uid;
+	}
+      return 0;
+    }
+  else
+    {
+      current->err = EPERM;
+      return -1;
+    }
+}
+int simu_setgid(gid_t gid)
+{
+  GET_CURRENT (gid);
+  if (is_set_gcapable (gid))
+    {
+      current->process->rgid = gid;
+      if (current->process->egid == 0)
+	{
+	  current->process->egid = gid;
+	  current->process->sgid = gid;
+	}
+      return 0;
+    }
+  else
+    {
+      current->err = EPERM;
+      return -1;
+    }
+}
+
+unsigned int simu_sleep(unsigned int seconds)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId ());
+  NS_ASSERT (current != 0);
+  current->process->manager->Wait (Seconds (seconds));
+  return 0;
+}
+
+
+int simu_kill (pid_t pid, int sig)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << pid << sig);
+  Process *process = current->process->manager->SearchProcess (pid);
+
+  if (process == 0)
+    {
+      current->err = ESRCH;
+      return -1;
+    }
+
+  UtilsSendSignal (process, SIGKILL);
+
+  return 0;
+}
+
+int simu_pause (void)
+{
+  //Thread *current = Current ();
+  //NS_LOG_FUNCTION (current << UtilsGetNodeId ());
+  //NS_ASSERT (current != 0);
+  // XXX
+  return 0;
+}
+
+
+int simu_gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId ());
+  NS_ASSERT (Current () != 0);
+  NS_ASSERT (tz == 0);
+  *tv = UtilsTimeToTimeval (UtilsSimulationTimeToTime (Now ()));
+  return 0;
+}
+time_t simu_time (time_t *t)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId ());
+  NS_ASSERT (Current () != 0);
+  time_t time = (time_t)UtilsSimulationTimeToTime (Now ()).GetSeconds ();
+  if (t != 0)
+    {
+      *t = time;
+    }
+  return time;
+}
+int simu_nanosleep (const struct timespec *req, struct timespec *rem) {
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId ());
+  NS_ASSERT (current != 0);
+  if (req == 0) {
+    current->err = EFAULT;
+    return -1;
+  }
+  if ((req->tv_sec < 0) || (req->tv_nsec < 0) || (req->tv_nsec > 999999999)) {
+    current->err = EINVAL;
+    return -1;
+  }
+  Time reqTime = UtilsTimespecToTime (*req);
+  Time remTime = current->process->manager->Wait (reqTime);
+  if (remTime == Seconds (0.0))
+    {
+      return 0;
+    }
+  else
+    {
+      current->err = EINTR;
+      if (rem != 0) *rem = UtilsTimeToTimespec (remTime);
+      return -1;
+    }
+  }
+
+long int simu_random (void) {
+  Thread *current = Current ();
+  return current->process->rndVarible.GetInteger ();
+}
+int simu_rand (void) {
+  Thread *current = Current ();
+  return current->process->rndVarible.GetInteger ();
+}
+
+//ignore seeds as RandomVariable implementation ensures that we take different random streams.
+//TODO: support getting the same rng stream for several processes
+void simu_srandom (unsigned int seed) {
+  return;
+}
+void simu_srand (unsigned int seed) {
+  return;
+}
+
+const char *simu_inet_ntop(int af, const void *src,
+			   char *dst, socklen_t cnt)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << af << src << dst << cnt);
+  Thread *current = Current ();
+  const char *retval = inet_ntop (af, src, dst, cnt);
+  if (retval == 0)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+
+
+
+
+
+int simu_getopt_r (int argc, char * const argv[], const char *optstring, 
+		   char **poptarg, int *poptind, int *popterr, int *poptopt)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << argc << argv << optstring << poptarg << 
+		   poptind << popterr << poptopt);
+  NS_ASSERT (Current () != 0);
+  NS_LOG_DEBUG ("optind=" << *poptind << 
+		" opterr=" << *popterr << 
+		" optopt=" << *poptopt);
+  /* The following is pretty evil but it all comes down to the fact
+   * that the libc does not export getopt_internal_r which is really the
+   * function we want to call here.
+   */
+  char *optargsaved = optarg;
+  int optindsaved = optind;
+  int opterrsaved = opterr;
+  int optoptsaved = optopt;
+  optarg = *poptarg;
+  optind = *poptind;
+  opterr = *popterr;
+  optopt = *poptopt;
+  int retval = getopt (argc, argv, optstring);
+  *poptarg = optarg;
+  *poptind = optind;
+  *popterr = opterr;
+  *poptopt = optopt;
+  optarg = optargsaved;
+  optind = optindsaved;
+  opterr = opterrsaved;
+  optopt = optoptsaved;
+  return retval;
+}
+int simu_getopt_long_r (int argc, char * const argv[], const char *optstring, 
+                        const struct option *longopts, int *longindex,
+                        char **poptarg, int *poptind, int *popterr, int *poptopt)
+{
+  NS_LOG_FUNCTION (Current () << "node" << UtilsGetNodeId () << argc << argv << optstring << 
+                   longopts << longindex);
+  NS_ASSERT (Current () != 0);
+  /* The following is pretty evil but it all comes down to the fact
+   * that the libc does not export getopt_internal_r which is really the
+   * function we want to call here.
+   */
+  char *optargsaved = optarg;
+  int optindsaved = optind;
+  int opterrsaved = opterr;
+  int optoptsaved = optopt;
+  optarg = *poptarg;
+  optind = *poptind;
+  opterr = *popterr;
+  optopt = *poptopt;
+  int retval = getopt_long (argc, argv, optstring, longopts, longindex);
+  *poptarg = optarg;
+  *poptind = optind;
+  *popterr = opterr;
+  *poptopt = optopt;
+  optarg = optargsaved;
+  optind = optindsaved;
+  opterr = opterrsaved;
+  optopt = optoptsaved;
+  return retval;
+}
+int simu_sched_yield (void)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId ());
+  NS_ASSERT (current != 0);
+  current->process->manager->Yield ();
+  return 0;
+}
+static void Itimer (Process *process)
+{
+  if (!process->itimerInterval.IsZero ())
+    {
+      process->itimer = Simulator::Schedule (process->itimerInterval,
+					     &Itimer, process);
+    }
+  // wakeup one thread
+  UtilsSendSignal (process, SIGALRM);
+}
+int simu_getitimer(int which, struct itimerval *value)
+{
+
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << which << value);
+  NS_ASSERT (current != 0);
+  if (value == 0)
+    {
+      current->err = EFAULT;
+      return -1;
+    }
+  // We don't support other kinds of timers.
+  NS_ASSERT (which == ITIMER_REAL);
+  value->it_interval = UtilsTimeToTimeval (current->process->itimerInterval);
+  value->it_value = UtilsTimeToTimeval (Simulator::GetDelayLeft (current->process->itimer));
+  return 0;
+}
+int simu_setitimer(int which, const struct itimerval *value,
+		   struct itimerval *ovalue)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << which << value << ovalue);
+  NS_ASSERT (current != 0);
+  if (value == 0)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  // We don't support other kinds of timers.
+  NS_ASSERT (which == ITIMER_REAL);
+  if (ovalue != 0)
+    {
+      ovalue->it_interval = UtilsTimeToTimeval (current->process->itimerInterval);
+      ovalue->it_value = UtilsTimeToTimeval (Simulator::GetDelayLeft (current->process->itimer));
+    }
+
+  current->process->itimer.Cancel ();
+  current->process->itimerInterval = UtilsTimevalToTime (value->it_interval);
+  if (value->it_value.tv_sec == 0 &&
+      value->it_value.tv_usec == 0)
+    {
+      return 0;
+    }
+  current->process->itimer = Simulator::Schedule (UtilsTimevalToTime (value->it_value),
+						  &Itimer, current->process);
+  return 0;
+}
+char *simu_getcwd (char *buf, size_t size)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << buf << size);
+  NS_ASSERT (current != 0);
+  uint32_t cwd_size = current->process->cwd.size ();
+  if ((buf != 0 && size < cwd_size + 1)
+      || (buf == 0 && size != 0 && size < cwd_size + 1))
+    {
+      current->err = ERANGE;
+      return 0;
+    }
+  // from here on, we know that we will have enough space
+  // in the buffer for the strcpy
+  if (buf == 0)
+    {
+      if (size == 0)
+	{
+	  buf = (char *)simu_malloc (cwd_size + 1);
+	  size = cwd_size + 1;
+	}
+      else
+	{
+	  buf = (char *)simu_malloc (size);
+	}
+      buf[size-1] = 0;
+    }
+  const char *source = current->process->cwd.c_str ();
+  strcpy (buf, source);
+  return buf;
+}
+char *simu_getwd (char *buf)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << buf);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();  
+  uint32_t cwd_size = current->process->cwd.size ();  
+  if (PATH_MAX < cwd_size + 1)
+    {
+      current->err = ENAMETOOLONG;
+      return 0;
+    }
+  const char *source = current->process->cwd.c_str ();
+  strcpy (buf, source);
+  return buf;  
+}
+char *simu_get_current_dir_name (void)
+{
+  NS_LOG_FUNCTION (Current () << UtilsGetNodeId ());
+  NS_ASSERT (Current () != 0);
+  return simu_getcwd (0, 0);
+}
+
+int simu_chdir(const char *path)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << UtilsGetNodeId ());
+  NS_ASSERT (current != 0);
+
+  int retval;
+  std::string newCwd = UtilsGetRealFilePath (path);
+  // test to see if the target directory exists
+  retval = ::open (newCwd.c_str (), O_DIRECTORY | O_RDONLY);
+  if (retval == -1)
+    {
+      current->err = errno;
+      return -1;
+    }
+  current->process->cwd = UtilsGetVirtualFilePath (path);
+  return 0;
+}
+int simu_fchdir(int fd)
+{
+  //XXX that one is not super trivial to implement.
+  // this fd is coming from the function dirfd
+  return 0;
+}
+
+unsigned simu_if_nametoindex (const char *ifname)
+{
+  int index = 0;
+  Ptr<Node> node = Current ()->process->manager->GetObject<Node> ();
+  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
+
+  for (uint32_t i = 0; i < node->GetNDevices (); ++i)
+    {
+      Ptr<NetDevice> dev = node->GetDevice (i);
+      if (ifname == Names::FindName (dev))
+        {
+          index = ipv4->GetInterfaceForDevice (dev);
+          return index;
+        }
+    }
+  return 0;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/socket-fd-factory.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#include "socket-fd-factory.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED(SocketFdFactory);
+
+TypeId 
+SocketFdFactory::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::SocketFdFactory")
+    .SetParent<Object> ()
+    ;
+  return tid;
+}
+
+SocketFdFactory::~SocketFdFactory ()
+{}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/socket-fd-factory.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,22 @@
+#ifndef SOCKET_FD_FACTORY_H
+#define SOCKET_FD_FACTORY_H
+
+#include "ns3/ptr.h"
+#include "ns3/object.h"
+
+namespace ns3 {
+
+class UnixFd;
+class Object;
+
+class SocketFdFactory : public Object
+{
+ public:
+  static TypeId GetTypeId (void);
+  virtual ~SocketFdFactory ();
+  virtual UnixFd *CreateSocket (int domain, int type, int protocol) = 0;
+};
+
+} // namespace ns3
+
+#endif /* SOCKET_FD_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/sys/simu-ioctl.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,15 @@
+#ifndef SIMU_IOCTL_H
+#define SIMU_IOCTL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_ioctl (int d, int request, char *argp);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* SIMU_IOCTL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/sys/simu-mman.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#ifndef SIMU_MMAN_H
+#define SIMU_MMAN_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *simu_mmap (void *start, size_t length, int prot, int flags,
+		 int fd, off_t offset);
+void *simu_mmap64 (void *start, size_t length, int prot, int flags,
+		   int fd, off64_t offset);
+int simu_munmap (void *start, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_MMAN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/sys/simu-select.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,17 @@
+#ifndef SIMU_SELECT_H
+#define SIMU_SELECT_H
+
+#include <sys/select.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_select(int nfds, fd_set *readfds, fd_set *writefds,
+                  fd_set *exceptfds, struct timeval *timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_SELECT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/sys/simu-socket.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,36 @@
+#ifndef SYS_SIMU_SOCKET_H
+#define SYS_SIMU_SOCKET_H
+
+#include <stdint.h>
+#include <sys/socket.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_socket (int domain, int type, int protocol);
+int simu_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen);
+int simu_connect (int fd, const struct sockaddr *my_addr, socklen_t addrlen);
+int simu_listen (int sockfd, int backlog);
+int simu_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+int simu_shutdown(int s, int how);
+ssize_t simu_recv (int fd, void *buf, size_t count, int flags);
+ssize_t simu_recvfrom(int s, void *buf, size_t len, int flags,
+		      struct sockaddr *from, socklen_t *fromlen);
+ssize_t simu_recvmsg(int s, struct msghdr *msg, int flags);
+int simu_setsockopt(int s, int level, int optname,
+		    const void *optval, socklen_t optlen);
+int simu_getsockopt(int s, int level, int optname,
+		    void *optval, socklen_t *optlen);
+ssize_t simu_send(int s, const void *buf, size_t len, int flags);
+ssize_t simu_sendto(int s, const void *buf, size_t len, int flags,
+		    const struct sockaddr *to, socklen_t tolen);
+ssize_t simu_sendmsg(int s, const struct msghdr *msg, int flags);
+int simu_getsockname(int s, struct sockaddr *name, socklen_t *namelen);
+int simu_getpeername(int s, struct sockaddr *name, socklen_t *namelen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SYS_SIMU_SOCKET_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/sys/simu-stat.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,27 @@
+#ifndef SIMU_STAT_H
+#define SIMU_STAT_H
+
+#include <sys/stat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct stat;
+struct stat64;
+
+int simu_xstat (int ver, const char *path, struct stat *buf);
+int simu_fxstat (int ver, int fd, struct stat *buf);
+int simu_lxstat (int ver, const char *pathname, struct stat *buf);
+
+int simu_xstat64 (int ver, const char *path, struct stat64 *buf);
+int simu_fxstat64 (int ver, int fd, struct stat64 *buf);
+int simu_lxstat64 (int ver, const char *pathname, struct stat64 *buf);
+
+int simu_mkdir(const char *pathname, mode_t mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_STAT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/sys/simu-time.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,21 @@
+#ifndef SYS_SIMU_TIME_H
+#define SYS_SIMU_TIME_H
+
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_gettimeofday (struct timeval *tv, struct timezone *tz);
+int simu_getitimer(int which, struct itimerval *value);
+int simu_setitimer(int which, const struct itimerval *value,
+		   struct itimerval *ovalue);
+int simu_nanosleep(const struct timespec *req, struct timespec *rem);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SYS_SIMU_TIME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/sys/simu-timerfd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,21 @@
+#ifndef SIMU_TIMERFD_H
+#define SIMU_TIMERFD_H
+
+#include <sys/timerfd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int simu_timerfd_create(int clockid, int flags);
+int simu_timerfd_settime(int fd, int flags,
+			 const struct itimerspec *new_value,
+			 struct itimerspec *old_value);
+int simu_timerfd_gettime(int fd, struct itimerspec *curr_value);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIMU_TIMERFD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/system-wrappers.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,562 @@
+#define _GNU_SOURCE 1
+#include "system-wrappers.h"
+#include "trampoline-manager.h"
+#include "simu-fcntl.h"
+#include "simu-unistd.h"
+#include "sys/simu-stat.h"
+#include "ns3/assert.h"
+#include <sys/syscall.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <elf.h>
+#include <stdlib.h>
+#include <string>
+
+
+namespace ns3 {
+
+enum State {
+  ENABLED,
+  NOOP,
+  DISABLED
+};
+static enum State g_state = DISABLED;
+
+extern "C" int system_open(const char *pathname, int flags, mode_t mode)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      {
+	long int status = syscall (__NR_open, (unsigned long)pathname, flags, mode);
+	return status;
+      }
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	ssize_t retval = simu_open (pathname, flags, mode);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;  
+}
+extern "C" int system_close (int fd)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      {
+	long int status = syscall (SYS_close, (unsigned long)fd);
+	return status;
+      }
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	ssize_t retval = simu_close (fd);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+extern "C" ssize_t system_write(int fd, const void *buf, size_t count)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      {
+	long int status = syscall (SYS_write, fd, (unsigned long)buf, count);
+	return status;
+      }
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	ssize_t retval = simu_write (fd, buf, count);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+extern "C" ssize_t system_read(int fd, void *buf, size_t count)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      {
+	long int status = syscall (SYS_read, fd, (unsigned long)buf, count);
+	return status;
+      }
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	ssize_t retval = simu_read (fd, buf, count);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+extern "C" ssize_t system_fcntl (int fd, int cmd, long arg)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      {
+	long int status = syscall (SYS_fcntl, fd, cmd, arg);
+	return status;
+      }
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	ssize_t retval = simu_fcntl (fd, cmd, arg);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+
+extern "C" off_t system_lseek(int fd, off_t offset, int whence)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      {
+	long int status = syscall (SYS_lseek, fd, offset, whence);
+	return status;
+      }
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	off_t retval = simu_lseek (fd, offset, whence);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+#if defined (__i386__)
+extern "C" off64_t system_llseek(int fd, off64_t offset, int whence)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      {
+	off64_t result;
+	off_t offset_high = (offset >> 32) & 0xffffffff;
+	off_t offset_low = offset & 0xffffffff;
+	int status = syscall (SYS__llseek, fd, offset_high, offset_low, &result, whence);
+	if (status == 0)
+	  {
+	    return result;
+	  }
+	return status;
+      }
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	off64_t retval = simu_lseek64 (fd, offset, whence);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+
+
+extern "C" int system_fxstat64(int ver, int fd, struct stat64 *buf)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      if (ver == 0)
+	{
+	  long int status = syscall (SYS_fstat64, fd, buf);
+	  return status;
+	}
+      else
+	{
+	  // the structure expected by the kernel for fstat
+	  struct kernel_stat 
+	  {
+	    unsigned long long st_dev;
+	    unsigned char __pad0[4];
+	    unsigned long __st_ino;
+	    unsigned int st_mode;
+	    unsigned int st_nlink;
+	    unsigned long st_uid;
+	    unsigned long st_gid;
+	    unsigned long long st_rdev;
+	    unsigned char __pad3[4];
+	    unsigned long long st_size;
+	    unsigned long st_blksize;
+	    unsigned long long st_blocks;
+	    unsigned long st_atim;
+	    unsigned long st_atim_nsec;
+	    unsigned long st_mtim;
+	    unsigned int st_mtim_nsec;
+	    unsigned long st_ctim;
+	    unsigned long st_ctim_nsec;
+	    unsigned long long st_ino;
+	  } kbuf;
+	  long int status = syscall (SYS_fstat64, fd, &kbuf);
+	  buf->st_dev = kbuf.st_dev;
+	  buf->st_ino = kbuf.st_ino;
+	  buf->st_mode = kbuf.st_mode;
+	  buf->st_nlink = kbuf.st_nlink;
+	  buf->st_uid = kbuf.st_uid;
+	  buf->st_gid = kbuf.st_gid;
+	  buf->st_rdev = kbuf.st_rdev;
+	  buf->st_size = kbuf.st_size;
+	  buf->st_blksize = kbuf.st_blksize;
+	  buf->st_blocks = kbuf.st_blocks;
+	  buf->st_atime = kbuf.st_atim;
+	  buf->st_mtime = kbuf.st_mtim;
+	  buf->st_ctime = kbuf.st_ctim;
+	  return status;
+	}
+      break;
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	off_t retval = simu_fxstat64 (ver, fd, buf);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+extern "C" int system_fxstat(int ver, int fd, struct stat *buf)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      if (ver == 0)
+	{
+	  long int status = syscall (SYS_fstat, fd, buf);
+	  return status;
+	}
+      else
+	{
+	  // the structure expected by the kernel for fstat
+	  struct kernel_stat 
+	  {
+	    unsigned long st_dev;
+	    unsigned long st_ino;
+	    unsigned short st_mode;
+	    unsigned short st_nlink;
+	    unsigned short st_uid;
+	    unsigned short st_gid;
+	    unsigned long st_rdev;
+	    unsigned long st_size;
+	    unsigned long st_blksize;
+	    unsigned long st_blocks;
+	    unsigned long st_atim;
+	    unsigned long st_atim_nsec;
+	    unsigned long st_mtim;
+	    unsigned long st_mtim_nsec;
+	    unsigned long st_ctim;
+	    unsigned long st_ctim_nsec;
+	    unsigned long __unused4;
+	    unsigned long __unused5;
+	  } kbuf;
+	  long int status = syscall (SYS_fstat, fd, &kbuf);
+	  buf->st_dev = kbuf.st_dev;
+	  buf->st_ino = kbuf.st_ino;
+	  buf->st_mode = kbuf.st_mode;
+	  buf->st_nlink = kbuf.st_nlink;
+	  buf->st_uid = kbuf.st_uid;
+	  buf->st_gid = kbuf.st_gid;
+	  buf->st_rdev = kbuf.st_rdev;
+	  buf->st_size = kbuf.st_size;
+	  buf->st_blksize = kbuf.st_blksize;
+	  buf->st_blocks = kbuf.st_blocks;
+	  buf->st_atime = kbuf.st_atim;
+	  buf->st_mtime = kbuf.st_mtim;
+	  buf->st_ctime = kbuf.st_ctim;
+	  return status;
+	}
+      break;
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	off_t retval = simu_fxstat (ver, fd, buf);
+	g_state = ENABLED;
+	return retval;
+      }
+    }
+  // quiet compiler
+  return 0;
+}
+
+#elif defined (__x86_64__)
+
+extern "C" int system_fxstat(int ver, int fd, struct stat *buf)
+{
+  switch (g_state)
+    {
+    case NOOP:
+      return -1;
+    case DISABLED:
+      if (ver == 0)
+	{
+	  long int status = syscall (SYS_fstat, fd, buf);
+	  return status;
+	}
+      else
+	{
+	  // the structure expected by the kernel for fstat
+	  struct kernel_stat
+	  {
+	    unsigned long   st_dev;
+	    unsigned long   st_ino;
+	    unsigned long   st_nlink;
+	    unsigned int    st_mode;
+	    unsigned int    st_uid;
+	    unsigned int    st_gid;
+	    unsigned int    __pad0;
+	    unsigned long   st_rdev;
+	    long            st_size;
+	    long            st_blksize;
+	    long            st_blocks;
+	    unsigned long   st_atim;
+	    unsigned long   st_atim_nsec;
+	    unsigned long   st_mtim;
+	    unsigned long   st_mtim_nsec;
+	    unsigned long   st_ctim;
+	    unsigned long   st_ctim_nsec;
+	    long            __unused[3];
+	  } kbuf;
+	  long int status = syscall (SYS_fstat, fd, &kbuf);
+	  buf->st_dev = kbuf.st_dev;
+	  buf->st_ino = kbuf.st_ino;
+	  buf->st_mode = kbuf.st_mode;
+	  buf->st_nlink = kbuf.st_nlink;
+	  buf->st_uid = kbuf.st_uid;
+	  buf->st_gid = kbuf.st_gid;
+	  buf->st_rdev = kbuf.st_rdev;
+	  buf->st_size = kbuf.st_size;
+	  buf->st_blksize = kbuf.st_blksize;
+	  buf->st_blocks = kbuf.st_blocks;
+	  buf->st_atime = kbuf.st_atim;
+	  buf->st_mtime = kbuf.st_mtim;
+	  buf->st_ctime = kbuf.st_ctim;
+	  return status;
+	}
+      break;
+    case ENABLED:
+      {
+	g_state = DISABLED;
+	off_t retval = simu_fxstat (ver, fd, buf);
+	g_state = ENABLED;
+	return retval;
+      }
+    } 
+  // quiet compiler
+  return 0;
+}
+
+#else
+#error "Need a definition for this platform"
+#endif
+
+
+static ElfW(Shdr)
+read_section (int fd, ElfW(Ehdr) header, int i)
+{
+  // helper functions for function below.
+  off_t offset;
+  offset = lseek (fd, header.e_shoff + i * header.e_shentsize, SEEK_SET);
+  NS_ASSERT (offset != -1);
+  ElfW(Shdr) section;
+  ssize_t bytes_read;
+  bytes_read = read (fd, &section, sizeof (section));
+  NS_ASSERT (bytes_read == sizeof(section));
+  return section;
+}
+
+static void *
+lookup_symbol (unsigned int symbol_section_type, const char *library, const char *symbol)
+{
+  struct link_map *map;
+  void *h = dlopen (library, RTLD_LAZY);
+  int status = dlinfo (h, RTLD_DI_LINKMAP, &map);
+  if (status == -1)
+    {
+      return 0;
+    }
+  const char *abs_filename = map->l_name;
+  int fd = open (abs_filename, O_RDONLY);
+  ElfW(Ehdr) header;
+  ssize_t bytes_read = read (fd, &header, sizeof (header));
+  if (bytes_read != sizeof (header))
+    {
+      close (fd);
+      return 0;
+    }
+  unsigned long symtab_offset = 0;
+  unsigned long symtab_size = 0;
+  unsigned long symtab_strtab_index = 0;
+  unsigned long symtab_entry_size = 0;
+  for (int i = 0; i < header.e_shnum; i++)
+    {
+      ElfW(Shdr) section = read_section (fd, header, i);
+      if (section.sh_type == symbol_section_type)
+	{
+	  symtab_offset = section.sh_offset;
+	  symtab_size = section.sh_size;
+	  symtab_strtab_index = section.sh_link;
+	  symtab_entry_size = section.sh_entsize;
+	  break;
+	}
+    }
+  if (symtab_offset == 0)
+    {
+      return 0;
+    }
+  ElfW(Shdr) section = read_section (fd, header, symtab_strtab_index);
+  unsigned long strtab_offset = section.sh_offset;
+  unsigned long strtab_size = section.sh_size;
+
+  char *strtab = (char *)malloc (strtab_size);
+  lseek (fd, strtab_offset, SEEK_SET);
+  read (fd, strtab, strtab_size);
+
+  ElfW(Sym) *symtab = (ElfW(Sym)*)malloc (symtab_size);
+  lseek (fd, symtab_offset, SEEK_SET);
+  read (fd, symtab, symtab_size);
+
+  unsigned long symbol_value = 0;
+  for (unsigned int i = 0; i < symtab_size / symtab_entry_size; i++)
+    {
+      if (symtab[i].st_name == 0)
+	{
+	  continue;
+	}
+      char *str = &strtab[symtab[i].st_name];
+      if (std::string (str) != symbol)
+	{
+	  continue;
+	}
+      // yay ! we have our symbol.
+      symbol_value = symtab[i].st_value;
+      break;
+    }
+
+  if (symbol_value == 0)
+    {
+      return 0;
+    }
+
+  // add base address of library.
+  symbol_value += map->l_addr;
+
+  free (strtab);
+  free (symtab);
+  close (fd);
+
+  return (void*)symbol_value;
+}
+
+static void *
+lookup_symbol (const char *library, const char *symbol)
+{
+  /**
+   * We have to perform the symbol lookup ourselves because dlsym
+   * does not work for us. i.e., dlsym searches only for symbols
+   * exported by the dynamic symbol section of a binary while what
+   * we need here is to find symbols which are not exported
+   * from the binary. So, we have to search for the SHT_SYMTAB
+   * section and parse it until we find our target symbols.
+   */
+  void *address = lookup_symbol (SHT_SYMTAB, library, symbol);
+  if (address == 0)
+    {
+      address = lookup_symbol (SHT_DYNSYM, library, symbol);
+    }
+  return address;
+}
+
+
+static void initialize_wrappers (void)
+{
+  static bool initialized = false;
+  if (initialized)
+    {
+      return;
+    }
+  initialized = true;
+  struct Wrapper {
+    const char *name;
+    void * wrapper;
+  } wrappers [] = {
+    {"__open", (void *)&system_open},
+    {"__open_nocancel", (void *)&system_open},
+    {"__close", (void *)&system_close},
+    {"__close_nocancel", (void *) &system_close},
+    {"__write", (void *)&system_write},
+    {"__read", (void *)&system_read},
+    {"__fcntl", (void *)&system_fcntl},
+    {"__lseek", (void *)&system_lseek},
+    {"__fxstat", (void *)&system_fxstat},
+#if defined (__i386__)
+    {"__llseek", (void *)&system_llseek},
+    {"__fxstat64", (void *)&system_fxstat64},
+#endif
+    // XXX: others ?
+  };
+
+  TrampolineManager *t = TrampolineManager::Instance ();
+  for (int i = 0; i != sizeof(wrappers)/sizeof(struct Wrapper); i++)
+    {
+      void *symbol = lookup_symbol ("libc.so.6", wrappers[i].name);
+      bool ok;
+      ok = t->Insert ((unsigned long)symbol, (unsigned long)wrappers[i].wrapper);
+      NS_ASSERT (ok);      
+    }
+}
+void SystemWrappersEnable (void)
+{
+  initialize_wrappers ();
+  g_state = ENABLED;
+}
+void SystemWrappersEnableNoop (void)
+{
+  initialize_wrappers ();
+  g_state = NOOP;
+}
+void SystemWrappersDisable (void)
+{
+  g_state = DISABLED;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/system-wrappers.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,12 @@
+#ifndef SYSTEM_WRAPPERS_H
+#define SYSTEM_WRAPPERS_H
+
+namespace ns3 {
+
+void SystemWrappersEnable (void);
+void SystemWrappersEnableNoop (void);
+void SystemWrappersDisable (void);
+
+} // namespace ns3
+
+#endif /* SYSTEM_WRAPPERS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/task-manager.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,382 @@
+#include "task-manager.h"
+#include "fiber-manager.h"
+#include "ucontext-fiber-manager.h"
+#include "pthread-fiber-manager.h"
+#include "task-scheduler.h"
+#include "ns3/log.h"
+#include "ns3/uinteger.h"
+#include "ns3/enum.h"
+#include "ns3/simulator.h"
+#include "ns3/node.h"
+#include "ns3/node-list.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE("TaskManager");
+NS_OBJECT_ENSURE_REGISTERED(TaskManager);
+
+bool 
+Task::IsActive (void) const
+{
+  return m_state == Task::ACTIVE;
+}
+bool 
+Task::IsRunning (void) const
+{
+  return m_state == Task::RUNNING;
+}
+bool 
+Task::IsBlocked (void) const
+{
+  return m_state == Task::BLOCKED;
+}
+bool 
+Task::IsDead (void) const
+{
+  return m_state == Task::DEAD;
+}
+void
+Task::SetExtraContext (void *ctx)
+{
+  m_extraContext = ctx;
+}
+void
+Task::SetContext (void *ctx)
+{
+  m_context = ctx;
+}
+void *
+Task::GetExtraContext (void) const
+{
+  return m_extraContext;
+}
+void *
+Task::GetContext (void) const
+{
+  return m_context;
+}
+
+void 
+Task::SetSwitchNotifier (void (*fn) (enum SwitchType, void *), void *context)
+{
+  m_switchNotifier = fn;
+  m_switchNotifierContext = context;
+}
+
+Task::~Task ()
+{}
+
+
+TypeId 
+TaskManager::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::TaskManager")
+    .SetParent<Object> ()
+    .AddConstructor<TaskManager> ()
+    .AddAttribute ("DefaultStackSize", 
+                   "The default size of the stack of every task created by this manager.",
+                   UintegerValue (8192),
+                   MakeUintegerAccessor (&TaskManager::m_defaultStackSize),
+                   MakeUintegerChecker<uint32_t> (4096))
+    .AddAttribute ("FiberManagerType", 
+                   "The type of FiberManager implementation to use to allocate, " 
+                   "deallocate and switch among fibers.",
+                   TypeId::ATTR_CONSTRUCT,
+                   EnumValue (PTHREAD_FIBER_MANAGER),
+                   MakeEnumAccessor (&TaskManager::SetFiberManagerType),
+                   MakeEnumChecker (PTHREAD_FIBER_MANAGER, "PthreadFiberManager",
+                                    UCONTEXT_FIBER_MANAGER, "UcontextFiberManager"))
+    ;
+  return tid;
+}
+
+TaskManager::TaskManager ()
+  : m_current (0),
+    m_scheduler (0),
+    m_fiberManager (0)
+{
+  NS_LOG_FUNCTION (this);
+}
+TaskManager::~TaskManager ()
+{
+  NS_LOG_FUNCTION (this);
+  GarbageCollectDeadTasks ();
+  m_fiberManager->Delete (m_mainFiber);
+  delete m_fiberManager;
+
+  m_mainFiber = 0;
+  m_fiberManager = 0;
+  m_scheduler = 0;
+}
+
+void TaskManager::DoDispose (void)
+{
+  Object::DoDispose ();
+}
+
+void
+TaskManager::GarbageCollectDeadTasks (void)
+{
+  NS_LOG_FUNCTION (this);
+  while (!m_deadTasks.empty ())
+    {
+      Task *task = m_deadTasks.front ();
+      m_deadTasks.pop_front ();
+      NS_LOG_DEBUG ("delete " << task);
+      m_fiberManager->Delete (task->m_fiber);
+      task->m_waitTimer.Cancel ();
+      task->m_fiber = 0;
+      delete task;
+    }
+  m_deadTasks.clear ();
+  m_nextGc.Cancel ();
+}
+
+
+void 
+TaskManager::SetScheduler (Ptr<TaskScheduler> scheduler)
+{
+  m_scheduler = scheduler;
+}
+
+Task *
+TaskManager::Start (void (*fn)(void*), void *context)
+{
+  return Start (fn, context, m_defaultStackSize);
+}
+Task *
+TaskManager::Start (void (*fn)(void*), void *context, uint32_t stackSize)
+{
+  NS_LOG_FUNCTION (this << fn << context << stackSize);
+  Task *task = new Task ();
+  struct StartTaskContext *ctx = new StartTaskContext ();
+  ctx->function = fn;
+  ctx->context = context;
+  task->m_fiber = m_fiberManager->Create (&TaskManager::Trampoline, ctx, stackSize);
+  NS_LOG_DEBUG ("create " << task << " fiber=" << task->m_fiber);
+  task->m_state = Task::BLOCKED; // must call Wakeup on task later.
+  task->m_context = 0;
+  task->m_extraContext = 0;
+  task->m_switchNotifier = 0;
+  task->m_switchNotifierContext = 0;
+  Wakeup (task);
+  return task;
+}
+
+void
+TaskManager::Trampoline (void *context)
+{
+  struct StartTaskContext *ctx = (struct StartTaskContext *)context;
+  void (*fn) (void*) = ctx->function;
+  void *fn_context = ctx->context;
+  delete ctx;
+  fn (fn_context);
+  NS_FATAL_ERROR ("The user function must not return.");
+}
+
+void 
+TaskManager::Stop (Task *task)
+{
+  NS_LOG_FUNCTION (this << task);
+  if (m_current == task)
+    {
+      // we ignore Stop on self.
+      return;
+    }
+
+  // we can delete the task immediately.
+  NS_LOG_DEBUG ("delete " << task << " fiber=" << task->m_fiber);
+  m_fiberManager->Delete (task->m_fiber);
+  task->m_state = Task::DEAD;
+  task->m_waitTimer.Cancel ();
+  task->m_fiber = 0;
+  delete task;
+}
+
+void 
+TaskManager::Wakeup (Task *task)
+{
+  NS_LOG_FUNCTION (this << task << task->m_state);
+  if (task->m_state == Task::ACTIVE 
+      || task->m_state == Task::RUNNING)
+    {
+      return;
+    }
+  task->m_state = Task::ACTIVE;
+  m_scheduler->Enqueue (task);
+  if (!m_nextSchedule.IsRunning ())
+    {
+      m_nextSchedule = Simulator::ScheduleNow (&TaskManager::Schedule, this);
+    }
+}
+
+void 
+TaskManager::Sleep (void)
+{
+  NS_LOG_FUNCTION (this << m_current);
+  NS_ASSERT (m_current != 0);
+  NS_ASSERT (m_current->m_state == Task::RUNNING);
+  Task *current = m_current;
+  current->m_state = Task::BLOCKED;
+  Schedule ();
+}
+
+Time 
+TaskManager::Sleep (Time timeout)
+{
+  NS_LOG_FUNCTION (this << m_current);
+  NS_ASSERT (m_current != 0);
+  NS_ASSERT (m_current->m_state == Task::RUNNING);
+  Time expectedEnd = Simulator::Now () + timeout;
+  Task *current = m_current;
+  current->m_state = Task::BLOCKED;
+  if (!timeout.IsZero ())
+    {
+      current->m_waitTimer = Simulator::Schedule (timeout, &TaskManager::EndWait, this, current);
+    }
+  Schedule ();
+  current->m_waitTimer.Cancel ();
+  if (!timeout.IsZero () 
+      && Simulator::Now () <= expectedEnd)
+    {
+      return expectedEnd - Simulator::Now ();
+    }
+  return Seconds (0.0);
+}
+void 
+TaskManager::Yield (void)
+{
+  NS_LOG_FUNCTION (this << m_current);
+  NS_ASSERT (m_current != 0);
+  NS_ASSERT (m_current->m_state == Task::RUNNING);
+  // re-queue to make sure it will be handled.
+  m_current->m_state = Task::ACTIVE;
+  m_scheduler->Enqueue (m_current);
+  Schedule ();
+}
+void 
+TaskManager::Exit (void)
+{
+  NS_LOG_FUNCTION (this << m_current);
+  NS_ASSERT (m_current != 0);
+  NS_ASSERT (m_current->m_state == Task::RUNNING);
+  Task *current = m_current;
+  current->m_state = Task::DEAD;
+  current->m_waitTimer.Cancel ();
+  m_deadTasks.push_back (current);
+  if (!m_nextGc.IsRunning ())
+    {
+      m_nextGc = Simulator::ScheduleNow (&TaskManager::GarbageCollectDeadTasks, this);
+    }
+  Schedule ();
+}
+
+Task *
+TaskManager::CurrentTask (void)
+{
+  return m_current;
+}
+TaskManager *
+TaskManager::Current (void)
+{
+  uint32_t nodeId = Simulator::GetContext ();
+  if (nodeId == 0xffffffff)
+    {
+      return 0;
+    }
+  Ptr<Node> node = NodeList::GetNode (nodeId);
+  Ptr<TaskManager> manager = node->GetObject<TaskManager> ();
+  return PeekPointer (manager);
+}
+
+void
+TaskManager::Schedule (void)
+{
+  NS_LOG_FUNCTION (this);
+  if (m_current == 0)
+    {
+      // we have nothing to schedule from
+      struct Task *next = m_scheduler->PeekNext ();
+      if (next != 0)
+	{
+	  // and now, we have something to schedule to.
+	  NS_LOG_DEBUG ("Leaving main, entering " << next);
+	  m_scheduler->DequeueNext ();
+	  m_current = next;
+	  NS_ASSERT (next->m_state == Task::ACTIVE);
+	  next->m_state = Task::RUNNING;
+	  if (next->m_switchNotifier != 0)
+	    {
+	      next->m_switchNotifier (Task::TO, next->m_switchNotifierContext);
+	    }
+          m_fiberManager->SwitchTo (m_mainFiber, next->m_fiber);
+	}
+      else
+	{
+	  // but, we have nothing to schedule to.
+	}
+    }
+  else
+    {
+      // we have something to schedule from.
+      // but, we have nothing to schedule to so, we go back to the main task.
+      NS_LOG_DEBUG ("Leaving " << m_current <<", entering main");
+      struct Task *next = m_scheduler->PeekNext ();
+      if (next != 0)
+	{
+	  // but before leaving, we check if we have further processes active, and,
+	  // if so, make sure we will schedule them later.
+	  Simulator::ScheduleNow (&TaskManager::Schedule, this);
+	}
+      struct Fiber *fiber = m_current->m_fiber;
+      if (m_current->m_switchNotifier != 0)
+	{
+	  m_current->m_switchNotifier (Task::FROM, m_current->m_switchNotifierContext);
+	}
+      m_current = 0;
+      m_fiberManager->SwitchTo (fiber, m_mainFiber);
+    }
+}
+
+void 
+TaskManager::SetFiberManagerType (enum FiberManagerType type)
+{
+  NS_LOG_FUNCTION (this << type);
+  switch (type)
+    {
+    case UCONTEXT_FIBER_MANAGER:
+      m_fiberManager = new UcontextFiberManager ();
+      break;
+    case PTHREAD_FIBER_MANAGER:
+      m_fiberManager = new PthreadFiberManager ();
+      break;
+    default:
+      NS_ASSERT (false);
+      break;
+    }
+  m_mainFiber = m_fiberManager->CreateFromCaller ();
+}
+
+
+void
+TaskManager::EndWait (Task *task)
+{
+  if (task->m_state == Task::BLOCKED)
+    {
+      Wakeup (task);
+    }
+}
+
+void 
+TaskManager::SetSwitchNotify (void (*fn) (void))
+{
+  m_fiberManager->SetSwitchNotification (fn);
+}
+uint32_t 
+TaskManager::GetStackSize (Task *task) const
+{
+  return m_fiberManager->GetStackSize (task->m_fiber);
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/task-manager.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,158 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#ifndef TASK_MANAGER_H
+#define TASK_MANAGER_H
+
+#include "ns3/object.h"
+#include "ns3/event-id.h"
+#include "ns3/nstime.h"
+#include <list>
+
+namespace ns3 {
+
+class TaskScheduler;
+class Fiber;
+class FiberManager;
+
+class Task
+{
+public:
+  enum SwitchType {
+    TO,
+    FROM
+  };
+  bool IsActive (void) const;
+  bool IsRunning (void) const;
+  bool IsBlocked (void) const;
+  bool IsDead (void) const;
+
+  void SetExtraContext (void *ctx);
+  void SetContext (void *ctx);
+
+  void *GetExtraContext (void) const;
+  void *GetContext (void) const;
+
+  void SetSwitchNotifier (void (*fn) (enum SwitchType, void *), void *context);
+private:
+  friend class TaskManager;
+  ~Task ();
+  enum State
+  {
+    RUNNING,
+    ACTIVE,
+    BLOCKED,
+    DEAD
+  };
+  enum State m_state;
+  Fiber *m_fiber;
+  EventId m_waitTimer;
+  void *m_context;
+  void *m_extraContext;
+  void (*m_switchNotifier) (enum SwitchType, void *);
+  void *m_switchNotifierContext;
+};
+
+class TaskManager : public Object
+{
+public:
+  static TypeId GetTypeId (void);
+
+  TaskManager ();
+  virtual ~TaskManager ();
+
+  void SetScheduler (Ptr<TaskScheduler> scheduler);
+
+  /**
+   * Create a task and schedule it to run later.
+   * The input context is forever associated to this task and
+   * can be retrieved by a call to CurrentTaskContext.
+   */
+  Task *Start (void (*fn)(void*), void *context);
+  Task *Start (void (*fn)(void*), void *context, uint32_t stackSize);
+
+  /**
+   * Stop and delete a task. This task will never run again.
+   * This method returns immediately.
+   */
+  void Stop (Task *task);
+
+  /**
+   * Schedule the input task to run later.
+   * This method returns immediately.
+   */
+  void Wakeup (Task *task);
+
+  /**
+   * This method blocks and returns only when someone calls Wakeup on
+   * this task.
+   */
+  void Sleep (void);
+  /**
+   * This method blocks and returns when someone calls Wakeup on
+   * this task or timeout elapsed. Returns the amount of time
+   * left until the timeout elapses.
+   */
+  Time Sleep (Time timeout);
+  /**
+   * This method blocks if other tasks can be scheduled but it
+   * will return immediately if the current task is the only
+   * active task.
+   */
+  void Yield (void);
+  /**
+   * This method blocks and never returns. The current task
+   * is asynchronously deleted at the next available opportunity.
+   */
+  void Exit (void);
+
+  /**
+   * Returns currently-executing task or 0 if no tasks are currently
+   * running.
+   */
+  Task *CurrentTask (void);
+  /**
+   * Returns the 'current' task manager.
+   * Note that this function does not return a reference (i.e., the caller does not
+   * need to call Unref on the object returned). This is done on purpose to avoid
+   * problems due to a task calling Current, storing the reference on the stack,
+   * calling Exit, and the destructor of the caller stack frame never being called
+   * during process unloading, hence resulting in a lost reference and a leak.
+   * This is also why we don't return a Ptr<TaskManager> because it would increase
+   * the reference count and thus lose references when the caller's stack is ripped
+   * out.
+   */
+  static TaskManager *Current (void);
+
+  void SetSwitchNotify (void (*fn) (void));
+  uint32_t GetStackSize (Task *task) const;
+private:
+  enum FiberManagerType
+    {
+      UCONTEXT_FIBER_MANAGER,
+      PTHREAD_FIBER_MANAGER,
+    };
+  struct StartTaskContext
+  {
+    void (*function)(void *);
+    void *context;
+  };
+
+  virtual void DoDispose (void);
+  void Schedule (void);
+  void SetFiberManagerType (enum FiberManagerType type);
+  void GarbageCollectDeadTasks (void);
+  void EndWait (Task *task);
+  static void Trampoline (void *context);
+
+  Task *m_current;
+  Ptr<TaskScheduler> m_scheduler;
+  FiberManager *m_fiberManager;
+  Fiber *m_mainFiber;
+  uint32_t m_defaultStackSize;
+  EventId m_nextSchedule;
+  EventId m_nextGc;
+  std::list<Task *> m_deadTasks;
+};
+
+} // namespace
+
+#endif /* TASK_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/task-scheduler.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,35 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 "task-scheduler.h"
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (TaskScheduler);
+
+TypeId 
+TaskScheduler::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::TaskScheduler")
+    .SetParent<Object> ()
+    ;
+  return tid;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/task-scheduler.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,58 @@
+/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * 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 TASK_SCHEDULER_H
+#define TASK_SCHEDULER_H
+
+#include "ns3/object.h"
+
+namespace ns3 {
+
+class Task;
+
+/**
+ * \brief maintains the list of active (eligible to run) taskes.
+ */
+class TaskScheduler : public Object
+{
+public:
+  static TypeId GetTypeId (void);
+
+  /**
+   * \returns the task which will be removed by
+   *          TaskScheduler::DequeueNext
+   */
+  virtual struct Task *PeekNext (void) = 0;
+  /**
+   * Remove the 'active' task most eligible to become
+   * the new 'current' task.
+   */
+  virtual void DequeueNext (void) = 0;
+  /**
+   * \param task a task to add to the list of 'active' tasks.
+   */
+  virtual void Enqueue (struct Task *task) = 0;
+  
+  virtual void Dequeue (struct Task *task) = 0;
+  
+};
+
+} // namespace ns3
+
+#endif /* TASK_SCHEDULER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/trampoline-manager.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,301 @@
+#include <sys/mman.h>
+#include <string.h>
+#include <stdint.h>
+#include <vector>
+#include "ns3/fatal-error.h"
+#include "trampoline-manager.h"
+
+namespace {
+
+static void
+Copy (unsigned long to, uint8_t *from, uint32_t size)
+{
+  unsigned long page_start = to / 4096 * 4096;
+  int status = mprotect ((void*)page_start, 4096, PROT_WRITE);
+  if (status != 0)
+    {
+      NS_FATAL_ERROR ("Could not setup trampoline at=" << to);
+    }
+  memcpy ((void*)to, from, size);
+  status = mprotect ((void *)page_start, 4096, PROT_READ | PROT_EXEC);
+  if (status != 0)
+    {
+      NS_FATAL_ERROR ("Could not setup trampoline at=" << to);
+    }
+}
+
+}
+
+#if defined (__i386__)
+
+namespace ns3 {
+
+class TrampolineManagerImpl
+{
+public:
+  TrampolineManagerImpl ();
+  ~TrampolineManagerImpl ();
+  bool Insert (unsigned long from, unsigned long to);
+};
+
+TrampolineManagerImpl::TrampolineManagerImpl ()
+{}
+TrampolineManagerImpl::~TrampolineManagerImpl ()
+{}
+bool 
+TrampolineManagerImpl::Insert (unsigned long from, unsigned long to)
+{
+  signed long delta = to;
+  delta -= from + 5;
+  unsigned long delta_unsigned = delta;
+  unsigned char buffer[5];
+  buffer[0] = 0xe9;
+  buffer[1] = (delta_unsigned >> 0) & 0xff;
+  buffer[2] = (delta_unsigned >> 8) & 0xff;
+  buffer[3] = (delta_unsigned >> 16) & 0xff;
+  buffer[4] = (delta_unsigned >> 24) & 0xff;
+  Copy (from, buffer, 5);
+  return true;
+}
+
+} // namespace ns3
+
+#elif defined (__x86_64__)
+
+#define _GNU_SOURCE 1 // for dl_iterate_phdr
+#include "trampoline-manager.h"
+#include "ns3/fatal-error.h"
+#include "ns3/assert.h"
+#include <link.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+
+extern "C" struct dl_phdr_info;
+
+namespace ns3 {
+
+class TrampolineManagerImpl
+{
+public:
+  TrampolineManagerImpl ();
+  ~TrampolineManagerImpl ();
+  bool Insert (unsigned long from, unsigned long to);
+ private:
+  struct Trampoline
+  {
+    unsigned long from;
+    unsigned long to;
+  };
+
+  static int IteratePhdr (struct dl_phdr_info *info,
+			  size_t size, void *data);
+  static unsigned long RoundUp (unsigned long value, unsigned long round);
+  void SetupStage0 (unsigned long from, unsigned long to);
+  void SetupStage1 (unsigned long from, unsigned long to);
+  void AddPatch (unsigned long at, unsigned long length);
+
+  
+  // array of to addresses
+  unsigned long *m_to;
+  // array of from addresses
+  unsigned long *m_from;
+  int8_t m_nTrampolines;
+  struct Patch
+  {
+    unsigned long at;
+    uint8_t *originalData;
+    unsigned long originalDataLength;
+  };
+  std::vector<struct Patch> m_patches;
+};
+
+struct TrampolineData
+{
+  unsigned long to;
+  unsigned long from;
+  unsigned long temporary;
+};
+
+
+TrampolineManagerImpl::TrampolineManagerImpl ()
+  : m_to (0),
+    m_from (0),
+    m_nTrampolines (0)
+{}
+TrampolineManagerImpl::~TrampolineManagerImpl ()
+{
+  for (uint32_t i = 0; i < m_patches.size (); i++)
+    {
+      struct Patch patch = m_patches[i];
+      Copy (patch.at, patch.originalData, patch.originalDataLength);
+      delete [] patch.originalData;
+    }
+  m_patches.clear ();
+  delete [] m_to;
+  delete [] m_from;
+}
+void 
+TrampolineManagerImpl::AddPatch (unsigned long at, unsigned long length)
+{
+  struct Patch patch;
+  patch.at = at;
+  patch.originalData = new uint8_t [length] ();
+  uint8_t *buffer = (uint8_t *)at;
+  memcpy (patch.originalData, buffer, length);
+  patch.originalDataLength = length;
+  m_patches.push_back (patch);
+}
+unsigned long
+TrampolineManagerImpl::RoundUp (unsigned long value, unsigned long round)
+{
+  if ((value % round) == 0)
+    {
+      return value;
+    }
+  unsigned long n = value / round;
+  return (n + 1) * round;
+}
+void
+TrampolineManagerImpl::SetupStage0 (unsigned long from, unsigned long to)
+{
+  AddPatch (from, 9);
+  signed long delta = to;
+  delta -= from + (2+2+5);
+  unsigned long udelta = delta;
+  unsigned char buffer[9];
+  // push trampoline index
+  buffer[0] = 0x6a;
+  buffer[1] = m_nTrampolines;
+  // pop %r11
+  buffer[2] = 0x41;
+  buffer[3] = 0x5b;
+  // jmp delta
+  buffer[4] = 0xe9;
+  buffer[5] = (udelta >> 0) & 0xff;
+  buffer[6] = (udelta >> 8) & 0xff;
+  buffer[7] = (udelta >> 16) & 0xff;
+  buffer[8] = (udelta >> 24) & 0xff;
+  Copy (from, buffer, 2+2+5);
+}
+void
+TrampolineManagerImpl::SetupStage1 (unsigned long from, unsigned long to)
+{
+  AddPatch (from, 14);
+  unsigned char buffer[14];
+  // mov to,%rax
+  buffer[0] = 0x48;
+  buffer[1] = 0xa1;
+  buffer[2] = (to >> 0) & 0xff;
+  buffer[3] = (to >> 8) & 0xff;
+  buffer[4] = (to >> 16) & 0xff;
+  buffer[5] = (to >> 24) & 0xff;
+  buffer[6] = (to >> 32) & 0xff;
+  buffer[7] = (to >> 40) & 0xff;
+  buffer[8] = (to >> 48) & 0xff;
+  buffer[9] = (to >> 54) & 0xff;
+  //jmpq *(%rax,%r11,8)
+  buffer[10] = 0x42;
+  buffer[11] = 0xff;
+  buffer[12] = 0x24;
+  buffer[13] = 0xd8;
+  Copy (from, buffer, 10+4);
+}
+int
+TrampolineManagerImpl::IteratePhdr (struct dl_phdr_info *info,
+				    size_t size, void *data)
+{
+  struct TrampolineData *trampoline = (struct TrampolineData *) data;
+  unsigned long load_base = info->dlpi_addr;
+  const ElfW(Phdr) *phdr, *loadro = 0, *loadrw = 0;
+  for (int i = 0; i < info->dlpi_phnum; i++)
+    {
+      phdr = &info->dlpi_phdr[i];
+      if (phdr->p_type == PT_LOAD)
+	{
+	  if (phdr->p_flags & PF_W)
+	    {
+	      loadrw = phdr;
+	    }
+	  else
+	    {
+	      loadro = phdr;
+	    }
+	}
+    }
+  NS_ASSERT (loadro != 0 && loadrw != 0);
+  unsigned long start, end;
+  start = loadro->p_vaddr + load_base;
+  end = loadro->p_vaddr + loadro->p_memsz + load_base;
+  if (trampoline->from < start || trampoline->from >= end)
+    {
+      // not this library
+      return 0;
+    }
+  end = RoundUp (end, 16);
+  NS_ASSERT (RoundUp (end, loadro->p_align) - end > 8);
+  trampoline->temporary = end;
+  return 1;
+}
+bool 
+TrampolineManagerImpl::Insert (unsigned long from, unsigned long to)
+{
+  struct TrampolineData data;
+  data.from = from;
+  data.to = to;
+  int status = dl_iterate_phdr (&TrampolineManagerImpl::IteratePhdr, &data);
+  if (status == 0)
+    {
+      return false;
+    }
+  SetupStage0 (from, data.temporary);
+  SetupStage1 (data.temporary, (unsigned long)&m_to);
+
+  unsigned long *pto = new unsigned long [m_nTrampolines+1] ();
+  memcpy (pto, m_to, sizeof(struct Trampoline*)*m_nTrampolines);
+  pto[m_nTrampolines] = to;
+  delete [] m_to;
+  m_to = pto;
+
+  unsigned long *pfrom = new unsigned long [m_nTrampolines+1] ();
+  memcpy (pfrom, m_from, sizeof(struct Trampoline*)*m_nTrampolines);
+  pfrom[m_nTrampolines] = from;
+  delete [] m_from;
+  m_from = pfrom;
+
+  NS_ASSERT (m_nTrampolines <= 0x7f);
+  m_nTrampolines++;
+  return true;
+}
+
+} // namespace ns3
+
+#else
+#error "Will not work on this architecture: need an implementation of class TrampolineManagerImpl."
+#endif
+
+namespace ns3 {
+
+TrampolineManager *
+TrampolineManager::Instance (void)
+{
+  static TrampolineManager instance (new TrampolineManagerImpl ());
+  return &instance;
+}
+
+TrampolineManager::TrampolineManager (TrampolineManagerImpl *impl)
+  : m_impl (impl)
+{}
+
+TrampolineManager::~TrampolineManager ()
+{
+  delete m_impl;
+}
+
+bool 
+TrampolineManager::Insert (unsigned long from, unsigned long to)
+{
+  return m_impl->Insert (from, to);
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/trampoline-manager.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,21 @@
+#ifndef TRAMPOLINE_MANAGER_H
+#define TRAMPOLINE_MANAGER_H
+
+namespace ns3 {
+
+class TrampolineManagerImpl;
+
+class TrampolineManager
+{
+ public:
+  static TrampolineManager *Instance (void);
+  bool Insert (unsigned long from, unsigned long to);
+ private:
+  TrampolineManager (TrampolineManagerImpl *impl);
+  ~TrampolineManager ();
+  TrampolineManagerImpl *m_impl;
+};
+
+} // namespace ns3
+
+#endif /* TRAMPOLINE_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/ucontext-fiber-manager.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,284 @@
+#define _GNU_SOURCE 1
+#include "ucontext-fiber-manager.h"
+#include "ns3/fatal-error.h"
+#include "ns3/assert.h"
+#include <ucontext.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <sys/mman.h>
+#include <link.h>
+
+#ifdef HAVE_VALGRIND_H
+# include "valgrind/valgrind.h"
+#else
+# define VALGRIND_STACK_REGISTER(start,end) (0)
+# define VALGRIND_STACK_DEREGISTER(id)
+#endif
+
+
+namespace ns3 {
+
+void *UcontextFiberManager::g_alternateSignalStack = 0;
+std::list<unsigned long> UcontextFiberManager::g_guardPages;
+
+struct UcontextFiber : public Fiber
+{
+  uint8_t *stack;
+  uint32_t stackSize;
+  ucontext_t context;
+  unsigned int vgId;
+};
+void 
+UcontextFiberManager::SegfaultHandler(int sig, siginfo_t *si, void *unused)
+{
+  int pagesize = sysconf(_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    {
+      NS_FATAL_ERROR ("Unable to query page size");
+    }
+  unsigned long page = (unsigned long) si->si_addr;
+  page = page - (page % pagesize);
+  for (std::list<unsigned long>::iterator i = g_guardPages.begin ();
+       i != g_guardPages.end (); ++i)
+    {
+      if (*i == page)
+	{
+	  // This is a stack overflow: all we can do is print some error message
+	  {
+	    char message[] = "Stack overflow !";
+	    write (2, message, strlen (message));
+	  }
+	  break;
+	}
+    }
+}
+
+void 
+UcontextFiberManager::FreeAlternateSignalStack (void)
+{
+  free (g_alternateSignalStack);
+}
+
+void 
+UcontextFiberManager::SetupSignalHandler (void)
+{
+  static bool alreadySetup = false;
+  if (alreadySetup)
+    {
+      return;
+    }
+  alreadySetup = true;
+
+  stack_t ss;
+
+  /**
+   * We _need_ to setup an alternate signal stack because the kernel will
+   * refuse to deliver a SIGSEGV signal to our process while it is on
+   * the stack which triggered this same error. This kind of makes sense
+   * so, we cannot blame the kernel for this.
+   */
+  ss.ss_sp = malloc(SIGSTKSZ);
+  ss.ss_size = SIGSTKSZ;
+  ss.ss_flags = 0;
+  int status = sigaltstack (&ss, NULL);
+  if (status == -1)
+    {
+      NS_FATAL_ERROR ("Unable to setup an alternate signal stack handler, errno="
+		      << strerror (errno));
+    }
+  g_alternateSignalStack = ss.ss_sp;
+
+  atexit (&FreeAlternateSignalStack);
+
+  struct sigaction sa;
+  sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESETHAND;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_sigaction = &UcontextFiberManager::SegfaultHandler;
+  status = sigaction(SIGSEGV, &sa, NULL);
+  if (status == -1)
+    {
+      NS_FATAL_ERROR ("Unable to setup page fault handler, errno="
+		      << strerror (errno));
+    }
+}
+
+uint32_t 
+UcontextFiberManager::CalcStackSize (uint32_t size)
+{
+  int pagesize = sysconf(_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    {
+      NS_FATAL_ERROR ("Unable to query page size");
+    }
+
+  if ((size % pagesize) == 0)
+    {
+      return size + 2*pagesize;
+    }
+  else
+    {
+      return size + (pagesize - (size % pagesize)) + 2*pagesize;
+    }
+}
+
+uint8_t *
+UcontextFiberManager::AllocateStack (uint32_t size)
+{
+  int pagesize = sysconf(_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    {
+      NS_FATAL_ERROR ("Unable to query page size");
+    }
+
+  SetupSignalHandler ();
+
+  uint32_t realSize = CalcStackSize (size);
+  void *map = mmap (0, realSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (map == MAP_FAILED)
+    {
+      NS_FATAL_ERROR ("Unable to allocate stack pages: size=" << size <<
+		      ", alloced=" << realSize <<
+		      ", errno=" << strerror (errno));
+    }
+  uint8_t *stack = (uint8_t *)map;
+  int status = mprotect (stack+pagesize, realSize-2*pagesize, PROT_READ | PROT_WRITE);
+  if (status == -1)
+    {
+      NS_FATAL_ERROR ("Unable to protect bottom of stack space, errno=" << strerror (errno));
+    }
+  g_guardPages.push_back ((unsigned long)stack);
+  return stack+pagesize;
+}
+void 
+UcontextFiberManager::DeallocateStack (uint8_t *buffer, 
+				       uint32_t stackSize)
+{
+  int pagesize = sysconf(_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    {
+      NS_FATAL_ERROR ("Unable to query page size, errno=" << strerror (errno));
+    }
+  uint32_t realSize = CalcStackSize (stackSize);
+  int status = munmap (buffer-pagesize, realSize);
+  if (status == -1)
+    {
+      NS_FATAL_ERROR ("Unable to unmap stack, errno=" << strerror (errno));
+    }
+  unsigned long guard = (unsigned long)(buffer-pagesize);
+  g_guardPages.remove (guard);
+}
+
+UcontextFiberManager::UcontextFiberManager ()
+  : m_notifySwitch (0)
+{}
+UcontextFiberManager::~UcontextFiberManager ()
+{}
+
+void 
+UcontextFiberManager::Trampoline (int a0, int a1, int a2, int a3)
+{
+  NS_ASSERT (sizeof(int) >= 4);
+  uint64_t fn = 0;
+  fn |= (uint32_t)a0;
+  fn <<= 32;
+  fn |= (uint32_t)a1;
+  uint64_t ctx = 0;
+  ctx |= (uint32_t)a2;
+  ctx <<= 32;
+  ctx |= (uint32_t)a3;
+
+  void (*cb) (void *) = (void (*)(void*)) fn;
+  cb ((void*)ctx);
+}
+
+struct Fiber *
+UcontextFiberManager::Create (void (*callback) (void *),
+			      void *context,
+			      uint32_t stackSize)
+{
+  struct UcontextFiber *fiber = new struct UcontextFiber ();
+  uint8_t *stack;
+  int retval;
+
+  stack = AllocateStack (stackSize);
+  fiber->vgId = VALGRIND_STACK_REGISTER(stack,stack+stackSize);
+  fiber->stack = stack;
+  fiber->stackSize = stackSize;
+
+  retval = getcontext (&fiber->context);
+  NS_ASSERT (retval != -1);
+  fiber->context.uc_stack.ss_sp = stack;
+  fiber->context.uc_stack.ss_size = stackSize;
+  // make sure the thread exits when it completes.
+  fiber->context.uc_link = NULL;
+
+  uint64_t cb = (uint64_t)callback;
+  uint64_t ctx = (uint64_t)context;
+  uint32_t a0 = cb >> 32;
+  uint32_t a1 = cb & 0xffffffff;
+  uint32_t a2 = ctx >> 32;
+  uint32_t a3 = ctx & 0xffffffff;
+  void (*fn) () = (void (*) ()) &UcontextFiberManager::Trampoline;
+  makecontext (&fiber->context, fn, 4, a0, a1, a2, a3);
+
+  return fiber;
+}
+
+struct Fiber *
+UcontextFiberManager::CreateFromCaller (void)
+{
+  struct UcontextFiber *fiber = new struct UcontextFiber ();
+  fiber->stack = 0;
+  fiber->stackSize = 0;
+  return fiber;
+}
+
+void 
+UcontextFiberManager::Delete (struct Fiber *fib)
+{
+  struct UcontextFiber *fiber = (struct UcontextFiber *)fib;
+  VALGRIND_STACK_DEREGISTER(fiber->vgId);
+  if (fiber->stack != 0)
+    {
+      DeallocateStack (fiber->stack, fiber->stackSize);
+    }
+  fiber->stack = 0;
+  fiber->stackSize = 0xdeadbeaf;
+  delete fiber;
+}
+
+void 
+UcontextFiberManager::SwitchTo (struct Fiber *fromFiber, 
+				const struct Fiber *toFiber)
+{
+  struct UcontextFiber *from = (struct UcontextFiber *)fromFiber;
+  struct UcontextFiber *to = (struct UcontextFiber *)toFiber;
+  swapcontext (&from->context, &to->context);
+  if (m_notifySwitch != 0)
+    {
+      m_notifySwitch ();
+    }
+}
+
+uint32_t 
+UcontextFiberManager::GetStackSize (struct Fiber *fib) const
+{
+  struct UcontextFiber *fiber = (struct UcontextFiber *)fib;
+  return fiber->stackSize;
+}
+
+void 
+UcontextFiberManager::SetSwitchNotification (void (*fn) (void))
+{
+  m_notifySwitch = fn;
+}
+
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/ucontext-fiber-manager.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,44 @@
+#ifndef UCONTEXT_FIBER_MANAGER_H
+#define UCONTEXT_FIBER_MANAGER_H
+
+#include "fiber-manager.h"
+#include <signal.h>
+#include <list>
+
+namespace ns3 {
+
+class UcontextFiberManager : public FiberManager
+{
+public:
+  UcontextFiberManager ();
+  virtual ~UcontextFiberManager ();
+
+  virtual struct Fiber *Create (void (*callback) (void *),
+				void *context,
+				uint32_t stackSize);
+  virtual struct Fiber *CreateFromCaller (void);
+  virtual void Delete (struct Fiber *fiber);
+  virtual void SwitchTo (struct Fiber *from, 
+			 const struct Fiber *to);
+  virtual uint32_t GetStackSize (struct Fiber *fiber) const;
+  virtual void SetSwitchNotification (void (*fn) (void));
+private:
+  static void SegfaultHandler(int sig, siginfo_t *si, void *unused);
+  // invoked as atexit handler
+  static void FreeAlternateSignalStack (void);
+
+  void SetupSignalHandler (void);
+  uint32_t CalcStackSize (uint32_t size);
+  uint8_t *AllocateStack (uint32_t stackSize);
+  void DeallocateStack (uint8_t *buffer, uint32_t stackSize);
+  static void Trampoline (int a0, int a1, int a2, int a3);
+  
+
+  void (*m_notifySwitch) (void);
+  static void *g_alternateSignalStack;
+  static std::list<unsigned long> g_guardPages;
+};
+
+} // namespace ns3
+
+#endif /* UCONTEXT_FIBER_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-datagram-socket-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,225 @@
+#include "process.h"
+#include "dce-manager.h"
+#include "utils.h"
+#include "unix-datagram-socket-fd.h"
+#include "ns3/log.h"
+#include "ns3/socket.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/inet-socket-address.h"
+#include "cmsg.h"
+#include <errno.h>
+#include <netinet/in.h>
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <arpa/inet.h>
+
+NS_LOG_COMPONENT_DEFINE ("UnixDatagramSocketFd");
+
+namespace ns3 {
+
+UnixDatagramSocketFd::UnixDatagramSocketFd (Ptr<Socket> sock)
+  : UnixSocketFd (sock)
+{
+  // XXX: should I really do this here ?
+  m_socket->SetAttributeFailSafe ("IcmpCallback", CallbackValue (MakeCallback (&UnixDatagramSocketFd::IcmpCallback, this)));
+}
+
+bool 
+UnixDatagramSocketFd::CanRecv (void) const
+{
+  return m_socket != 0 && m_socket->GetRxAvailable () != 0;
+}
+bool 
+UnixDatagramSocketFd::CanSend (void) const
+{
+  return m_socket != 0 && m_socket->GetTxAvailable () != 0;
+}
+
+void 
+UnixDatagramSocketFd::QueueErr (sock_extended_err ee, struct sockaddr_in offender, uint8_t ttl)
+{
+  NS_LOG_FUNCTION (this);
+  if (!IsRecvErr ())
+    {
+      return;
+    }
+  struct Error e;
+  e.ee = ee;
+  e.offender = offender;
+  e.ttl = ttl;
+  m_errQueue.push_back (e);
+}
+
+void
+UnixDatagramSocketFd::IcmpCallback (Ipv4Address icmpSource, uint8_t icmpTtl, 
+				    uint8_t icmpType, uint8_t icmpCode,
+				    uint32_t icmpInfo)
+{
+  NS_LOG_FUNCTION (this << icmpSource << (uint32_t)icmpTtl << (uint32_t)icmpType <<
+                   (uint32_t)icmpCode << icmpInfo);
+  // received icmp errors never interrupt a blocked recv and
+  // never notify a blocked select/poll.
+
+  sock_extended_err ee;
+  struct sockaddr_in offender;
+
+  if (icmpType == Icmpv4Header::DEST_UNREACH &&
+      icmpCode == Icmpv4DestinationUnreachable::FRAG_NEEDED)
+    {
+      
+      ee.ee_errno = EMSGSIZE;
+    }
+  else if (icmpType == Icmpv4Header::DEST_UNREACH &&
+	   icmpCode == Icmpv4DestinationUnreachable::PORT_UNREACHABLE)
+    {
+      
+      ee.ee_errno = EHOSTUNREACH;
+    }
+  else if (icmpType == Icmpv4Header::TIME_EXCEEDED &&
+	   icmpCode == Icmpv4TimeExceeded::TIME_TO_LIVE)
+    {
+      ee.ee_errno = EHOSTUNREACH;
+    }
+  else
+    {
+      NS_ASSERT (false);
+      ee.ee_errno = 0;
+    }
+  ee.ee_origin = SO_EE_ORIGIN_ICMP;
+  ee.ee_type = icmpType;
+  ee.ee_code = icmpCode;
+  ee.ee_pad = 0;
+  ee.ee_info = icmpInfo;
+  ee.ee_data = 0;
+  offender.sin_family = AF_INET;
+  offender.sin_addr.s_addr = htonl (icmpSource.Get ());
+  offender.sin_port = 0;
+  memset (offender.sin_zero, 0, sizeof (offender.sin_zero));
+  QueueErr (ee, offender, icmpTtl);
+}
+
+ssize_t 
+UnixDatagramSocketFd::DoRecvmsg (struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+
+  if (flags & MSG_ERRQUEUE)
+    {
+      // MSG_ERRQUEUE is valid only for DGRAM sockets.
+      if (m_errQueue.empty ())
+	{
+	  current->err = EAGAIN;
+	  return -1;
+	}
+      
+      Cmsg cmsg = Cmsg (msg);
+      if (IsRecvErr ())
+	{
+	  cmsg.Add (SOL_IP, IP_RECVERR, sizeof (struct Error), (const uint8_t*)&m_errQueue.front ());
+	}
+      if (IsRecvTtl ())
+	{
+	  int tmp = m_errQueue.front ().ttl;
+	  cmsg.Add (SOL_IP, IP_TTL, sizeof (int), (const uint8_t*)&tmp);
+	}
+      cmsg.Finish ();
+      m_errQueue.pop_front ();
+      return 0;
+    }
+  else
+    {
+      msg->msg_controllen = 0;
+    }
+
+  if (!WaitRecvDoSignal (flags & MSG_DONTWAIT))
+    {
+      // current->err set by call above.
+      return -1;
+    }
+
+  uint32_t count = msg->msg_iov[0].iov_len;
+  uint8_t *buf = (uint8_t *)msg->msg_iov[0].iov_base;
+  // we ignore the secondary items of the iovec buffers.
+  // because we implement a datagram-only socket for now.
+  Address from;
+  Ptr<Packet> packet = m_socket->RecvFrom (count, flags, from);
+  if (packet == 0)
+    {
+      current->err = ErrnoToSimuErrno ();
+      return -1;
+    }
+  Ns3AddressToPosixAddress (from, (struct sockaddr*)msg->msg_name, &msg->msg_namelen);
+  // XXX: we ignore MSG_TRUNC for the return value.
+  NS_ASSERT (packet->GetSize () <= count);
+  memcpy (buf, packet->PeekData (), packet->GetSize ());
+  return packet->GetSize ();
+}
+ssize_t 
+UnixDatagramSocketFd::DoSendmsg(const struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+
+
+  ssize_t retval = 0;
+  for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
+    {
+      uint8_t *buf = (uint8_t *)msg->msg_iov[i].iov_base;
+      uint32_t len = msg->msg_iov[i].iov_len;
+      Ptr<Packet> packet = Create<Packet> (buf, len);
+      int result;
+      if (msg->msg_name != 0 && msg->msg_namelen != 0)
+	{
+	  Address ad = PosixAddressToNs3Address ((const struct sockaddr *)msg->msg_name, 
+						 (socklen_t)msg->msg_namelen);
+	  result = m_socket->SendTo (packet, flags, ad);
+	}
+      else
+	{
+	  result = m_socket->Send (packet);
+	}
+      if (result == -1)
+	{
+	  current->err = ErrnoToSimuErrno ();
+	  return -1;
+	}
+      retval += result;
+    }
+  return retval;
+}
+int 
+UnixDatagramSocketFd::Listen (int backlog)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = EOPNOTSUPP;
+  return -1;
+}
+int 
+UnixDatagramSocketFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << my_addr << addrlen);
+  NS_ASSERT (current != 0);
+  current->err = EOPNOTSUPP;
+  return -1;
+}
+int 
+UnixDatagramSocketFd::Shutdown (int how)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << how);
+  NS_ASSERT (current != 0);
+  // XXX: linux does not generate EOPNOTSUPP for this. I _think_ it 
+  // generates ENOTCONN which, honestly, makes _zero_ sense.
+  current->err = EOPNOTSUPP;
+  return -1;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-datagram-socket-fd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,39 @@
+#ifndef UNIX_DATAGRAM_SOCKET_FD_H
+#define UNIX_DATAGRAM_SOCKET_FD_H
+
+#include "unix-socket-fd.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/icmpv4.h"
+#include <netinet/in.h>
+
+namespace ns3 {
+
+class UnixDatagramSocketFd : public UnixSocketFd
+{
+public:
+  UnixDatagramSocketFd (Ptr<Socket> sock);
+  
+private:
+  virtual ssize_t DoRecvmsg(struct msghdr *msg, int flags);
+  virtual ssize_t DoSendmsg(const struct msghdr *msg, int flags);
+  virtual int Listen (int backlog);
+  virtual int Accept (struct sockaddr *my_addr, socklen_t *addrlen);
+  virtual int Shutdown(int how);
+  virtual bool CanRecv (void) const;
+  virtual bool CanSend (void) const;
+  void IcmpCallback (Ipv4Address icmpSource, uint8_t icmpTtl, 
+                    uint8_t icmpType, uint8_t icmpCode,
+                    uint32_t icmpInfo);
+  void QueueErr (sock_extended_err ee, struct sockaddr_in offender, uint8_t ttl);
+
+  struct Error {
+    sock_extended_err ee;
+    struct sockaddr_in offender;
+    uint8_t ttl;
+  };
+  std::list<struct Error> m_errQueue;
+};
+
+} // namespace ns3
+
+#endif /* UNIX_DATAGRAM_SOCKET_FD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,39 @@
+#include "unix-fd.h"
+#include "waiter.h"
+
+namespace ns3 {
+
+UnixFd::UnixFd ()
+  : m_recvWaiter (0),
+    m_sendWaiter (0)
+{}
+
+void 
+UnixFd::SetRecvWaiter (Waiter *waiter)
+{
+  m_recvWaiter = waiter;
+}
+void 
+UnixFd::SetSendWaiter (Waiter *waiter)
+{
+  m_sendWaiter = waiter;
+}
+
+void 
+UnixFd::WakeupSend (void)
+{
+  if (m_sendWaiter != 0)
+    {
+      m_sendWaiter->Wakeup ();
+    }
+}
+void 
+UnixFd::WakeupRecv (void)
+{
+  if (m_recvWaiter != 0)
+    {
+      m_recvWaiter->Wakeup ();
+    }
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-fd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,60 @@
+#ifndef UNIX_FD_H
+#define UNIX_FD_H
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <time.h>
+#include "ns3/ref-count-base.h"
+
+namespace ns3 {
+
+class Waiter;
+
+class UnixFd : public RefCountBase
+{
+public:
+  virtual int Close (void) = 0;
+  virtual ssize_t Write (const void *buf, size_t count) = 0;
+  virtual ssize_t Read(void *buf, size_t count) = 0;
+  virtual ssize_t Recvmsg(struct msghdr *msg, int flags) = 0;
+  virtual ssize_t Sendmsg(const struct msghdr *msg, int flags) = 0;
+  virtual bool Isatty (void) const = 0;
+  virtual int Setsockopt (int level, int optname,
+			  const void *optval, socklen_t optlen) = 0;
+  virtual int Getsockopt (int level, int optname,
+			  void *optval, socklen_t *optlen) = 0;
+  virtual int Getsockname(struct sockaddr *name, socklen_t *namelen) = 0;
+  virtual int Getpeername(struct sockaddr *name, socklen_t *namelen) = 0;
+  virtual int Ioctl (int request, char *argp) = 0;
+  virtual int Bind (const struct sockaddr *my_addr, socklen_t addrlen) = 0;
+  virtual int Connect (const struct sockaddr *my_addr, socklen_t addrlen) = 0;
+  virtual int Listen (int backlog) = 0;
+  virtual int Shutdown(int how) = 0;
+  virtual int Accept (struct sockaddr *my_addr, socklen_t *addrlen) = 0;
+  virtual void *Mmap (void *start, size_t length, int prot, int flags, off64_t offset) = 0;
+  virtual off64_t Lseek (off64_t offset, int whence) = 0;
+  virtual int Fxstat (int ver, struct ::stat *buf) = 0;
+  virtual int Fxstat64 (int ver, struct ::stat64 *buf) = 0;
+  virtual int Fcntl (int cmd, unsigned long arg) = 0;
+  virtual int Settime (int flags,
+		       const struct itimerspec *new_value,
+		       struct itimerspec *old_value) = 0;
+  virtual int Gettime (struct itimerspec *cur_value) const = 0;
+
+  void SetRecvWaiter (Waiter *waiter);
+  void SetSendWaiter (Waiter *waiter);
+  virtual bool CanRecv (void) const = 0;
+  virtual bool CanSend (void) const = 0;
+
+protected:
+  UnixFd ();
+  void WakeupSend (void);
+  void WakeupRecv (void);
+private:
+  Waiter *m_recvWaiter;
+  Waiter *m_sendWaiter;
+};
+
+} // namespace ns3
+
+#endif /* UNIX_FD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-file-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,310 @@
+#include "unix-file-fd.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "utils.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+NS_LOG_COMPONENT_DEFINE ("UnixFileFd");
+
+namespace ns3 {
+
+UnixFileFdBase::UnixFileFdBase (int realFd)
+  : m_realFd (realFd)
+{}
+UnixFileFdBase::~UnixFileFdBase ()
+{
+  NS_LOG_FUNCTION (this << m_realFd);
+  m_realFd = -1;
+}
+int 
+UnixFileFdBase::PeekRealFd (void) const
+{
+  return m_realFd;
+}
+ssize_t 
+UnixFileFdBase::Write (const void *buf, size_t count)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << buf << count);
+  NS_ASSERT (current != 0);
+  ssize_t result = ::write (m_realFd, buf, count);
+  if (result == -1)
+    {
+      current->err = errno;
+    }
+  return result;
+}
+ssize_t 
+UnixFileFdBase::Read (void *buf, size_t count)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << buf << count);
+  NS_ASSERT (current != 0);
+  ssize_t result = ::read (m_realFd, buf, count);
+  if (result == -1)
+    {
+      current->err = errno;
+    }
+  return result;
+}
+
+ssize_t 
+UnixFileFdBase::Recvmsg(struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+ssize_t 
+UnixFileFdBase::Sendmsg(const struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+bool 
+UnixFileFdBase::Isatty (void) const
+{
+  return ::isatty (m_realFd);
+}
+int 
+UnixFileFdBase::Setsockopt (int level, int optname,
+			const void *optval, socklen_t optlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixFileFdBase::Getsockopt (int level, int optname,
+			void *optval, socklen_t *optlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixFileFdBase::Getsockname(struct sockaddr *name, socklen_t *namelen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << name << *namelen);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;  
+}
+int 
+UnixFileFdBase::Getpeername(struct sockaddr *name, socklen_t *namelen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << name << *namelen);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+
+int 
+UnixFileFdBase::Ioctl (int request, char *argp)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = EINVAL;  
+  return -1;
+}
+int 
+UnixFileFdBase::Bind (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixFileFdBase::Connect (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;  
+}
+int 
+UnixFileFdBase::Listen (int backlog)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixFileFdBase::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << my_addr << addrlen);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixFileFdBase::Shutdown(int how)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << how);
+  NS_ASSERT (current != 0);
+  current->err = ENOTSOCK;
+  return -1;
+}
+void *
+UnixFileFdBase::Mmap (void *start, size_t length, int prot, int flags,
+		  off64_t offset)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  
+  void *retval = ::mmap (start, length, prot, flags, m_realFd, offset);
+  if (retval == 0)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+off64_t 
+UnixFileFdBase::Lseek (off64_t offset, int whence)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << offset << whence);
+  NS_ASSERT (current != 0);
+  off64_t retval = ::lseek64 (m_realFd, offset, whence);
+  if (retval == -1)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+int 
+UnixFileFdBase::Fxstat (int ver, struct ::stat *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << buf);
+  NS_ASSERT (current != 0);
+  int retval = ::__fxstat (ver, m_realFd, buf);
+  if (retval == -1)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+int 
+UnixFileFdBase::Fxstat64 (int ver, struct ::stat64 *buf)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << buf);
+  NS_ASSERT (current != 0);
+  int retval = ::__fxstat64 (ver, m_realFd, buf);
+  if (retval == -1)
+    {
+      current->err = errno;
+    }
+  return retval;
+}
+int 
+UnixFileFdBase::Fcntl (int cmd, unsigned long arg)
+{
+  NS_LOG_FUNCTION (this << Current () << cmd << arg);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  int retval = ::fcntl (m_realFd, cmd, arg);
+  if (retval == -1)
+    {
+      current->err = errno;
+    }
+  return retval;  
+}
+int 
+UnixFileFdBase::Settime (int flags,
+			 const struct itimerspec *new_value,
+			 struct itimerspec *old_value)
+{
+  NS_LOG_FUNCTION (this << Current () << flags << new_value << old_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return -1;
+}
+int 
+UnixFileFdBase::Gettime (struct itimerspec *cur_value) const
+{
+  NS_LOG_FUNCTION (this << Current () << cur_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return -1;
+}
+
+
+bool 
+UnixFileFdBase::CanRecv (void) const
+{
+  return true;
+}
+bool 
+UnixFileFdBase::CanSend (void) const
+{
+  return true;
+}
+
+UnixFileFd::UnixFileFd (int realFd)
+  : UnixFileFdBase (realFd)
+{}
+UnixFileFd::~UnixFileFd ()
+{
+  if (PeekRealFd () != -1)
+    {
+      ::close (PeekRealFd ());
+    }
+}
+int 
+UnixFileFd::Close (void)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  int result = ::close (PeekRealFd ());
+  if (result == -1)
+    {
+      current->err = errno;
+    }
+  // caller is responsible for removing this fd from process
+  // list of fds and deleting this class instance.
+  return result;
+}
+
+TermUnixFileFd::TermUnixFileFd (int realFd)
+  : UnixFileFdBase (realFd)
+{}
+TermUnixFileFd::~TermUnixFileFd ()
+{}
+int 
+TermUnixFileFd::Close (void)
+{
+  return 0;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-file-fd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,68 @@
+#ifndef UNIX_FILE_FD_H
+#define UNIX_FILE_FD_H
+
+#include "unix-fd.h"
+
+namespace ns3 {
+
+class UnixFileFdBase : public UnixFd
+{
+public:
+  UnixFileFdBase (int realFd);
+  virtual ~UnixFileFdBase ();
+  virtual ssize_t Write (const void *buf, size_t count);
+  virtual ssize_t Read (void *buf, size_t count);
+  virtual ssize_t Recvmsg(struct msghdr *msg, int flags);
+  virtual ssize_t Sendmsg(const struct msghdr *msg, int flags);
+  virtual bool Isatty (void) const;
+  virtual int Setsockopt (int level, int optname,
+			  const void *optval, socklen_t optlen);
+  virtual int Getsockopt (int level, int optname,
+			  void *optval, socklen_t *optlen);
+  virtual int Getsockname(struct sockaddr *name, socklen_t *namelen);
+  virtual int Getpeername(struct sockaddr *name, socklen_t *namelen);
+  virtual int Ioctl (int request, char *argp);
+  virtual int Bind (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual int Connect (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual int Listen (int backlog);
+  virtual int Accept (struct sockaddr *my_addr, socklen_t *addrlen);
+  virtual int Shutdown(int how);
+  virtual void *Mmap (void *start, size_t length, int prot, int flags,
+		      off64_t offset);
+  virtual off64_t Lseek (off64_t offset, int whence);
+  virtual int Fxstat (int ver, struct ::stat *buf);
+  virtual int Fxstat64 (int ver, struct ::stat64 *buf);
+  virtual int Fcntl (int cmd, unsigned long arg);
+  virtual int Settime (int flags,
+		       const struct itimerspec *new_value,
+		       struct itimerspec *old_value);
+  virtual int Gettime (struct itimerspec *cur_value) const;
+
+  virtual bool CanRecv (void) const;
+  virtual bool CanSend (void) const;
+protected:
+  int PeekRealFd (void) const;
+private:
+  int m_realFd;
+};
+
+class UnixFileFd : public UnixFileFdBase
+{
+public:
+  UnixFileFd (int realFd);
+  virtual ~UnixFileFd ();
+  virtual int Close (void);
+};
+
+class TermUnixFileFd : public UnixFileFdBase
+{
+public:
+  TermUnixFileFd (int realFd);
+  virtual ~TermUnixFileFd ();
+  virtual int Close (void);
+};
+
+} // namespace ns3
+
+#endif /* UNIX_FILE_FD_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-socket-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,610 @@
+#include "unix-socket-fd.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "utils.h"
+#include "waiter.h"
+#include "cmsg.h"
+#include "sys/simu-socket.h"
+#include "ns3/log.h"
+#include "ns3/socket.h"
+#include "ns3/packet.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/uinteger.h"
+#include "ns3/boolean.h"
+#include "ns3/simulator.h"
+#include <fcntl.h>
+#include <errno.h>
+#include <linux/icmp.h> // need ICMP_FILTER
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+
+NS_LOG_COMPONENT_DEFINE ("UnixSocketFd");
+
+namespace ns3 {
+
+UnixSocketFd::UnixSocketFd (Ptr<Socket> socket)
+  : m_socket (socket),
+    m_sendTimeout (Seconds (0.0)),
+    m_recvTimeout (Seconds (0.0)),
+    m_statusFlags (0)
+{
+  m_socket->SetAttributeFailSafe ("SndBufSize", UintegerValue (4096));
+  m_socket->SetAttributeFailSafe ("RcvBufSize", UintegerValue (4096));
+  m_socket->SetRecvCallback (MakeCallback (&UnixSocketFd::RecvSocketData, this));
+  m_socket->SetSendCallback (MakeCallback (&UnixSocketFd::SendSocketData, this));
+}
+UnixSocketFd::~UnixSocketFd ()
+{
+  NS_LOG_FUNCTION (this);
+  if (m_socket != 0)
+    {
+      m_socket->SetRecvCallback (MakeNullCallback<void,Ptr<Socket> > ());
+      m_socket = 0;
+    }
+}
+void *
+UnixSocketFd::Mmap (void *start, size_t length, int prot, int flags, off64_t offset)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << start << length << prot << flags << offset);
+  NS_ASSERT (current != 0);
+  current->err = ENODEV;
+  return MAP_FAILED;
+}
+int 
+UnixSocketFd::Fxstat (int ver, struct stat *buf)
+{
+  NS_LOG_FUNCTION (this << Current () << buf);
+  NS_ASSERT (Current ()!= 0);
+  buf->st_mode = S_IFSOCK;
+  buf->st_dev = -1;
+  buf->st_blksize = 0;
+  return 0;
+}
+int 
+UnixSocketFd::Fxstat64 (int ver, struct stat64 *buf)
+{
+  NS_LOG_FUNCTION (this << Current () << buf);
+  NS_ASSERT (Current () != 0);
+  buf->st_mode = S_IFSOCK;
+  buf->st_dev = -1;
+  buf->st_blksize = 0;
+  return 0;
+}
+int 
+UnixSocketFd::Fcntl (int cmd, unsigned long arg)
+{
+  switch (cmd) 
+    {
+    case F_GETFL: //XXX this command should also consider the flags O_APPEND and O_ASYNC
+      return m_statusFlags;
+      break;
+    case F_SETFL:
+      m_statusFlags = arg;
+      return 0;
+      break;
+    default:
+      //XXX commands missing
+      NS_FATAL_ERROR ("fcntl not implemented on socket");
+      return -1;
+    }
+}
+int 
+UnixSocketFd::ErrnoToSimuErrno (void) const
+{
+  switch (m_socket->GetErrno ()) {
+  case Socket::ERROR_ISCONN:
+    return EISCONN;
+  case Socket::ERROR_NOTCONN:
+    return ENOTCONN;
+  case Socket::ERROR_MSGSIZE:
+    return EMSGSIZE;
+  case Socket::ERROR_AGAIN:
+    return EAGAIN;
+  case Socket::ERROR_SHUTDOWN:
+    return ESHUTDOWN;
+  case Socket::ERROR_OPNOTSUPP:
+    return EOPNOTSUPP;
+  case Socket::ERROR_AFNOSUPPORT:
+    return EAFNOSUPPORT;
+  case Socket::ERROR_INVAL:
+    return EINVAL;
+  case Socket::ERROR_BADF:
+    return EBADF;
+  case Socket::ERROR_NOROUTETOHOST:
+    return EHOSTUNREACH;
+  case Socket::SOCKET_ERRNO_LAST:
+  case Socket::ERROR_NOTERROR:
+  default:
+    NS_ASSERT (false);
+    return 0; // quiet compiler
+    break;
+  }
+}
+void 
+UnixSocketFd::RecvSocketData (Ptr<Socket> socket)
+{
+  NS_LOG_FUNCTION (this << m_socket << socket);
+  WakeupRecv ();
+}
+void 
+UnixSocketFd::SendSocketData (Ptr<Socket> socket, uint32_t available)
+{
+  NS_LOG_FUNCTION (this << m_socket << socket);
+  WakeupSend ();  
+}
+
+int 
+UnixSocketFd::Close (void)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  int result = m_socket->Close ();
+  if (result == -1)
+    {
+      current->err = ErrnoToSimuErrno ();
+    }
+  m_socket->SetRecvCallback (MakeNullCallback<void,Ptr<Socket> > ());
+  m_socket->SetSendCallback (MakeNullCallback<void,Ptr<Socket>,uint32_t > ());
+  m_socket = 0;
+  /**
+   * Closing a socket while another thread is doing blocking IO
+   * on it at the same time is valid behavior according to POSIX.
+   * The traditional UNIX semantics are to not wakeup the blocked
+   * IO if it was a read but to wakeup blocked IO if it was a write.
+   * So, m_readWaiter might well be != 0 here but we don't care.
+   * Instead, we check wakeup writers
+   */
+  WakeupSend ();
+  return result;
+}
+ssize_t 
+UnixSocketFd::Write (const void *buf, size_t count)
+{
+  NS_LOG_FUNCTION (this << buf << count);
+  struct msghdr msg;
+  struct iovec iov;
+  msg.msg_control = 0;
+  msg.msg_controllen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iov;
+  iov.iov_len = count;
+  iov.iov_base = (void*)buf;
+  msg.msg_name = 0;
+  msg.msg_namelen = 0;
+  ssize_t retval = Sendmsg (&msg, 0);
+  return retval;
+}
+ssize_t 
+UnixSocketFd::Read (void *buf, size_t count)
+{
+  NS_LOG_FUNCTION (this << buf << count);
+  struct msghdr msg;
+  struct iovec iov;
+  msg.msg_control = 0;
+  msg.msg_controllen = 0;
+  msg.msg_iovlen = 1;
+  msg.msg_iov = &iov;
+  iov.iov_len = count;
+  iov.iov_base = buf;
+  msg.msg_name = 0;
+  msg.msg_namelen = 0;
+  ssize_t retval = Recvmsg (&msg, 0);
+  return retval;
+}
+ssize_t 
+UnixSocketFd::Recvmsg(struct msghdr *msg, int flags)
+{
+  bool nonBlocking = (m_statusFlags & O_NONBLOCK) == O_NONBLOCK;
+  flags |= nonBlocking?MSG_DONTWAIT:0;
+  return DoRecvmsg (msg, flags);
+}
+ssize_t
+UnixSocketFd::Sendmsg(const struct msghdr *msg, int flags)
+{
+  bool nonBlocking = (m_statusFlags & O_NONBLOCK) == O_NONBLOCK;
+  flags |= nonBlocking?MSG_DONTWAIT:0;
+  return DoSendmsg (msg, flags);
+}
+
+bool 
+UnixSocketFd::Isatty (void) const
+{
+  return false;
+}
+
+int 
+UnixSocketFd::Setsockopt (int level, int optname,
+			  const void *optval, socklen_t optlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << level << optname << optval << optlen);
+  NS_ASSERT (current != 0);
+
+  switch (level) {
+  case SOL_RAW:
+    switch (optname) {
+    case ICMP_FILTER: {
+      if (optlen != 4)
+        {
+          current->err = EINVAL;
+          return -1;
+        }
+      uint32_t *data = (uint32_t *)optval;
+      if (!m_socket->SetAttributeFailSafe ("IcmpFilter", UintegerValue (*data)))
+        {
+          current->err = ENOPROTOOPT;
+          return -1;
+        }
+    } break;
+    }
+    break;
+  case SOL_SOCKET:
+    switch (optname) {
+    case SO_RCVTIMEO: {
+      if (optlen != sizeof (struct timeval))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      struct timeval *tv = (struct timeval *)optval;
+      m_recvTimeout = UtilsTimevalToTime (*tv);
+    } break;
+    case SO_SNDTIMEO: {
+      if (optlen != sizeof (struct timeval))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      struct timeval *tv = (struct timeval *)optval;
+      m_sendTimeout = UtilsTimevalToTime (*tv);
+    } break;
+    case SO_SNDBUF: {
+      if (optlen != sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *val = (int*)optval;
+      if (!m_socket->SetAttributeFailSafe ("SndBufSize", UintegerValue (*val)))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+    } break;
+    }
+    break;
+  case SOL_IP:
+    switch (optname) {
+    case IP_RECVERR: {
+      if (optlen != sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *v = (int*)optval;
+      m_recverr = *v;
+    } break;
+    case IP_RECVTTL: {
+      if (optlen != sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *v = (int*)optval;
+      m_recvttl = *v;
+    } break;
+    case IP_TTL: {
+      if (optlen != sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *v = (int*)optval;
+      if (!m_socket->SetAttributeFailSafe ("IpTtl", UintegerValue (*v)))
+	{
+          current->err = ENOPROTOOPT;
+          return -1;
+	}
+    } break;
+    }
+    break;
+  }
+  return 0;
+}
+int 
+UnixSocketFd::Getsockopt (int level, int optname,
+			  void *optval, socklen_t *optlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << level << optname << optval << optlen);
+  NS_ASSERT (current != 0);
+
+  switch (level) {
+  case SOL_RAW:
+    switch (optname) {
+    case ICMP_FILTER: {
+      if (*optlen < 4)
+        {
+          current->err = EINVAL;
+          return -1;
+        }
+      UintegerValue data;
+      if (!m_socket->GetAttributeFailSafe ("IcmpFilter", data))
+        {
+          current->err = ENOPROTOOPT;
+          return -1;
+        }
+      uint32_t v = data.Get ();
+      memcpy (optval, (void*)&v, 4);
+      *optlen = 4;
+    } break;
+    }
+    break;
+  case SOL_SOCKET:
+    switch (optname) {
+    case SO_RCVTIMEO: {
+      if (*optlen < sizeof (struct timeval))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      struct timeval *tv = (struct timeval *)optval;
+      *tv = UtilsTimeToTimeval (m_recvTimeout);
+      *optlen = sizeof (struct timeval);
+    } break;
+    case SO_SNDTIMEO: {
+      if (*optlen < sizeof (struct timeval))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      struct timeval *tv = (struct timeval *)optval;
+      *tv = UtilsTimeToTimeval (m_sendTimeout);
+      *optlen = sizeof (struct timeval);
+    } break;
+    case SO_SNDBUF: {
+      if (*optlen < sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *val = (int*)optval;
+      UintegerValue attrValue;
+      if (!m_socket->GetAttributeFailSafe ("SndBufSize", attrValue))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      *val = attrValue.Get ();
+      *optlen = sizeof (int);
+    } break;
+    }
+    break;
+  case SOL_IP:
+    switch (optname) {
+    case IP_RECVERR: {
+      if (*optlen < sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *v = (int*)optval;
+      *v = m_recverr;
+      *optlen = sizeof (int);
+    } break;
+    case IP_RECVTTL: {
+      if (*optlen < sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *v = (int*)optval;
+      *v = m_recvttl;
+      *optlen = sizeof (int);
+    } break;
+    case IP_TTL: {
+      if (*optlen < sizeof (int))
+	{
+	  current->err = EINVAL;
+	  return -1;
+	}
+      int *v = (int*)optval;
+      UintegerValue val;
+      if (!m_socket->GetAttributeFailSafe ("IpTtl", val))
+	{
+	  current->err = ENOPROTOOPT;
+	  return -1;
+	}
+      *v = val.Get ();
+      *optlen = sizeof (int);
+    } break;
+    }
+    break;
+  }
+  return 0;
+}
+int 
+UnixSocketFd::Getsockname(struct sockaddr *name, socklen_t *namelen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << name << *namelen);
+  NS_ASSERT (current != 0);  
+  Address ad;
+  int status = m_socket->GetSockName (ad);
+  if (status == -1)
+    {
+      current->err = ErrnoToSimuErrno ();
+      return -1;
+    }
+  if (Ns3AddressToPosixAddress (ad, name, namelen) == -1)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  return 0;
+}
+int 
+UnixSocketFd::Getpeername(struct sockaddr *name, socklen_t *namelen)
+{
+  //XXX
+  return -1;
+}
+int 
+UnixSocketFd::Ioctl (int request, char *argp)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  current->err = EINVAL;  
+  return -1;
+}
+Address
+UnixSocketFd::PosixAddressToNs3Address (const struct sockaddr *my_addr, socklen_t addrlen) const
+{
+  if (my_addr->sa_family == AF_INET)
+    {
+      const struct sockaddr_in *addr = (const struct sockaddr_in *)my_addr;
+      Ipv4Address ipv4;
+      ipv4.Set (ntohl (addr->sin_addr.s_addr));
+      uint16_t port = ntohs (addr->sin_port);
+      InetSocketAddress inet = InetSocketAddress (ipv4, port);
+      return inet;
+    }
+  NS_ASSERT (false);
+  return Address ();
+}
+int
+UnixSocketFd::Ns3AddressToPosixAddress(const Address& nsaddr, 
+				       struct sockaddr *addr, socklen_t *addrlen) const
+{
+  if (addr == 0 || addrlen == 0)
+    {
+      return 0;
+    }
+  if (InetSocketAddress::IsMatchingType(nsaddr))
+    {
+      InetSocketAddress ns_inetaddr = InetSocketAddress::ConvertFrom(nsaddr);
+      if (*addrlen < sizeof (struct sockaddr_in))
+	{
+	  return -1;
+	}
+      struct sockaddr_in *inet_addr = (struct sockaddr_in *)addr;
+      inet_addr->sin_family = AF_INET;
+      inet_addr->sin_port = htons (ns_inetaddr.GetPort ());
+      inet_addr->sin_addr.s_addr = htonl (ns_inetaddr.GetIpv4 ().Get ());
+      *addrlen = sizeof(struct sockaddr_in);
+    }
+  else
+    {
+      NS_ASSERT (false);
+    }
+  return 0;
+}
+int 
+UnixSocketFd::Bind (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+
+  Address ad = PosixAddressToNs3Address (my_addr, addrlen);
+  int result = m_socket->Bind (ad);
+  if (result == -1)
+    {
+      current->err = ErrnoToSimuErrno ();
+    }
+  return result;
+}
+int 
+UnixSocketFd::Connect (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+
+  Address ad = PosixAddressToNs3Address (my_addr, addrlen);
+  int result = m_socket->Connect (ad);
+  if (result == -1)
+    {
+      current->err = ErrnoToSimuErrno ();
+    }
+  return result;
+}
+bool 
+UnixSocketFd::IsRecvErr (void) const
+{
+  return m_recverr == 1;
+}
+bool 
+UnixSocketFd::IsRecvTtl (void) const
+{
+  return m_recvttl == 1;
+}
+off64_t 
+UnixSocketFd::Lseek (off64_t offset, int whence)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << offset << whence);
+  NS_ASSERT (current != 0);
+  current->err = ESPIPE;
+  return -1;
+}
+bool
+UnixSocketFd::WaitRecvDoSignal (bool dontwait)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << dontwait);
+  if (dontwait && !CanRecv ())
+    {
+      current->err = EAGAIN;
+      return false;
+    }
+  if (!CanRecv ())
+    {
+      Waiter waiter;
+      SetRecvWaiter (&waiter);
+      waiter.SetTimeout (m_recvTimeout);
+      bool ok = waiter.WaitDoSignal ();
+      SetRecvWaiter (0);
+      NS_ASSERT_MSG (ok?CanRecv ():true, this << " " << current);
+      return ok;
+    }
+  NS_ASSERT (CanRecv ());
+  return true;
+}
+Time 
+UnixSocketFd::GetRecvTimeout (void)
+{
+  return m_recvTimeout;
+}
+Time 
+UnixSocketFd::GetSendTimeout (void)
+{
+  return m_sendTimeout;
+}
+
+int 
+UnixSocketFd::Settime (int flags,
+		       const struct itimerspec *new_value,
+		       struct itimerspec *old_value)
+{
+  NS_LOG_FUNCTION (this << Current () << flags << new_value << old_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return -1;
+}
+int 
+UnixSocketFd::Gettime (struct itimerspec *cur_value) const
+{
+  NS_LOG_FUNCTION (this << Current () << cur_value);
+  NS_ASSERT (Current () != 0);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return -1;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-socket-fd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,81 @@
+#ifndef UNIX_SOCKET_FD_H
+#define UNIX_SOCKET_FD_H
+
+#include "unix-fd.h"
+#include "ns3/ptr.h"
+#include "ns3/address.h"
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+#include <linux/types.h>
+#include <linux/errqueue.h>
+#include <netinet/in.h>
+#include <list>
+
+
+namespace ns3 {
+
+class Socket;
+class Thread;
+class Waiter;
+
+class UnixSocketFd : public UnixFd
+{
+public:
+  virtual ~UnixSocketFd ();
+  virtual int Close (void);
+  virtual ssize_t Write (const void *buf, size_t count);
+  virtual ssize_t Read (void *buf, size_t count);
+  virtual ssize_t Recvmsg(struct msghdr *msg, int flags);
+  virtual ssize_t Sendmsg(const struct msghdr *msg, int flags);
+  virtual bool Isatty (void) const;
+  virtual int Setsockopt (int level, int optname,
+			  const void *optval, socklen_t optlen);
+  virtual int Getsockopt (int level, int optname,
+			  void *optval, socklen_t *optlen);
+  virtual int Getsockname(struct sockaddr *name, socklen_t *namelen);
+  virtual int Getpeername(struct sockaddr *name, socklen_t *namelen);
+  virtual int Ioctl (int request, char *argp);
+  virtual int Bind (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual int Connect (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual void *Mmap (void *start, size_t length, int prot, int flags, off64_t offset);
+  virtual off64_t Lseek (off64_t offset, int whence);
+  virtual int Fxstat (int ver, struct stat *buf);
+  virtual int Fxstat64 (int ver, struct stat64 *buf);
+  virtual int Fcntl (int cmd, unsigned long arg);
+  virtual int Settime (int flags,
+		       const struct itimerspec *new_value,
+		       struct itimerspec *old_value);
+  virtual int Gettime (struct itimerspec *cur_value) const;
+
+private:
+  virtual ssize_t DoRecvmsg(struct msghdr *msg, int flags) = 0;
+  virtual ssize_t DoSendmsg(const struct msghdr *msg, int flags) = 0;
+
+protected:
+  UnixSocketFd (Ptr<Socket> sock);
+  int ErrnoToSimuErrno (void) const;
+  Address PosixAddressToNs3Address (const struct sockaddr *my_addr, socklen_t addrlen) const;
+  int Ns3AddressToPosixAddress(const Address& nsaddr, 
+			       struct sockaddr *addr, socklen_t *addrlen) const;
+  bool WaitRecvDoSignal (bool blocking);
+  Time GetRecvTimeout (void);
+  Time GetSendTimeout (void);
+  bool IsRecvErr (void) const;
+  bool IsRecvTtl (void) const;
+
+  Ptr<Socket> m_socket;
+
+private:
+  void RecvSocketData (Ptr<Socket> socket);
+  void SendSocketData (Ptr<Socket> socket, uint32_t available);
+
+  Time m_sendTimeout;
+  Time m_recvTimeout;
+  int m_recvttl;
+  int m_recverr;
+  int m_statusFlags;
+};
+
+} // namespace ns3
+
+#endif /* UNIX_SOCKET_FD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-stream-socket-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,256 @@
+#include "unix-stream-socket-fd.h"
+#include "utils.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "waiter.h"
+#include "ns3/log.h"
+#include "ns3/socket.h"
+#include "ns3/packet.h"
+#include <errno.h>
+#include <algorithm>
+
+NS_LOG_COMPONENT_DEFINE ("UnixStreamSocketFd");
+
+namespace ns3 {
+
+UnixStreamSocketFd::UnixStreamSocketFd (Ptr<Socket> sock)
+  : UnixSocketFd (sock),
+    m_backlog (0)
+{
+  NS_LOG_FUNCTION (this << sock);
+  m_socket->SetAcceptCallback (MakeCallback (&UnixStreamSocketFd::ConnectionRequest, this),
+			       MakeCallback (&UnixStreamSocketFd::ConnectionCreated, this));
+}
+ssize_t 
+UnixStreamSocketFd::DoRecvmsg(struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << msg << flags);
+  NS_ASSERT (current != 0);
+
+  if (!WaitRecvDoSignal (flags & MSG_DONTWAIT))
+    {
+      // current->err set by callee
+      return -1;
+    }
+
+  uint32_t totalAvailable = 0;
+  for (uint32_t i = 0; i < msg->msg_iovlen; i++)
+    {
+      totalAvailable += msg->msg_iov[i].iov_len;
+    }
+  Address from;
+  Ptr<Packet> packet = m_socket->RecvFrom (totalAvailable, flags, from);
+  if (packet == 0)
+    {
+      current->err = ErrnoToSimuErrno ();
+      return -1;
+    }
+  NS_ASSERT (packet->GetSize () <= totalAvailable);
+  const uint8_t *buf = packet->PeekData ();
+  size_t toCopy = packet->GetSize ();
+  for (uint32_t i = 0; i < msg->msg_iovlen && toCopy > 0; i++)
+    {
+      uint32_t len = std::min (toCopy, msg->msg_iov[i].iov_len);
+      memcpy (msg->msg_iov[i].iov_base, buf, len);
+      toCopy -= len;
+      buf += len;
+    }
+  Ns3AddressToPosixAddress (from, (struct sockaddr*)msg->msg_name, &msg->msg_namelen);
+  return packet->GetSize ();
+}
+ssize_t 
+UnixStreamSocketFd::DoSendmsg(const struct msghdr *msg, int flags)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << msg << flags);
+  NS_ASSERT (current != 0);
+
+  if (msg->msg_name != 0 || msg->msg_namelen != 0)
+    {
+      current->err = EISCONN;
+      return -1;
+    }
+
+  Waiter waiter;
+  waiter.SetTimeout (GetSendTimeout ());
+  ssize_t retval = 0;
+  for (uint32_t i = 0; i < msg->msg_iovlen; ++i)
+    {
+      uint8_t *buf = (uint8_t *)msg->msg_iov[i].iov_base;
+      ssize_t len = msg->msg_iov[i].iov_len;
+      while (len > 0)
+	{
+	  while (m_socket->GetTxAvailable () == 0)
+	    {
+	      SetSendWaiter (&waiter);
+	      Waiter::Result result = waiter.Wait ();
+	      SetSendWaiter (0);
+	      switch (result) {
+	      case Waiter::OK:
+		break;
+	      case Waiter::INTERRUPTED:
+		if (retval != 0)
+		  {
+		    // this is a short write
+		    return retval;
+		  }
+		else
+		  {
+		    UtilsDoSignal ();
+		    current->err = EINTR;
+		    return -1;
+		  }
+		break;
+	      case Waiter::TIMEOUT:
+		if (retval != 0)
+		  {
+		    // this is a short write
+		    return retval;
+		  }
+		else
+		  {
+		    current->err = EAGAIN;
+		    return -1;
+		  }
+		break;
+	      }
+	    }
+	  ssize_t availLen = std::min (len, (ssize_t)m_socket->GetTxAvailable ());
+	  Ptr<Packet> packet = Create<Packet> (buf, availLen);
+	  int result;
+	  result = m_socket->Send (packet, flags);
+	  if (result == -1 && retval == 0)
+	    {
+	      if (retval != 0)
+		{
+		  // this is a short write
+		  return retval;
+		}
+	      else
+		{
+		  current->err = ErrnoToSimuErrno ();
+		  return -1;
+		}
+	    }
+	  NS_ASSERT (result == availLen);
+	  len -= result;
+	  buf += result;
+	  retval += result;
+	}
+    }
+  return retval;
+}
+int 
+UnixStreamSocketFd::Listen (int backlog)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << backlog);
+  NS_ASSERT (current != 0);
+
+  int retval = m_socket->Listen ();
+  if (retval == -1)
+    {
+      current->err = ErrnoToSimuErrno ();
+      return -1;
+    }
+  m_backlog = backlog;
+  return 0;
+}
+int 
+UnixStreamSocketFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << my_addr << addrlen);
+  NS_ASSERT (current != 0);
+
+  Waiter waiter;
+  SetRecvWaiter (&waiter);
+  waiter.SetTimeout (GetRecvTimeout ());
+  while (m_connectionQueue.empty ())
+    {
+      if (!waiter.Wait ())
+	{
+	  // current->err set by caller above.
+	  return -1;
+	}
+    }
+  SetRecvWaiter (0);
+
+  // create an fd for the socket.
+  int fd = UtilsAllocateFd ();
+  if (fd == -1)
+    {
+      current->err = EMFILE;
+      return -1;
+    }
+
+  Ptr<Socket> sock = m_connectionQueue.front ().first;
+  Address ad = m_connectionQueue.front ().second;
+  m_connectionQueue.pop_front ();
+  UnixStreamSocketFd *socket = new UnixStreamSocketFd (sock);
+
+  Ns3AddressToPosixAddress (ad, my_addr, addrlen);
+  current->process->openFiles.push_back (std::make_pair (fd, socket));
+  return fd;
+}
+bool 
+UnixStreamSocketFd::CanRecv (void) const
+{
+  return m_socket != 0 && (m_socket->GetRxAvailable () != 0 || !m_connectionQueue.empty ());
+}
+bool
+UnixStreamSocketFd::CanSend (void) const
+{
+  return m_socket != 0 && m_socket->GetTxAvailable () != 0;
+}
+bool 
+UnixStreamSocketFd::ConnectionRequest (Ptr<Socket> sock, const Address & from)
+{
+  NS_LOG_FUNCTION (sock << from);
+  return ((int)m_connectionQueue.size ()) < m_backlog;
+}
+void 
+UnixStreamSocketFd::ConnectionCreated (Ptr<Socket> sock, const Address & from)
+{
+  NS_LOG_FUNCTION (sock << from);
+  NS_ASSERT (((int)m_connectionQueue.size ()) < m_backlog);
+  m_connectionQueue.push_back (std::make_pair (sock, from));
+  WakeupRecv ();
+}
+int 
+UnixStreamSocketFd::Shutdown (int how)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current << how);
+  NS_ASSERT (current != 0);
+  
+  int retval;
+  if (how == SHUT_RD)
+    {
+      retval = m_socket->ShutdownRecv ();
+    }
+  else if (how == SHUT_WR)
+    {
+      retval = m_socket->ShutdownSend ();
+    }
+  else if (how == SHUT_RDWR)
+    {
+      retval = m_socket->ShutdownRecv ();
+      retval = m_socket->ShutdownSend ();
+    }
+  else
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  if (retval == -1)
+    {
+      current->err = ErrnoToSimuErrno ();
+      return -1;
+    }
+  return 0;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-stream-socket-fd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,31 @@
+#ifndef UNIX_STREAM_SOCKET_FD_H
+#define UNIX_STREAM_SOCKET_FD_H
+
+#include "unix-socket-fd.h"
+#include <list>
+
+namespace ns3 {
+
+class UnixStreamSocketFd : public UnixSocketFd
+{
+public:
+  UnixStreamSocketFd (Ptr<Socket> sock);
+private:
+  virtual ssize_t DoRecvmsg(struct msghdr *msg, int flags);
+  virtual ssize_t DoSendmsg(const struct msghdr *msg, int flags);
+  virtual int Listen (int backlog);
+  virtual int Accept (struct sockaddr *my_addr, socklen_t *addrlen);
+  virtual int Shutdown(int how);
+  virtual bool CanRecv (void) const;
+  virtual bool CanSend (void) const;
+
+  bool ConnectionRequest (Ptr<Socket> sock, const Address & from);
+  void ConnectionCreated (Ptr<Socket> sock, const Address & from);
+
+  std::list<std::pair<Ptr<Socket>,Address> > m_connectionQueue;
+  int m_backlog;
+};
+
+} // namespace ns3
+
+#endif /* UNIX_STREAM_SOCKET_FD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-timer-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,269 @@
+#include "unix-timer-fd.h"
+#include "utils.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include <errno.h>
+#include <sys/mman.h>
+
+NS_LOG_COMPONENT_DEFINE ("UnixTimerFd");
+
+namespace ns3 {
+
+UnixTimerFd::UnixTimerFd (int clockid, int flags)
+  : m_period (Seconds (0.0)),
+    m_skipped (0),
+    m_timer (),
+    m_waiter (0)
+{}
+
+int
+UnixTimerFd::Close (void)
+{
+  m_timer.Cancel ();
+  if (m_waiter != 0)
+    {
+      m_waiter->process->manager->Wakeup (m_waiter);
+    }
+  return 0;
+}
+  
+ssize_t 
+UnixTimerFd::Write (const void *buf, size_t count)
+{
+  NS_LOG_FUNCTION (this << buf << count);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return -1;
+}
+ssize_t 
+UnixTimerFd::Read(void *buf, size_t count)
+{
+  Thread *current = Current ();
+  if (count < 8)
+    {
+      current->err = EINVAL;
+      return -1;
+    }
+  uint64_t *counter = (uint64_t *)buf;
+  if (m_skipped > 0)
+    {
+      *counter = m_skipped;
+      m_skipped = 0;
+      return 0;
+    }
+  m_waiter = current;
+  current->process->manager->Wait ();
+  m_waiter = 0;
+  *counter = m_skipped;
+  m_skipped = 0;
+  
+  return 0;
+}
+ssize_t 
+UnixTimerFd::Recvmsg(struct msghdr *msg, int flags)
+{
+  NS_LOG_FUNCTION (this << msg << flags);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+ssize_t 
+UnixTimerFd::Sendmsg(const struct msghdr *msg, int flags)
+{
+  NS_LOG_FUNCTION (this << msg << flags);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+bool 
+UnixTimerFd::Isatty (void) const
+{
+  return false;
+}
+int 
+UnixTimerFd::Setsockopt (int level, int optname,
+			 const void *optval, socklen_t optlen)
+{
+  NS_LOG_FUNCTION (this << level << optname << optval << optlen);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Getsockopt (int level, int optname,
+			 void *optval, socklen_t *optlen)
+{
+  NS_LOG_FUNCTION (this << level << optname << optval << optlen);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Getsockname(struct sockaddr *name, socklen_t *namelen)
+{
+  NS_LOG_FUNCTION (this << name << namelen);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Getpeername(struct sockaddr *name, socklen_t *namelen)
+{
+  NS_LOG_FUNCTION (this << name << namelen);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Ioctl (int request, char *argp)
+{
+  //XXX
+  return -1;
+}
+int 
+UnixTimerFd::Bind (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  NS_LOG_FUNCTION (this << my_addr << addrlen);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Connect (const struct sockaddr *my_addr, socklen_t addrlen)
+{
+  NS_LOG_FUNCTION (this << my_addr << addrlen);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Listen (int backlog)
+{
+  NS_LOG_FUNCTION (this << backlog);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Shutdown(int how)
+{
+  NS_LOG_FUNCTION (this << how);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+int 
+UnixTimerFd::Accept (struct sockaddr *my_addr, socklen_t *addrlen)
+{
+  NS_LOG_FUNCTION (this << my_addr << addrlen);
+  Thread *current = Current ();
+  current->err = ENOTSOCK;
+  return -1;
+}
+void *
+UnixTimerFd::Mmap (void *start, size_t length, int prot, int flags, off64_t offset)
+{
+  NS_LOG_FUNCTION (this << start << length << prot << flags << offset);
+  Thread *current = Current ();
+  current->err = EINVAL;
+  return MAP_FAILED;
+}
+off64_t 
+UnixTimerFd::Lseek (off64_t offset, int whence)
+{
+  NS_LOG_FUNCTION (this << offset << whence);
+  Thread *current = Current ();
+  current->err = ESPIPE;
+  return -1;
+}
+int 
+UnixTimerFd::Fxstat (int ver, struct ::stat *buf)
+{
+  NS_LOG_FUNCTION (this << buf);
+  //XXX: I do not know what I should write here.
+  // but this call is expected to succeed by the kernel.
+  return 0;
+}
+int 
+UnixTimerFd::Fxstat64 (int ver, struct ::stat64 *buf)
+{
+  NS_LOG_FUNCTION (this << buf);
+  //XXX: I do not know what I should write here.
+  // but this call is expected to succeed by the kernel.
+  return 0;
+}
+int 
+UnixTimerFd::Fcntl (int cmd, unsigned long arg)
+{
+  // XXX: this really needs to be fixed
+  return 0;
+}
+void
+UnixTimerFd::TimerExpired (void)
+{
+  if (!m_period.IsZero ())
+    {
+      m_timer = Simulator::Schedule (m_period,
+				     &UnixTimerFd::TimerExpired,
+				     this);
+    }
+  m_skipped ++;
+  if (m_waiter != 0)
+    {
+      m_waiter->process->manager->Wakeup (m_waiter);
+    }
+}
+int 
+UnixTimerFd::Settime (int flags,
+		      const struct itimerspec *new_value,
+		      struct itimerspec *old_value)
+{
+  NS_ASSERT (flags == 0);
+  if (old_value != 0)
+    {
+      Gettime (old_value);
+    }
+  m_skipped = 0;
+  m_timer.Cancel ();
+  m_period = UtilsTimespecToTime (new_value->it_interval);
+  Time initial = UtilsTimespecToTime (new_value->it_value);
+  if (!initial.IsZero ())
+    {
+      m_timer = Simulator::Schedule (initial, 
+				     &UnixTimerFd::TimerExpired,
+				     this);
+    }
+  return 0;
+}
+int 
+UnixTimerFd::Gettime (struct itimerspec *cur_value) const
+{
+  if (!m_timer.IsRunning ())
+    {
+      cur_value->it_value.tv_sec = 0;
+      cur_value->it_value.tv_nsec = 0;
+    }
+  else
+    {
+      Time left = Simulator::GetDelayLeft (m_timer);
+      cur_value->it_value = UtilsTimeToTimespec (left);
+    }
+  cur_value->it_interval = UtilsTimeToTimespec (m_period);
+  return 0;
+}
+
+bool 
+UnixTimerFd::CanRecv (void) const
+{
+  // XXX ?
+  return false;
+}
+bool 
+UnixTimerFd::CanSend (void) const
+{
+  return false;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/unix-timer-fd.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,58 @@
+#ifndef UNIX_TIMER_FD_H
+#define UNIX_TIMER_FD_H
+
+#include "unix-fd.h"
+#include "process.h"
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+
+namespace ns3 {
+
+class UnixTimerFd : public UnixFd
+{
+public:
+  UnixTimerFd (int clockid, int flags);
+
+  virtual int Close (void);  
+  virtual ssize_t Write (const void *buf, size_t count);
+  virtual ssize_t Read(void *buf, size_t count);
+  virtual ssize_t Recvmsg(struct msghdr *msg, int flags);
+  virtual ssize_t Sendmsg(const struct msghdr *msg, int flags);
+  virtual bool Isatty (void) const;
+  virtual int Setsockopt (int level, int optname,
+			  const void *optval, socklen_t optlen);
+  virtual int Getsockopt (int level, int optname,
+			  void *optval, socklen_t *optlen);
+  virtual int Getsockname(struct sockaddr *name, socklen_t *namelen);
+  virtual int Getpeername(struct sockaddr *name, socklen_t *namelen);
+  virtual int Ioctl (int request, char *argp);
+  virtual int Bind (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual int Connect (const struct sockaddr *my_addr, socklen_t addrlen);
+  virtual int Listen (int backlog);
+  virtual int Shutdown(int how);
+  virtual int Accept (struct sockaddr *my_addr, socklen_t *addrlen);
+  virtual void *Mmap (void *start, size_t length, int prot, int flags, off64_t offset);
+  virtual off64_t Lseek (off64_t offset, int whence);
+  virtual int Fxstat (int ver, struct ::stat *buf);
+  virtual int Fxstat64 (int ver, struct ::stat64 *buf);
+  virtual int Fcntl (int cmd, unsigned long arg);
+  virtual int Settime (int flags,
+		       const struct itimerspec *new_value,
+		       struct itimerspec *old_value);
+  virtual int Gettime (struct itimerspec *cur_value) const;
+
+  virtual bool CanRecv (void) const;
+  virtual bool CanSend (void) const;
+
+private:
+  void TimerExpired (void);
+
+  Time m_period;
+  uint64_t m_skipped;
+  EventId m_timer;
+  Thread * m_waiter;
+};
+
+} // namespace ns3
+
+#endif /* UNIX_TIMER_FD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/utils.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,255 @@
+#include "utils.h"
+#include "dce-manager.h"
+#include "unix-fd.h"
+#include "process.h"
+#include "task-manager.h"
+#include "ns3/node.h"
+#include "ns3/log.h"
+#include <sstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+
+NS_LOG_COMPONENT_DEFINE ("ProcessUtils");
+
+namespace ns3 {
+
+uint32_t UtilsGetNodeId (void)
+{
+  return Simulator::GetContext ();
+}
+static std::string UtilsGetRealFilePath (uint32_t node)
+{
+  std::ostringstream oss;
+  oss << "files-" << node;
+  return oss.str ();
+}
+static std::string UtilsGetRealFilePath (void)
+{
+  return UtilsGetRealFilePath (UtilsGetNodeId ());
+}
+
+std::string UtilsGetAbsRealFilePath (uint32_t node, std::string path)
+{
+  NS_LOG_FUNCTION (Current () << path);
+
+  std::string nodeDir = UtilsGetRealFilePath (node);
+  UtilsEnsureDirectoryExists (nodeDir);
+  return nodeDir + path;  
+}
+
+std::string 
+UtilsGetRealFilePath (std::string path)
+{
+  NS_LOG_FUNCTION (Current () << path);
+
+  std::string nodeDir = UtilsGetRealFilePath ();
+  UtilsEnsureDirectoryExists (nodeDir);
+  return nodeDir + UtilsGetVirtualFilePath (path);
+}
+
+void UtilsEnsureDirectoryExists (std::string realPath)
+{
+  ::DIR *dir = ::opendir (realPath.c_str ());
+  if (dir != 0)
+    {
+      ::closedir (dir);
+    }
+  else if (errno == ENOENT)
+    {
+      int status = ::mkdir (realPath.c_str (), S_IRWXU | S_IRWXG);
+      if (status == -1)
+	{
+	  NS_FATAL_ERROR ("Could not create directory " << realPath <<
+			  ": " << strerror (errno));
+	}
+    }
+}
+
+std::string UtilsGetVirtualFilePath (std::string path)
+{
+  NS_LOG_FUNCTION (Current () << path);
+
+  std::string::size_type slash = path.find ("/");
+  if (slash == 0)
+    {
+      // path relative to root of node.
+      return path;
+    }
+  else
+    {
+      NS_ASSERT (Current () != 0);
+      Thread *current = Current ();
+      // path relative to cwd in node
+      return current->process->cwd + "/" + path;
+    }
+}
+
+int
+UtilsSearchOpenFd (int fd)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (current << fd);
+  NS_ASSERT (current != 0);
+  int index = 0;
+  for (std::vector<std::pair<int,UnixFd *> >::iterator i = current->process->openFiles.begin (); 
+       i != current->process->openFiles.end (); ++i)
+    {
+      if (i->first == fd)
+	{
+          return index;
+        }
+      index++;
+    }
+  return -1;
+}
+Thread *Current (void)
+{
+  TaskManager *manager = TaskManager::Current ();
+  if (manager == 0)
+    {
+      return 0;
+    }
+  return (struct Thread *)manager->CurrentTask ()->GetContext ();
+}
+bool HasPendingSignal (void)
+{
+  bool isPending = sigisemptyset (&(Current ()->process->pendingSignals)) == 0;
+  return isPending;
+}
+struct timeval UtilsTimeToTimeval (Time time)
+{
+  struct timeval tv;
+  tv.tv_sec = (time_t) time.GetSeconds ();
+  tv.tv_usec = time.GetMicroSeconds () % 1000000;
+  return tv;
+}
+struct timespec UtilsTimeToTimespec (Time time)
+{
+  struct timespec tv;
+  tv.tv_sec = (time_t) time.GetSeconds ();
+  tv.tv_nsec = time.GetNanoSeconds () % 1000000000;
+  return tv;
+}
+static unsigned long TimeBase (void)
+{
+  unsigned long secondsSinceEpochOnFridayApril042008 = 1207284276;
+  return secondsSinceEpochOnFridayApril042008;
+}
+Time UtilsSimulationTimeToTime (Time time)
+{
+  return time + Seconds (TimeBase ());
+}
+Time UtilsTimeToSimulationTime (Time time)
+{
+  return time - Seconds (TimeBase ());
+}
+Time UtilsTimevalToTime (struct timeval tv)
+{
+  Time time = Seconds (tv.tv_sec);
+  time += MicroSeconds (tv.tv_usec);
+  return time;
+}
+Time UtilsTimevalToTime (const struct timeval *tv)
+{
+  if (tv == 0)
+    {
+      return Seconds (0.0);
+    }
+  return UtilsTimevalToTime (*tv);
+}
+Time UtilsTimespecToTime (struct timespec tm)
+{
+  Time time = Seconds (tm.tv_sec);
+  time += NanoSeconds (tm.tv_nsec);
+  return time;
+}
+void
+UtilsSendSignal (Process *process, int signum)
+{
+  sigaddset (&process->pendingSignals, signum);
+  for (std::vector<Thread *>::iterator i = process->threads.begin (); 
+       i != process->threads.end (); ++i)
+    {
+      Thread *thread = *i;
+      if (sigismember (&thread->signalMask, signum) == 0)
+	{
+	  // signal not blocked by thread.
+	  if (thread->task->IsBlocked ())
+	    {
+	      process->manager->Wakeup (thread);
+	      return;
+	    }
+	}
+    }
+  // Could not find any candidate thread to receive signal.
+  // signal pending until a thread unblocks it.
+}
+void UtilsDoSignal (void)
+{
+  Thread *current = Current ();
+  // we try to check if we 
+  // have pending signals and we deliver them if we have any.
+  for (std::vector<SignalHandler>::iterator i = current->process->signalHandlers.begin (); 
+       i != current->process->signalHandlers.end (); ++i)
+    {
+      if (sigismember (&current->signalMask, i->signal) == 1 &&
+	  i->signal != SIGKILL &&
+	  i->signal != SIGSTOP)
+	{
+	  // don't deliver signals which are masked
+	  // ignore the signal mask for SIGKILL and SIGSTOP
+	  // though.
+	  continue;
+	}
+      if (sigismember (&current->pendingSignals, i->signal) == 1)
+	{
+	  NS_LOG_DEBUG ("deliver signal=" << i->signal);
+	  // the signal is pending so, we try to deliver it.
+	  if (i->flags & SA_SIGINFO)
+	    {
+	      siginfo_t info;
+	      ucontext_t ctx;
+	      i->sigaction (i->signal, &info, &ctx);
+	    }
+	  else
+	    {
+	      i->handler (i->signal);
+	    }
+	  sigdelset (&current->pendingSignals, i->signal);
+	}
+      if (sigismember (&current->process->pendingSignals, i->signal) == 1)
+	{
+	  NS_LOG_DEBUG ("deliver signal=" << i->signal);
+	  // the signal is pending so, we try to deliver it.
+	  if (i->flags & SA_SIGINFO)
+	    {
+	      siginfo_t info;
+	      ucontext_t ctx;
+	      i->sigaction (i->signal, &info, &ctx);
+	    }
+	  else
+	    {
+	      i->handler (i->signal);
+	    }
+	  sigdelset (&current->process->pendingSignals, i->signal);
+	}
+    }
+}
+int UtilsAllocateFd (void)
+{
+  for (int fd = 0; fd < MAX_FDS; fd++)
+    {
+      if (UtilsSearchOpenFd (fd) == -1)
+	{
+	  NS_LOG_DEBUG ("Allocated fd=" << fd);
+	  return fd;
+	}
+    }
+  return -1;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/utils.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,50 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <string>
+#include <sys/time.h>
+#include "ns3/nstime.h"
+
+#define GET_CURRENT(x)					\
+  Thread *current;					\
+  current = Current ();					\
+  do {							\
+  NS_LOG_FUNCTION (current << UtilsGetNodeId () << x);	\
+  NS_ASSERT (current != 0);				\
+  } while (false)
+#define GET_CURRENT_NOLOG()				\
+  Thread *current;					\
+  current = Current ();					\
+  do {							\
+  NS_LOG_FUNCTION (current << UtilsGetNodeId ());	\
+  NS_ASSERT (current != 0);				\
+  } while (false)
+
+
+namespace ns3 {
+
+class Thread;
+class Process;
+
+void UtilsEnsureDirectoryExists (std::string realPath);
+std::string UtilsGetRealFilePath (std::string path);
+std::string UtilsGetAbsRealFilePath (uint32_t node, std::string path);
+std::string UtilsGetVirtualFilePath (std::string path);
+uint32_t UtilsGetNodeId (void);
+int UtilsSearchOpenFd (int fd);
+Thread *Current (void);
+bool HasPendingSignal (void);
+Time UtilsTimeToSimulationTime (Time time);
+Time UtilsSimulationTimeToTime (Time time);
+struct timeval UtilsTimeToTimeval (Time time);
+struct timespec UtilsTimeToTimespec (Time time);
+Time UtilsTimespecToTime (struct timespec tm);
+Time UtilsTimevalToTime (struct timeval tv);
+Time UtilsTimevalToTime (const struct timeval *tv);
+void UtilsSendSignal (Process *process, int signum);
+void UtilsDoSignal (void);
+int UtilsAllocateFd (void);
+#define MAX_FDS 1024
+} // namespace ns3
+
+#endif /* UTILS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/waiter.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,114 @@
+#include "waiter.h"
+#include "utils.h"
+#include "process.h"
+#include "dce-manager.h"
+#include "task-manager.h"
+#include "ns3/simulator.h"
+#include "ns3/event-id.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include <errno.h>
+
+NS_LOG_COMPONENT_DEFINE ("Waiter");
+
+namespace ns3 {
+
+Waiter::Waiter ()
+  : m_waiting (0),
+    m_timeout (Seconds (0.0))
+{
+  NS_LOG_FUNCTION(this);
+}
+
+Waiter::~Waiter ()
+{
+  NS_LOG_FUNCTION(this);
+}
+
+void
+Waiter::SetTimeout (Time timeout)
+{
+  m_timeout = timeout;
+}
+Time
+Waiter::GetTimeoutLeft (void) const
+{
+  return m_timeout;
+}
+
+Waiter::Result 
+Waiter::Wait (void)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  NS_ASSERT (current != 0);
+  EventId timer;
+  if (!m_timeout.IsZero ())
+    {
+      timer = Simulator::Schedule (m_timeout, &Waiter::Wakeup, this);
+    }
+  m_waiting = current;
+  current->process->manager->Wait ();
+  m_waiting = 0;
+  if (HasPendingSignal ())
+    {
+      timer.Cancel ();
+      m_timeout = Seconds (0.0);
+      NS_LOG_DEBUG ("interrupted self=" << this << " current=" << current);
+      return Waiter::INTERRUPTED;
+    }
+  if (!m_timeout.IsZero () && timer.IsExpired ())
+    {
+      m_timeout = Seconds (0.0);
+      NS_LOG_DEBUG ("timeout self=" << this << " current=" << current);
+      return Waiter::TIMEOUT;
+    }
+  timer.Cancel ();
+  m_timeout = Simulator::GetDelayLeft (timer);
+  NS_LOG_DEBUG ("ok self=" << this << " current=" << current);
+  return Waiter::OK;
+}
+bool 
+Waiter::WaitDoSignal (void)
+{
+  Thread *current = Current ();
+  NS_LOG_FUNCTION (this << current);
+  Waiter::Result result = Wait ();
+  switch (result) {
+  case Waiter::INTERRUPTED:
+    UtilsDoSignal ();
+    current->err = EINTR;
+    return false;
+    break;
+  case Waiter::TIMEOUT:
+    current->err = EAGAIN;
+    return false;
+    break;
+  case Waiter::OK:
+    break;
+  }
+  return true;
+}
+
+void 
+Waiter::Wakeup (void)
+{
+  NS_LOG_FUNCTION (this << m_waiting);
+  if (m_waiting != 0)
+    {
+      /* The waiting thread could well be active because, it could have been
+       * unblocked but not scheduled yet which means that the assignment of 
+       * m_waiting to zero has not been done yet in Waiter::Wait.
+       */
+      if (m_waiting->task->IsBlocked ())
+	{
+	  m_waiting->process->manager->Wakeup (m_waiting);
+	}
+      else
+	{
+	  NS_ASSERT (m_waiting->task->IsActive ());
+	}
+    }
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/waiter.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,47 @@
+#ifndef WAITER_H
+#define WAITER_H
+
+#include "ns3/nstime.h"
+#include "ns3/callback.h"
+#include "ns3/event-id.h"
+
+namespace ns3 {
+
+struct Thread;
+
+class Waiter
+{
+public:
+  typedef enum
+  {
+    INTERRUPTED,
+    TIMEOUT,
+    OK
+  } Result;
+
+  Waiter ();
+  ~Waiter ();
+
+  void SetTimeout (Time timeout);
+  Time GetTimeoutLeft (void) const;
+  // wait for a call to Wakeup, return OK if Wakeup is called
+  // and no signal is pending.
+  // return TIMEOUT if timeout expired
+  // return INTERRUPTED if signal pending.
+  Waiter::Result Wait (void);
+  // wait for a call to Wakeup, handle signals and stop timeout 
+  // if any are pending. Return true only if Wakeup is called
+  // and no signal is pending.
+  bool WaitDoSignal (void);
+
+  // wakeup someone waiting on Wait.
+  void Wakeup (void);
+private:
+
+  Thread *m_waiting;
+  Time m_timeout;
+};
+
+} // namespace ns3
+
+#endif /* WAITER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/wscript	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,190 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+import Options
+import os.path
+
+class CouldNotFindFile:
+    pass
+
+def search_file(files):
+    for f in files:
+        if os.path.isfile (f):
+            return f
+    raise CouldNotFindFile ()
+
+
+def set_options(opt):
+    opt.tool_options('compiler_cc') 
+    opt.add_option('--with-linux-stack',
+                   help=('Path to the linux module'),
+                   default=None,
+                   dest='linux_stack', type="string")
+
+def configure(conf):
+    conf.check_tool('compiler_cc')
+    conf.check(function_name='makecontext', 
+               header_name='ucontext.h',
+               mandatory=True)
+    conf.env.append_value('LINKFLAGS', '-pthread')
+    conf.env['HAVE_DL'] = conf.check (lib='dl')
+
+    if Options.options.linux_stack is not None and os.path.isdir(Options.options.linux_stack):
+        conf.check_message("linux stack location", '', True, 
+                           ("%s (given)" % Options.options.linux_stack))
+        conf.report_optional_feature("linux stack", "Linux stack", True,
+                                     "enabled (found in %s)" % Options.options.linux_stack)
+        conf.env['LINUX_STACK'] = os.path.abspath(Options.options.linux_stack)
+        conf.env.append_value('NS3_MODULE_PATH', conf.env['LINUX_STACK'])
+    else:
+        conf.check_message("linux stack location", '', False)
+        conf.report_optional_feature("linux stack", "Linux stack", False,
+                                     "linux stack not found")
+
+    vg_h = conf.check(header_name='valgrind/valgrind.h')
+    vg_memcheck_h = conf.check(header_name='valgrind/memcheck.h')
+    if vg_h and vg_memcheck_h:
+        conf.env.append_value('CXXDEFINES', 'HAVE_VALGRIND_H')
+
+
+def build(bld):
+    dce = bld.create_ns3_module('dce', ['core', 'common', 'simulator', 'node'])
+    dce.source = [
+        'dce-manager.cc',
+	'dce-application.cc',
+        'simu.cc',
+        'simu-signal.cc',
+        'dce-manager-test.cc',
+        'libc-simu.c',
+        'utils.cc',
+        'unix-fd.cc',
+        'unix-file-fd.cc',
+        'unix-socket-fd.cc',
+        'unix-datagram-socket-fd.cc',
+        'unix-stream-socket-fd.cc',
+        'unix-timer-fd.cc',
+        'simu-fd.cc',
+        'simu-stdio.cc',
+        'simu-pthread.cc',
+        'simu-stdlib.cc',
+        'simu-debug.cc',
+        'simu-semaphore.cc',
+        'simu-pthread-mutex.cc',
+        'simu-cxa.cc',
+        'simu-netdb.cc',
+        'simu-string.cc',
+        'simu-env.cc',
+        'simu-pthread-cond.cc',
+        'simu-timerfd.cc',
+        'simu-stat.cc',
+        'simu-global-variables.cc',
+        'cmsg.cc',
+        'waiter.cc',
+        'alloc.cc',
+        'simu-alloc.cc',
+        'trampoline-manager.cc',
+        'system-wrappers.cc',
+        'fiber-manager.cc',
+        'ucontext-fiber-manager.cc',
+        'pthread-fiber-manager.cc',
+        'task-manager.cc',
+        'task-scheduler.cc',
+        'rr-task-scheduler.cc',
+        'loader-factory.cc',
+        'elf-dependencies.cc',
+        'elf-cache.cc',
+        'cooja-loader-factory.cc',
+        'copy-loader-factory.cc',
+        'dlm-loader-factory.cc',
+        'socket-fd-factory.cc',
+        'ns3-socket-fd-factory.cc',
+        'netlink/netlink-socket.cc',
+        'netlink/netlink-socket-address.cc',
+        'netlink/netlink-socket-factory.cc',
+        'netlink/netlink-attribute.cc',
+        'netlink/netlink-message.cc',
+        'netlink/netlink-message-route.cc',
+        'netlink/netlink-socket-test.cc',
+        ]
+    dce.uselib = 'DL'
+
+    headers = bld.new_task_gen('ns3header')
+    headers.module = 'dce'
+    headers.source = [
+        'dce-manager.h',
+        'task-scheduler.h',
+        'task-manager.h',
+        'socket-fd-factory.h',
+        'loader-factory.h',
+	'dce-application.h',
+        ]
+
+    if dce.env['LINUX_STACK']:
+        dce.source.extend([
+                'linux-socket-fd-factory.cc',
+                'linux-socket-fd.cc',
+                ])
+        dce.includes = dce.env['LINUX_STACK']
+        headers.source.extend ([
+                'linux-socket-fd-factory.h'])
+
+
+    rvd = bld.new_task_gen('cc', 'program')
+    rvd.name = 'readversiondef'
+    rvd.target = 'readversiondef'
+    rvd.source = ['readversiondef.c']
+
+    bld.add_group('dce_version_files')
+
+    libc = search_file ([
+            '/lib64/libc.so.6',
+            '/lib/libc.so.6',
+            ])
+    libpthread = search_file ([
+            '/lib64/libpthread.so.0',
+            '/lib/libpthread.so.0',
+            ])
+
+    bld.new_task_gen(source=['readversiondef', 'libc-ns3.version'],
+                     target='libc.version',
+                     rule='${SRC[0].abspath(env)} ' + libc + ' |' \
+                         'cat ${SRC[1].abspath()} - > ${TGT}')
+
+    bld.new_task_gen(source=['readversiondef', 'libpthread-ns3.version'],
+                     target='libpthread.version',
+                     rule='${SRC[0].abspath(env)} ' + libpthread + ' |' \
+                         'cat ${SRC[1].abspath()} - > ${TGT}')
+
+    bld.add_group('dce_use_version_files')
+
+    # The very small libc used to replace the glibc
+    # and forward to the simu_* code
+    module = bld.new_task_gen('cc', 'shlib')
+    module.name = 'c-ns3'
+    module.target = module.name
+    module.env.append_value('CCFLAGS', module.env['shlib_CCFLAGS'])
+    module.env.append_value('CCFLAGS', '-g')
+    module.env.append_value('CCDEFINES', 'LIBSETUP=libc_setup')
+    module.env.append_value('LINKFLAGS', '-nostdlib')
+    module.env.append_value('LINKFLAGS', 
+                            '-Wl,--version-script=' + bld.path.find_or_declare('libc.version').bldpath(bld.env))
+    module.env.append_value('LINKFLAGS', '-Wl,-soname=libc.so.6')
+    module.source = ['libc.c', 'libc-global-variables.c']
+
+    # The very small libpthread used to replace the glibc
+    # and forward to the simu_* code
+    module = bld.new_task_gen('cc', 'shlib')
+    module.name = 'pthread-ns3'
+    module.target = module.name
+    module.env.append_value('CCFLAGS', module.env['shlib_CCFLAGS'])
+    module.env.append_value('CCFLAGS', '-g')
+    module.env.append_value('CCDEFINES', 'LIBSETUP=libpthread_setup')
+    module.env.append_value('LINKFLAGS', '-nostdlib')
+    module.env.append_value('LINKFLAGS', '-lc')
+    module.env.append_value('LINKFLAGS', 
+                            '-Wl,--version-script=' + bld.path.find_or_declare('libpthread.version').bldpath(bld.env))
+    module.env.append_value('LINKFLAGS', '-Wl,-soname=libpthread.so.0')
+    module.source = ['libc.c']
+
+    # The following is needed to debug loader errors on ubuntu when you install libc6-dbg.
+    #obj.env.append_value('LINKFLAGS', '-Wl,--dynamic-linker=/usr/lib/debug/ld-linux.so.2')
+
+    bld.set_group(0)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-cond.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,121 @@
+#include <pthread.h>
+#include "test-macros.h"
+
+void test_attr_init (void)
+{
+  pthread_condattr_t attr;
+  int status = pthread_condattr_init (&attr);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_condattr_destroy (&attr);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+void test_init (void)
+{
+  pthread_cond_t cond;
+  int status = pthread_cond_init (&cond, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_cond_destroy (&cond);
+  TEST_ASSERT_EQUAL (status, 0);
+  pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
+  status = pthread_cond_destroy (&cond2);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+struct BarrierContext
+{
+  BarrierContext ();
+  int sense;
+};
+class Barrier
+{
+public:
+  Barrier (int expected);
+  ~Barrier ();
+  void Wait (struct BarrierContext *context);
+private:
+  pthread_cond_t m_cond;
+  pthread_mutex_t m_mutex;  
+  int m_expected;
+  int m_reached;
+  int m_release;
+};
+
+BarrierContext::BarrierContext ()
+  : sense (1)
+{}
+
+Barrier::Barrier (int expected)
+  : m_expected (expected),
+    m_reached (0),
+    m_release (0)
+{
+  pthread_cond_init (&m_cond, 0);
+  pthread_mutex_init (&m_mutex, 0);
+}
+Barrier::~Barrier ()
+{
+  pthread_cond_destroy (&m_cond);
+  pthread_mutex_destroy (&m_mutex);
+}
+void 
+Barrier::Wait (struct BarrierContext *context)
+{
+  pthread_mutex_lock (&m_mutex);
+  context->sense = -context->sense;
+  m_reached++;
+  if (m_reached == m_expected)
+    {
+      m_reached = 0;
+      m_release = context->sense;
+      pthread_cond_broadcast (&m_cond);
+    }
+  else
+    {
+      while (m_release != context->sense)
+	{
+	  pthread_cond_wait (&m_cond, &m_mutex);
+	}
+    }
+  pthread_mutex_unlock (&m_mutex);
+}
+
+int g_nIterations = 1000;
+
+void *thread (void *context)
+{
+  Barrier *barrier = (Barrier *)context;
+  BarrierContext ctx;
+  for (int i = 0; i < g_nIterations; i++)
+    {
+      barrier->Wait (&ctx);
+    }
+  return 0;
+}
+
+void test_cond (void)
+{
+  int nThreads = 4;
+  
+  Barrier *barrier = new Barrier (nThreads);
+  pthread_t * threads = new pthread_t [nThreads] ();
+  for (int i = 0; i < nThreads; i++)
+    {
+      pthread_create (&threads[i], 0, thread, barrier);
+    }
+  for (int i = 0; i < nThreads; i++)
+    {
+      pthread_join (threads[i], 0);
+    }
+
+  delete barrier;
+  delete [] threads;
+}
+
+int main (int argc, char *argv[])
+{
+  test_attr_init ();
+  test_init ();
+  test_cond ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-empty.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,4 @@
+int main (int argc, char *argv[])
+{
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-env.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,120 @@
+#include <stdlib.h>
+#include "test-macros.h"
+
+static bool environ_search (const char *str)
+{
+  for (char **cur = environ; *cur != 0; cur++)
+    {
+      if (strcmp (str, *cur) == 0)
+	{
+	  return true;
+	}
+    }
+  return false;
+}
+
+void test_environ (void)
+{
+  clearenv ();
+  setenv ("F", "10", 1);
+  TEST_ASSERT (environ_search ("F=10"));
+  setenv ("E", "9", 1);
+  TEST_ASSERT (environ_search ("F=10"));
+  TEST_ASSERT (environ_search ("E=9"));
+  setenv ("D", "8", 1);
+  TEST_ASSERT (environ_search ("F=10"));
+  TEST_ASSERT (environ_search ("E=9"));
+  TEST_ASSERT (environ_search ("D=8"));
+  unsetenv ("E");
+  TEST_ASSERT (environ_search ("F=10"));
+  TEST_ASSERT (!environ_search ("E=9"));
+  TEST_ASSERT (environ_search ("D=8"));
+}
+
+void test_putenv (void)
+{
+  clearenv ();
+  char *nothing = getenv ("THIS_IS_A_TEST");
+  TEST_ASSERT_EQUAL (nothing, 0);
+  char *shel = getenv ("SHEL");
+  TEST_ASSERT_EQUAL (shel, 0);
+
+  int status = putenv ((char*)"SHEL=foo");
+  TEST_ASSERT_EQUAL (status, 0);
+  shel = getenv ("SHEL");
+  TEST_ASSERT_UNEQUAL (shel, 0);
+  TEST_ASSERT (strcmp (shel, "foo") == 0);
+  status = putenv ((char*)"SHEL=bar");
+  TEST_ASSERT_EQUAL (status, 0);
+  shel = getenv ("SHEL");
+  TEST_ASSERT_UNEQUAL (shel, 0);
+  TEST_ASSERT (strcmp (shel, "bar") == 0);
+
+  status = putenv ((char*)"SHEL");
+  TEST_ASSERT_EQUAL (status, 0);
+  shel = getenv ("SHEL");
+  TEST_ASSERT_EQUAL (shel, 0);
+  
+  status = putenv ((char*)"A=a");
+  TEST_ASSERT_EQUAL (status, 0);
+  status = putenv ((char*)"B=b");
+  TEST_ASSERT_EQUAL (status, 0);
+  status = putenv ((char*)"C=c");
+  TEST_ASSERT_EQUAL (status, 0);
+  status = putenv ((char*)"B=b");
+  TEST_ASSERT_EQUAL (status, 0);
+  status = putenv ((char*)"B");
+  TEST_ASSERT_EQUAL (status, 0);
+  shel = getenv ("A");
+  TEST_ASSERT_UNEQUAL (shel, 0);
+  shel = getenv ("B");
+  TEST_ASSERT_EQUAL (shel, 0);
+  shel = getenv ("C");
+  TEST_ASSERT_UNEQUAL (shel, 0);
+}
+
+void test_setenv (void)
+{  
+  int status = clearenv ();
+  TEST_ASSERT_EQUAL (status, 0);
+  char *shel = getenv ("A");
+  TEST_ASSERT_EQUAL (shel, 0);
+  shel = getenv ("B");
+  TEST_ASSERT_EQUAL (shel, 0);
+  shel = getenv ("C");
+  TEST_ASSERT_EQUAL (shel, 0);
+
+  status = setenv ("A", "a", 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = setenv ("B", "b", 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = setenv ("C", "c", 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = setenv ("B", "c", 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  shel = getenv ("B");
+  TEST_ASSERT (strcmp (shel, "b") == 0);
+  status = setenv ("B", "c", 1);
+  TEST_ASSERT_EQUAL (status, 0);
+  shel = getenv ("B");
+  TEST_ASSERT (strcmp (shel, "c") == 0);
+  status = unsetenv ("B");
+  TEST_ASSERT_EQUAL (status, 0);
+  status = unsetenv ("D");
+  TEST_ASSERT_EQUAL (status, 0);
+  shel = getenv ("A");
+  TEST_ASSERT_UNEQUAL (shel, 0);
+  shel = getenv ("B");
+  TEST_ASSERT_EQUAL (shel, 0);
+  shel = getenv ("C");
+  TEST_ASSERT_UNEQUAL (shel, 0);
+
+}
+
+int main (int argc, char *argv[])
+{
+  test_putenv ();
+  test_setenv ();
+  test_environ ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-fd-simple.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,362 @@
+#define _GNU_SOURCE 1
+#include "test-macros.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+
+static void test_open_exclusive (void)
+{
+  int status, fd;
+
+  // first, make sure we get an empty file
+  fd = open ("X", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+
+  // create a second time exclusive. fail.
+  status = open ("X", O_CREAT | O_EXCL | O_RDWR, S_IRWXU);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EEXIST);
+
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // a second time
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EBADF);
+
+  // invalid fd
+  status = close (-1);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EBADF);
+
+  // cleanup
+  status = unlink ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_stat (void)
+{
+  int fd, status;
+
+  // make sure file does not exist yet.
+  fd = open ("X", O_RDONLY);
+  TEST_ASSERT_EQUAL (fd, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // make sure it really does not exist
+  struct stat st;
+  status = stat ("X", &st);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  status = lstat ("X", &st);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // verify fails on invalid descriptor
+  status = fstat (-1, &st);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EBADF);
+
+  // first, make sure we get an empty file
+  fd = open ("X", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+  // we know that fd 0, 1, and 2 exist already
+  TEST_ASSERT (fd >= 3); 
+
+  // verify new file has zero size
+  status = fstat (fd, &st);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (st.st_size, 0);
+
+  // verify new file has zero size
+  status = stat ("X", &st);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (st.st_size, 0);
+
+  // verify new file has zero size
+  status = lstat ("X", &st);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (st.st_size, 0);
+
+  // delete file
+  status = unlink ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // close
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_exists (void)
+{
+  int fd;
+
+  // open non-existing file. fail
+  fd = open ("X", O_RDONLY);
+  TEST_ASSERT_EQUAL (fd, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // open pathname with invalid directory.
+  fd = open ("X/A", O_RDONLY);
+  TEST_ASSERT_EQUAL (fd, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // open non-existing directory. fail.
+  fd = open ("X", O_DIRECTORY | O_RDONLY);
+  TEST_ASSERT_EQUAL (fd, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+}
+
+static void test_file_remove (void)
+{
+  int status, fd;
+
+  // create file
+  fd = open ("X", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+  TEST_ASSERT_UNEQUAL (fd, -1); 
+
+  // try to delete with remove.
+  status = remove ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+  
+  // finally, close fd
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_create_dir (void)
+{
+  int status, fd;
+
+  // check that directory does not exist.
+  status = open ("X", O_DIRECTORY | O_RDONLY);
+  TEST_ASSERT_EQUAL (status, -1);
+
+  // create directory
+  status = mkdir ("X", S_IRWXU);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // create a second time. fail.
+  status = mkdir ("X", S_IRWXU);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EEXIST);
+
+  // check that directory exists.
+  fd = open ("X", O_DIRECTORY | O_RDONLY);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+
+  // close
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // delete directory as file. fail.
+  status = unlink ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EISDIR);
+
+  // delete directory.
+  status = rmdir ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_remove_dir (void)
+{
+  int status;
+
+  // check that directory does not exist.
+  status = open ("X", O_DIRECTORY | O_RDONLY);
+  TEST_ASSERT_EQUAL (status, -1);
+
+  // delete non-existing with remove
+  status = remove ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // create directory
+  status = mkdir ("X", S_IRWXU);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // delete with remove
+  status = remove ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // delete a second time with remove. fail.
+  status = remove ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // delete a third time with rmdir. fail.
+  status = rmdir ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // create directory
+  status = mkdir ("X", S_IRWXU);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // delete with rmdir
+  status = rmdir ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // delete a second time with rmdir. fail.
+  status = rmdir ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // delete a third time with remove. fail.
+  status = remove ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+}
+
+static void test_subfile (void)
+{
+  int status, fd;
+  // create directory
+  status = mkdir ("X", S_IRWXU);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // create subfile.
+  fd = open ("X/A", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+  TEST_ASSERT_UNEQUAL (status, -1);
+
+  // try to delete non-empty directory. fail.
+  status = rmdir ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOTEMPTY);
+
+  // delete file but don't close it yet
+  status = unlink ("X/A");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // delete empty directory.
+  status = rmdir ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // finally, close subfile
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_read_write (void)
+{
+  int status, fd;
+
+  fd = open ("X", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+
+  status = write (fd, "100", 4);
+  TEST_ASSERT_EQUAL (status, 4);
+
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  fd = open ("X", O_RDONLY);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+
+  char buffer[6];
+  status = read (fd, buffer, 2);
+  TEST_ASSERT_EQUAL (status, 2);
+
+  status = read (fd, &buffer[2], 4);
+  TEST_ASSERT_EQUAL (status, 2);
+
+  status = read (fd, &buffer, 1);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = strcmp ("100", buffer);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = unlink ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_cwd (void)
+{
+  char *cwd = get_current_dir_name ();
+  TEST_ASSERT_UNEQUAL (cwd, 0);
+  int len = strlen (cwd);
+  free (cwd);
+
+  char *buffer = (char*)malloc (len + 1);
+  memset (buffer, 0, len + 1);
+  cwd = getcwd (buffer, len);
+  TEST_ASSERT_EQUAL (cwd, 0);
+  cwd = getcwd (buffer, len+1);
+  TEST_ASSERT_UNEQUAL (cwd, 0);
+  free (buffer);
+
+  char tmp[PATH_MAX+1];
+  cwd = getwd (tmp);
+  TEST_ASSERT_UNEQUAL (cwd, 0);
+}
+
+static void test_chdir (void)
+{
+  int status, fd;
+
+  // verify target directory does not exist
+  status = chdir ("X");
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOENT);
+
+  // create directory
+  status = mkdir ("X", S_IRWXU);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // create subfile.
+  fd = open ("X/A", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+  TEST_ASSERT_UNEQUAL (status, -1);
+
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // go in target directory
+  status = chdir ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // verify we can open file
+  fd = open ("A", O_RDONLY);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // go up
+  status = chdir ("..");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // verify we can open file
+  fd = open ("X/A", O_RDONLY);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // cleanup
+  status = unlink ("X/A");
+  TEST_ASSERT_EQUAL (status, 0);
+  status = rmdir ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+int main (int argc, char *argv[])
+{
+  test_open_exclusive ();
+  test_stat ();
+  test_exists ();
+  test_file_remove ();
+  test_create_dir ();
+  test_remove_dir ();
+  test_subfile ();
+  test_read_write ();
+  test_cwd ();
+  test_chdir ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-macros.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,11 @@
+#include "test-macros.h"
+
+extern "C" void ns3_report_test_error(const char *s);
+
+void ns3_report_test_error(const char *s)
+{
+  std::cerr << s;
+}
+
+Ns3ReportTestError g_ns3_report_test_error = ns3_report_test_error;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-macros.h	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,45 @@
+#ifndef TEST_MACROS_H
+#define TEST_MACROS_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+typedef void (*Ns3ReportTestError) (const char *);
+extern "C" Ns3ReportTestError g_ns3_report_test_error __attribute__((visibility("default")));
+
+#define OUTPUT(x)							\
+  {									\
+    std::ostringstream oss;						\
+    oss << "file=" << __FILE__ << " line=" << __LINE__ << " "		\
+	<< x << std::endl;						\
+    std::string s = oss.str ();						\
+    g_ns3_report_test_error (s.c_str());				\
+  }
+  
+
+#define TEST_ASSERT_EQUAL(a,b)			\
+  if ((a) != (b))				\
+    {						\
+      OUTPUT("assert failed " << "\"" << (a) << "\" == \"" << (b) << "\""); \
+      exit (1);					\
+    }
+
+#define TEST_ASSERT_UNEQUAL(a,b)		\
+  if ((a) == (b))				\
+    {						\
+      OUTPUT("assert failed " << "\"" << (a) << "\" != \"" << (b) << "\""); \
+      exit (1);					\
+    }
+
+#define TEST_ASSERT(v)				\
+  if (!(v))					\
+    {						\
+      OUTPUT("assert failed " << "(" << (v) << ")"); \
+      exit (1);					\
+    }
+
+
+#endif /* TEST_MACROS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-malloc-2.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+  void *a = malloc (32000);
+  void *b = malloc (2000);
+  free (a);
+  free (b);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-malloc.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,32 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <list>
+
+int main (int argc, char *argv[])
+{
+  int sizes[] = {0, 1, 2, 3, 4, 8, 10, 16, 19, 30, 64, 120, 240, 1020, 4098, 10000, 100000, 1000000};
+  for (uint32_t i = 0; i < sizeof (sizes)/sizeof (int); i++)
+    {
+      int size = sizes[i];
+      void *ptr = malloc (size);
+      memset (ptr, 0x66, size);
+      free (ptr);
+    }
+  std::list<void*> ptrs;
+  for (uint32_t i = 0; i < sizeof (sizes)/sizeof (int); i++)
+    {
+      int size = sizes[i];
+      void *ptr = malloc (size);
+      memset (ptr, 0x66, size);
+      ptrs.push_back (ptr);
+    }
+  for (uint32_t i = 0; i < sizeof (sizes)/sizeof (int); i++)
+    {
+      free (ptrs.front ());
+      ptrs.pop_front ();
+    }
+  ptrs.clear ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-mutex.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,186 @@
+#include <pthread.h>
+#include "test-macros.h"
+#include <stdint.h>
+#include <errno.h>
+
+struct SharedData
+{
+  uint32_t count;
+  pthread_mutex_t mutex;
+};
+
+
+static void *thread_fn (void *ctx)
+{
+  struct SharedData *data = (struct SharedData *)ctx;
+  int status;
+  do {
+    status = sleep (2);
+    TEST_ASSERT_EQUAL (status, 0);
+    status = pthread_mutex_lock (&data->mutex);
+    TEST_ASSERT_EQUAL (status, 0);
+    data->count++;
+    uint32_t a = data->count;
+    status = sleep (2);
+    TEST_ASSERT_EQUAL (status, 0);
+    TEST_ASSERT_EQUAL (data->count, a);
+    status = pthread_mutex_unlock (&data->mutex);
+    TEST_ASSERT_EQUAL (status, 0);
+  } while (data->count < 1000);
+
+  return 0;
+}
+
+
+int main (int argc, char *argv[])
+{
+  int status;
+  pthread_mutex_t mutex;
+
+  // check basic initialization/destruction
+  status = pthread_mutex_init (&mutex, NULL);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_destroy (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_destroy (&mutex);
+  TEST_ASSERT_EQUAL (status, EINVAL);
+
+  // check basic lock error checking
+  // for normal mutexes.
+  pthread_mutexattr_t attr;
+  status = pthread_mutexattr_init (&attr);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_init (&mutex, &attr);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutexattr_destroy (&attr);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, EPERM);
+  status = pthread_mutex_lock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_lock (&mutex);
+  TEST_ASSERT_EQUAL (status, EDEADLK);
+  status = pthread_mutex_trylock (&mutex);
+  TEST_ASSERT_EQUAL (status, EBUSY);
+  status = pthread_mutex_destroy (&mutex);
+  TEST_ASSERT_EQUAL (status, EBUSY);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, EPERM);
+  status = pthread_mutex_destroy (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // check basic lock error checking
+  // for recursive mutexes.
+  status = pthread_mutexattr_init (&attr);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_init (&mutex, &attr);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutexattr_destroy (&attr);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, EPERM);
+  status = pthread_mutex_lock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_trylock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_lock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_destroy (&mutex);
+  TEST_ASSERT_EQUAL (status, EBUSY);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&mutex);
+  TEST_ASSERT_EQUAL (status, EPERM);
+  status = pthread_mutex_destroy (&mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  struct SharedData data;
+  data.count = 0;
+  status = pthread_mutex_init (&data.mutex, NULL);
+  TEST_ASSERT_EQUAL (status, 0);
+  pthread_t thread;
+  status = pthread_create (&thread, NULL,
+				&thread_fn,
+				(void*)&data);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  do {
+    status = sleep (5);
+    TEST_ASSERT_EQUAL (status, 0);
+    status = pthread_mutex_lock (&data.mutex);
+    TEST_ASSERT_EQUAL (status, 0);
+    data.count++;
+    uint32_t a = data.count;
+    TEST_ASSERT_EQUAL (status, 0);
+    TEST_ASSERT_EQUAL (data.count, a);
+    status = sleep (10);
+    TEST_ASSERT_EQUAL (status, 0);
+    TEST_ASSERT_EQUAL (data.count, a);
+    status = pthread_mutex_unlock (&data.mutex);
+    TEST_ASSERT_EQUAL (status, 0);
+    status = sleep (5);
+    TEST_ASSERT_EQUAL (status, 0);
+  } while (data.count < 1000);
+
+  status = pthread_join (thread, NULL);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = pthread_mutex_destroy (&data.mutex);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER;
+  status = pthread_mutex_destroy (&a);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  pthread_mutex_t b = PTHREAD_MUTEX_INITIALIZER;
+  status = pthread_mutex_lock (&b);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_lock (&b);
+  TEST_ASSERT_EQUAL (status, EDEADLOCK);
+  status = pthread_mutex_unlock (&b);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_destroy (&b);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  pthread_mutex_t c = PTHREAD_MUTEX_INITIALIZER;
+  status = pthread_mutex_trylock (&c);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_trylock (&c);
+  TEST_ASSERT_EQUAL (status, EBUSY);
+  status = pthread_mutex_unlock (&c);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_destroy (&c);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  pthread_mutex_t d = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+  status = pthread_mutex_trylock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_trylock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_lock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_lock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_unlock (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_mutex_destroy (&d);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-nanosleep.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,58 @@
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include "test-macros.h"
+#include <sys/time.h>
+#include <signal.h>
+
+
+void sigresp (int) {return;}
+
+int main (int argc, char *argv[])
+{
+  // Simple nanolseep() without interruption
+  {
+  timespec req = {1, 5000};
+  timespec rem;
+
+  timeval start;
+  timeval end;
+
+  gettimeofday (&start, NULL);
+  int result = nanosleep (&req, &rem);
+  gettimeofday (&end, NULL);
+
+  TEST_ASSERT_EQUAL (result, 0);
+  TEST_ASSERT_EQUAL (end.tv_sec-start.tv_sec, 1);
+  TEST_ASSERT_EQUAL (end.tv_usec-start.tv_usec, 5);
+  }
+
+  // Test with nanosleep() interrupted by SIGALRM fired by itimer
+  {
+  signal (SIGALRM, sigresp);
+  struct itimerval it;
+  memset (&it, 0, sizeof (it));
+  it.it_value.tv_sec = 1;
+  it.it_value.tv_usec = 5;
+
+  timespec req = {3, 0};
+  timespec rem;
+  timeval end;
+  timeval start;
+
+  gettimeofday (&start, NULL);
+  setitimer (ITIMER_REAL, &it, NULL);
+  int result = nanosleep (&req, &rem);
+  gettimeofday (&end, NULL);
+
+  TEST_ASSERT_EQUAL (result, -1);
+  TEST_ASSERT_EQUAL (end.tv_sec-start.tv_sec, 1);
+  TEST_ASSERT_EQUAL (end.tv_usec-start.tv_usec, 5);
+  TEST_ASSERT_EQUAL (rem.tv_sec, 1);
+  TEST_ASSERT (rem.tv_nsec >= 500000000);
+  }
+
+  exit (0);
+  // never reached.
+  return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-netdb.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,40 @@
+#define _GNU_SOURCE 1
+#include <netdb.h>
+#include "test-macros.h"
+
+void test_gethostbyname (void)
+{
+  struct hostent *host;
+  host = gethostbyname("127.0.0.1");
+  TEST_ASSERT_UNEQUAL (host, 0);
+  TEST_ASSERT_EQUAL (host->h_addrtype, AF_INET);
+}
+
+void test_gethostbyname2 (void)
+{
+  struct hostent *host;
+  host = gethostbyname2 ("127.0.0.1", AF_INET);
+  TEST_ASSERT_UNEQUAL (host, 0);
+  TEST_ASSERT_EQUAL (host->h_addrtype, AF_INET);
+}
+
+void test_getaddrinfo (void)
+{
+  struct addrinfo *info;
+  int status = getaddrinfo ("127.0.0.1", "http", 0, &info);
+  TEST_ASSERT_EQUAL (status, 0);
+  freeaddrinfo (info);
+  status = getaddrinfo ("127.0.0.1", "htt", 0, &info);
+  TEST_ASSERT_UNEQUAL (status, 0);
+  TEST_ASSERT_EQUAL (status, EAI_SERVICE);
+  TEST_ASSERT (gai_strerror (status) != 0);
+}
+
+
+int main (int argc, char *argv[])
+{
+  test_gethostbyname ();
+  test_gethostbyname2 ();
+  test_getaddrinfo ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-once.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,28 @@
+#include <pthread.h>
+#include "test-macros.h"
+
+static int g_once = 0;
+
+static void once_fn (void)
+{
+  g_once++;
+}
+int main (int argc, char *argv[])
+{
+  /* This is a really very simple check. The conformance of
+     the pthread_once function relies on the caller's unicity
+     of the once variable which, in our codebase, is ensured with
+     the ElfLoader and that is tested for elsewhere (most notably
+     in test-elf-loader.cc)
+   */
+  pthread_once_t once = PTHREAD_ONCE_INIT;
+  TEST_ASSERT_EQUAL (g_once, 0);
+  int status = pthread_once (&once, &once_fn);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (g_once, 1);
+  status = pthread_once (&once, &once_fn);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (g_once, 1);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-pthread-key.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,59 @@
+#include <pthread.h>
+#include <errno.h>
+#include "test-macros.h"
+
+static pthread_key_t a;
+
+static void *thread_fn (void *v)
+{
+  void *tmp = pthread_getspecific (a);
+  TEST_ASSERT_EQUAL (tmp, 0);
+  int *av = (int *)malloc (4);
+  int status = pthread_setspecific (a, av);
+  TEST_ASSERT_EQUAL (status, 0);
+  tmp = pthread_getspecific (a);
+  TEST_ASSERT_EQUAL (tmp, av);
+  return v;
+}
+static void destructor (void* value)
+{
+  void *new_value = pthread_getspecific (a);
+  TEST_ASSERT_EQUAL (new_value, 0);
+  free (value);
+}
+
+int main (int argc, char *argv[])
+{
+  pthread_key_t b;
+  int status = pthread_key_create (&b, NULL);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_key_delete (b);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_key_delete (b);
+  TEST_ASSERT_EQUAL (status, EINVAL);
+
+  status = pthread_key_create (&a, &destructor);
+  TEST_ASSERT_EQUAL (status, 0);
+  void *tmp = pthread_getspecific (a);
+  TEST_ASSERT_EQUAL (tmp, 0);
+  int *av = (int*)malloc (4);
+  status = pthread_setspecific (a, av);
+  TEST_ASSERT_EQUAL (status, 0);
+  tmp = pthread_getspecific (a);
+  TEST_ASSERT_EQUAL (tmp, av);
+  pthread_t thread;
+  status = pthread_create (&thread, NULL, 
+			   &thread_fn,
+			   (void*)-5);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_setspecific (a, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  free (av);
+
+  void *retval;
+  status = pthread_join (thread, &retval);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (retval, (void*)-5);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-pthread.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,174 @@
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include "test-macros.h"
+
+static void *
+thread0 (void *arg)
+{
+  pthread_exit (arg);
+  // never reached.
+  TEST_ASSERT (false);
+  return arg;
+}
+static void *
+thread1 (void *arg)
+{
+  sleep (10);
+  pthread_exit (arg);
+  // never reached.
+  TEST_ASSERT (false);
+  return arg;
+}
+static void *
+thread2 (void *arg)
+{
+  int status = pthread_detach (pthread_self ());
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sleep (30);
+  TEST_ASSERT_EQUAL (status, 0);
+  pthread_exit (arg);
+  // never reached.
+  TEST_ASSERT (false);
+  return arg;
+}
+static void *
+thread3 (void *arg)
+{
+  int status = pthread_detach (pthread_self ());
+  TEST_ASSERT_EQUAL (status, 0);
+  // the result of this test is unspecified by the posix spec but
+  // we have specified that multiple calls to pthread_detach are not
+  // harmful.
+  status = pthread_detach (pthread_self ());
+  TEST_ASSERT_EQUAL (status, EINVAL);
+  pthread_exit (arg);
+  // never reached.
+  TEST_ASSERT (false);
+  return arg;
+}
+static void *
+thread4 (void *arg)
+{
+  sleep(1);
+  // thread is joined from main thread already
+  int status = pthread_detach (pthread_self ());
+  TEST_ASSERT_EQUAL (status, 0);
+  pthread_exit (arg);
+  // never reached.
+  TEST_ASSERT (false);
+  return arg;
+}
+static void *
+thread5 (void *arg)
+{
+  sleep (1);
+  // the target thread is already joined by the main thread.
+  pthread_t *thread = (pthread_t *)arg;
+  void *return_value;
+  int status = pthread_join (*thread, &return_value);
+  TEST_ASSERT_EQUAL (status, EINVAL);
+  pthread_exit (arg);
+  // never reached.
+  TEST_ASSERT (false);
+  return arg;
+}
+static void *
+thread6 (void *arg)
+{
+  sleep (2);
+  pthread_exit (arg);
+  // never reached.
+  TEST_ASSERT (false);
+  return arg;
+}
+
+
+int main (int argc, char *argv[])
+{
+  int status;
+  pthread_t thread;
+
+  // try to join after the thread exits.
+  status = pthread_create (&thread, NULL, 
+			   &thread0,
+			   (void*)-3);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sleep (20);
+  TEST_ASSERT_EQUAL (status, 0);
+  void *return_value;
+  status = pthread_join (thread, &return_value);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (return_value, (void*)-3);
+
+
+  // try to join before the thread exits.  
+  status = pthread_create (&thread, NULL, 
+			   &thread1,
+			   (void*)-4);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_join (thread, &return_value);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (return_value, (void*)-4);
+
+  // ensure that we cannot join ourselves.
+  status = pthread_join (pthread_self (), &return_value);
+  TEST_ASSERT_EQUAL (status, EDEADLK);
+
+  // try to join a thread in detached state.
+  status = pthread_create (&thread, NULL, 
+			   &thread2,
+			   (void*)-5);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sleep (20);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_join (thread, &return_value);
+  TEST_ASSERT_UNEQUAL (status, 0);
+  TEST_ASSERT_EQUAL (status, EINVAL);
+  status = sleep(11); // make sure thread2 is dead.
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // try to join a thread in detached state which is dead.
+  status = pthread_create (&thread, NULL, 
+			   &thread3,
+			   (void*)-6);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sleep (20);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_join (thread, NULL);
+  TEST_ASSERT_UNEQUAL (status, 0);
+  // in the libc implementation, the check for a valid
+  // thread descriptor does not always work correctly.
+  // The only case in which it works correctly is when the
+  // thread has been joined and the associated thread descriptor
+  // has not been yet reused for another newly created thread.
+  // So, theoretically, ESRCH is the correct return value here
+  // but EINVAL is what we get on nptl
+  TEST_ASSERT (status == ESRCH 
+	       || status == EINVAL);
+
+  // try to detach a thread which is joined.
+  status = pthread_create (&thread, NULL, 
+			   &thread4,
+			   (void*)-7);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_join (thread, &return_value);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (return_value, (void*)-7);
+
+  // try to join the same thread twice
+  status = pthread_create (&thread, NULL, 
+			   &thread5,
+			   (void*)&thread);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_create (&thread, NULL, 
+			   &thread6,
+			   (void*)-82);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_join (thread, &return_value);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (return_value, (void*)-82);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-random.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include "test-macros.h"
+
+int main (int argc, char *argv[])
+{
+  srand (0);
+  int a = random ();
+  int b = rand ();
+
+  TEST_ASSERT_UNEQUAL (a, 0);
+  TEST_ASSERT_UNEQUAL (a, b);
+
+  exit (0);
+  // never reached.
+  return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-select.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,42 @@
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include "test-macros.h"
+
+// test, that select () with timeout={0,0} exits immediately
+static void test_select_null_null (void)
+{
+  // create timer to check whether a following call to select() blocks
+  int timerfd = timerfd_create (CLOCK_MONOTONIC, 0);
+  TEST_ASSERT_UNEQUAL (timerfd, -1);
+
+  // arm timer to fire in 5 seconds
+  struct itimerspec new_value;
+  new_value.it_value.tv_sec = 5;
+  new_value.it_value.tv_nsec = 0;
+  new_value.it_interval.tv_sec = 0;
+  new_value.it_interval.tv_nsec = 0;
+  int status = timerfd_settime (timerfd, 0, &new_value, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // prepare fd_set to select() on it
+  fd_set fds;
+  FD_ZERO (&fds);
+  FD_SET (timerfd, &fds);
+
+  // doing select() with timeout = {0, 0}
+  struct timeval timeout = {0, 0};
+  int nfds = select (timerfd + 1, &fds, NULL, NULL, &timeout);
+  close (timerfd);
+  // no fds must be ready and select() should complete without errors
+  TEST_ASSERT_EQUAL (nfds, 0);
+}
+
+int main (int argc, char *argv[])
+{
+  test_select_null_null();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-sem.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,97 @@
+#include <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#include "test-macros.h"
+
+void *thread_a (void *ctx)
+{
+  sem_t *sems = (sem_t *)ctx;
+  for (int i = 0; i < 100; i++)
+    {
+      int status = sem_post (&sems[0]);
+      TEST_ASSERT_EQUAL (status, 0);
+      status = sem_wait (&sems[1]);
+      TEST_ASSERT_EQUAL (status, 0);
+    }
+  return 0;
+}
+
+void *thread_b (void *ctx)
+{
+  sem_t *sems = (sem_t *)ctx;
+  for (int i = 0; i < 100; i++)
+    {
+      int status = sem_wait (&sems[0]);
+      TEST_ASSERT_EQUAL (status, 0);
+      status = sem_post (&sems[1]);
+      TEST_ASSERT_EQUAL (status, 0);
+    }
+  return 0;
+}
+
+int main (int argc, char *argv[])
+{
+  // basic tests
+  sem_t sem;
+  struct timespec tm;
+  int status = sem_init (&sem, 0, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_destroy (&sem);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_destroy (&sem);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EINVAL);
+  status = sem_init (&sem, 1, 0);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOSYS);
+  status = sem_init (&sem, 0, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_post (&sem);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_wait (&sem);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_post (&sem);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_trywait (&sem);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_post (&sem);
+  TEST_ASSERT_EQUAL (status, 0);
+  tm.tv_sec = 1;
+  tm.tv_nsec = 0;
+  status = sem_timedwait (&sem, &tm);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_trywait (&sem);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EAGAIN);
+  tm.tv_sec = 0;
+  tm.tv_nsec = 0;
+  status = sem_timedwait (&sem, &tm);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ETIMEDOUT);
+  status = sem_destroy (&sem);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // perform ping pong between two threads.
+  sem_t sems[2];
+  pthread_t threads[2];
+  status = sem_init (&sems[0], 0, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_init (&sems[1], 0, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_create (&threads[0], 0, 
+			   &thread_a, sems);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_create (&threads[1], 0, 
+			   &thread_b, sems);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_join (threads[0], 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = pthread_join (threads[1], 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_destroy (&sems[0]);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = sem_destroy (&sems[1]);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-sleep.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include "test-macros.h"
+
+int main (int argc, char *argv[])
+{
+  time_t start = time (0);
+  unsigned int left = sleep (1);
+  time_t end = time (0);
+  TEST_ASSERT_EQUAL (left, 0);
+  TEST_ASSERT_EQUAL (end-start, 1);
+  exit (0);
+  // never reached.
+  return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-stdio.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,306 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include "test-macros.h"
+
+static void test_fopen (void)
+{
+  int status;
+  status = unlink ("X");
+
+  FILE *file;
+  file = fopen ("X", "f");
+  TEST_ASSERT_EQUAL (file, 0);
+  TEST_ASSERT_EQUAL (errno, EINVAL);
+  file = fopen ("X", "r");
+  TEST_ASSERT_EQUAL (file, 0);
+  file = fopen ("X", "r+");
+  TEST_ASSERT_EQUAL (file, 0);
+
+  file = fopen ("X", "w");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  file = fopen ("X", "r");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  file = fopen ("X", "r+");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  file = fopen ("X", "w");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = unlink ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+
+  file = fopen ("X", "w+");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  file = fopen ("X", "w+");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = unlink ("X");
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_freadwrite (void)
+{
+  char buffer[] = {
+    0xff, 0xfe, 0xfd, 0x00, 
+    0x02, 0x05, 0x12, 0x15
+  };
+  int status;
+  status = unlink ("X");
+
+  FILE *file;
+  file = fopen ("X", "w");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  
+  size_t items;
+  items = fwrite (buffer, sizeof(buffer), 1, file);
+  TEST_ASSERT_EQUAL (items, 1);
+  items = fwrite (buffer, 1, sizeof(buffer), file);
+  TEST_ASSERT_EQUAL (items, sizeof(buffer));
+
+  items = fread (buffer, 1, 1, file);
+  TEST_ASSERT_EQUAL (items, 0);
+  TEST_ASSERT_UNEQUAL (ferror (file), 0);
+  clearerr (file);
+  TEST_ASSERT_EQUAL (ferror (file), 0);
+
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // Now, try to open a new file
+  file = fopen ("X", "r");
+  TEST_ASSERT_UNEQUAL (file, 0);
+
+  char read_buffer[sizeof(buffer)];
+  items = fread (read_buffer, 1, sizeof(read_buffer), file);
+  TEST_ASSERT_EQUAL (items, sizeof(read_buffer));
+  items = fread (read_buffer, sizeof(read_buffer), 1, file);
+  TEST_ASSERT_EQUAL (items, 1);
+
+  items = fread (read_buffer, sizeof(read_buffer), 1, file);
+  TEST_ASSERT_EQUAL (items, 0);
+  TEST_ASSERT_UNEQUAL (feof (file), 0);
+  TEST_ASSERT_EQUAL (ferror (file), 0);
+  clearerr (file);
+  TEST_ASSERT_EQUAL (feof (file), 0);
+  TEST_ASSERT_EQUAL (ferror (file), 0);
+
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void
+test_freopen (void)
+{
+  int status;
+  // cleanup
+  unlink ("X");
+
+  char c = 0x66;
+  FILE *wo = fopen ("X", "w");
+  TEST_ASSERT_UNEQUAL (wo, 0);
+  status = fwrite (&c, 1, 1, wo);
+  TEST_ASSERT_EQUAL (status, 1);
+  status = fread (&c, 1, 1, wo);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (feof (wo), 0);
+  TEST_ASSERT_UNEQUAL (ferror (wo), 0);
+
+  FILE *ro = freopen ("X", "r", wo);
+  TEST_ASSERT_EQUAL (wo, ro);
+  status = fread (&c, 1, 1, ro);
+  TEST_ASSERT_EQUAL (status, 1);
+
+  fclose (ro);
+}
+
+void test_fcloseall (void)
+{
+  int status = fcloseall ();
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+void test_fileno (void)
+{
+  int fd = fileno (stdout);
+  TEST_ASSERT_EQUAL (fd, 1);
+  fd = fileno (stderr);
+  TEST_ASSERT_EQUAL (fd, 2);
+  fd = fileno (stdin);
+  TEST_ASSERT_EQUAL (fd, 0);
+}
+void test_seek (void)
+{
+  // cleanup
+  unlink ("X");
+  // let's write a file
+  char buffer[] = {
+    0xff, 0xfe, 0xfd, 0x00, 
+    0x02, 0x05, 0x12, 0x15
+  };
+  FILE *file;
+  file = fopen ("X", "w+");
+  TEST_ASSERT_UNEQUAL (file, 0);
+  
+  size_t items;
+  items = fwrite (buffer, sizeof(buffer), 1, file);
+  TEST_ASSERT_EQUAL (items, 1);
+  items = fwrite (buffer, 1, sizeof(buffer), file);
+  TEST_ASSERT_EQUAL (items, sizeof(buffer));
+  int status = fflush (file);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = fclose (file);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  // now, let's read data.
+  FILE *ro = fopen ("X", "r");
+  TEST_ASSERT_UNEQUAL (ro, 0);
+  long current = ftell (ro);
+  TEST_ASSERT_EQUAL (current, 0);
+  status = fseek (ro, 0, SEEK_SET);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = fseek (ro, 0, SEEK_END);
+  TEST_ASSERT_EQUAL (status, 0);
+  current = ftell (ro);
+  TEST_ASSERT_EQUAL (current, sizeof(buffer)*2);
+  status = fseek (ro, -5, SEEK_END);
+  TEST_ASSERT_EQUAL (status, 0);
+  current = ftell (ro);
+  TEST_ASSERT_EQUAL (current, sizeof(buffer)*2-5);
+  status = fseek (ro, +3, SEEK_CUR);
+  TEST_ASSERT_EQUAL (status, 0);
+  current = ftell (ro);
+  TEST_ASSERT_EQUAL (current, sizeof(buffer)*2-5+3);
+  rewind (ro);
+  current = ftell (ro);
+  TEST_ASSERT_EQUAL (current, 0);
+
+  fpos_t pos;
+  status = fgetpos (ro, &pos);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = fseek (ro, +3, SEEK_CUR);
+  TEST_ASSERT_EQUAL (status, 0);
+  current = ftell (ro);
+  TEST_ASSERT_EQUAL (current, 3);
+  status = fsetpos (ro, &pos);
+  TEST_ASSERT_EQUAL (status, 0);
+  current = ftell (ro);
+  TEST_ASSERT_EQUAL (current, 0);
+
+
+  status = fclose (ro);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+void test_buf (void)
+{
+  // cleanup
+  unlink ("X");
+
+  FILE *f = fopen ("X", "w");
+  char buffer[BUFSIZ];
+  // enable buffered output
+  setbuf (f, buffer);
+  // disable buffering.
+  setbuf (f, 0);
+
+  // enable buffered output
+  setbuffer (f, buffer, BUFSIZ);
+  // disable buffering.
+  setbuffer (f, 0, 0);
+
+  // enable line buffering
+  setlinebuf (f);
+
+  int status = setvbuf (f, buffer, _IOFBF, BUFSIZ);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = setvbuf (f, 0, _IONBF, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  status = setvbuf (f, buffer, _IOLBF, BUFSIZ);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  fclose (f);
+}
+
+void test_formatted_io (void)
+{
+  // cleanup
+  unlink ("X");
+
+  FILE *f = fopen ("X", "w+");
+
+  int status = fputs ("test\n", f);
+  TEST_ASSERT_UNEQUAL (status, EOF);
+  long pos = ftell (f);
+  TEST_ASSERT_EQUAL (pos, 5);
+  status = fputc ('a', f);
+  TEST_ASSERT_UNEQUAL (status, EOF);
+  pos = ftell (f);
+  TEST_ASSERT_EQUAL (pos, 6);
+  status = putc ('a', f);
+  TEST_ASSERT_UNEQUAL (status, EOF);
+  pos = ftell (f);
+  TEST_ASSERT_EQUAL (pos, 7);
+
+  status = fseek (f, -2, SEEK_END);
+  TEST_ASSERT_EQUAL (status, 0);
+  pos = ftell (f);
+  TEST_ASSERT_EQUAL (pos, 5);
+
+  status = fgetc (f);
+  TEST_ASSERT_EQUAL (status, 'a');
+  status = ungetc ('b', f);
+  TEST_ASSERT_EQUAL (status, 'b');
+  status = fgetc (f);
+  TEST_ASSERT_EQUAL (status, 'b');
+  status = getc (f);
+  TEST_ASSERT_EQUAL (status, 'a');
+
+  status = fseek (f, 0, SEEK_SET);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  char buffer[100];
+
+  char *retval = fgets (buffer, 100, f);
+  TEST_ASSERT_UNEQUAL (retval, 0);
+  TEST_ASSERT (strcmp ("test\n", retval) == 0);
+  
+
+  fclose (f);
+
+  status = putchar ('a');
+  TEST_ASSERT_UNEQUAL (status, EOF);
+  status = puts ("test");
+  TEST_ASSERT_UNEQUAL (status, EOF);
+  // getchar
+  // gets
+}
+
+int main (int argc, char *argv[])
+{
+  test_fopen ();
+  test_freadwrite ();
+  test_freopen ();
+  test_fileno ();
+  test_seek ();
+  test_buf ();
+  test_formatted_io ();
+
+  // Should be last because it closes all open streams, including stdout et al.
+  test_fcloseall ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-stdlib.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+#include <errno.h>
+#include "test-macros.h"
+
+static void test_strtod (void)
+{
+  double retval;
+  retval = strtod("55", NULL);
+  TEST_ASSERT_EQUAL (retval, 55);
+  retval = strtod("-127", NULL);
+  TEST_ASSERT_EQUAL (retval, -127);
+  retval = strtod ("122.233", NULL);
+  TEST_ASSERT_EQUAL (retval, 122.233);
+  retval = strtod ("0x122.3", NULL);
+  TEST_ASSERT_EQUAL (retval, 290.1875);
+  retval = strtod ("2e3", NULL);
+  TEST_ASSERT_EQUAL (retval, 2000);
+}
+
+int main (int argc, char *argv[])
+{
+  test_strtod();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-strerror.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,16 @@
+#include <string.h>
+#include <errno.h>
+#include "test-macros.h"
+
+int main (int argc, char *argv[])
+{
+  char buffer[100];
+  char *s = strerror (EINVAL);
+  TEST_ASSERT_UNEQUAL (s, 0);
+  s = strerror_r (EINVAL, buffer, 100);
+  TEST_ASSERT_UNEQUAL (s, 0);
+  s = strerror_r (EINVAL, buffer, 0);
+  TEST_ASSERT_UNEQUAL (s, 0);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-string.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,19 @@
+#include <string.h>
+#include <stdlib.h>
+#include "test-macros.h"
+
+void test_strdup (void)
+{
+  const char *s = "test";
+  char *copy = strdup (s);
+  free (copy);
+  copy = strndup (s, 2);
+  TEST_ASSERT (strcmp (copy, "te") == 0);
+  free (copy);
+}
+
+int main (int argc, char *argv[])
+{
+  test_strdup ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test-timer-fd.cc	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,143 @@
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include "test-macros.h"
+
+static void test_file (void)
+{
+  int fd = open ("X", O_CREAT | O_TRUNC | O_WRONLY);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+
+  struct itimerspec cur_value;
+  int status = timerfd_gettime (fd, &cur_value);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EINVAL);
+  
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_timerfd (void)
+{
+  int fd = timerfd_create (CLOCK_MONOTONIC, 0);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+
+  uint64_t buf;
+  ssize_t bytes_read = read (fd, &buf, 7);
+  TEST_ASSERT_EQUAL (bytes_read, -1);
+  TEST_ASSERT_EQUAL (errno, EINVAL);
+
+  struct itimerspec cur_value;
+  int status = timerfd_gettime (fd, &cur_value);
+  TEST_ASSERT_EQUAL (status, 0);
+  TEST_ASSERT_EQUAL (cur_value.it_value.tv_sec, 0);
+  TEST_ASSERT_EQUAL (cur_value.it_value.tv_nsec, 0);
+  TEST_ASSERT_EQUAL (cur_value.it_interval.tv_sec, 0);
+  TEST_ASSERT_EQUAL (cur_value.it_interval.tv_nsec, 0);
+
+  int flags = fcntl (fd, F_GETFL);
+  TEST_ASSERT_UNEQUAL (flags, -1);
+  flags |= O_NONBLOCK;
+  status = fcntl (fd, F_SETFL, flags);
+  TEST_ASSERT_EQUAL (status, 0);
+  bytes_read = read (fd, &buf, 8);
+  TEST_ASSERT_EQUAL (bytes_read, -1);
+  TEST_ASSERT_EQUAL (errno, EAGAIN);
+  flags &= ~O_NONBLOCK;
+  status = fcntl (fd, F_SETFL, flags);
+  TEST_ASSERT_EQUAL (status, 0);
+  
+  struct itimerspec new_value;
+  new_value.it_value.tv_sec = 1;
+  new_value.it_value.tv_nsec = 500000000;
+  new_value.it_interval.tv_sec = 2;
+  new_value.it_interval.tv_nsec = 500000000;
+  status = timerfd_settime (fd, 0, &new_value, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+  
+  status = timerfd_gettime (fd, &cur_value);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  for (int i = 0; i < 1; i++)
+    {
+      uint64_t buf;
+      bytes_read = read (fd, &buf, 8);
+      TEST_ASSERT_EQUAL (bytes_read, 8);
+      TEST_ASSERT_EQUAL (buf, 1);
+    }
+
+  sleep (6);
+  bytes_read = read (fd, &buf, 8);
+  TEST_ASSERT_EQUAL (bytes_read, 8);
+  TEST_ASSERT_EQUAL (buf, 2);
+
+  int copy = dup (fd);
+
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = close (copy);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+static void test_otherops (void)
+{
+  int fd = timerfd_create (CLOCK_MONOTONIC, 0);
+  TEST_ASSERT_UNEQUAL (fd, -1);
+  
+  struct itimerspec new_value;
+  new_value.it_value.tv_sec = 1;
+  new_value.it_value.tv_nsec = 500000000;
+  new_value.it_interval.tv_sec = 2;
+  new_value.it_interval.tv_nsec = 500000000;
+  int status = timerfd_settime (fd, 0, &new_value, 0);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  uint64_t buf;
+  status = recv (fd, &buf, 8, 0);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOTSOCK);
+  status = send (fd, &buf, 8, 0);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ENOTSOCK);
+
+  void *p = mmap ((void*)0, 4096, 0, 0, fd, 0);
+  TEST_ASSERT_EQUAL (p, MAP_FAILED);
+  TEST_ASSERT_EQUAL (errno, EINVAL);
+
+  status = lseek (fd, 1, SEEK_CUR);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, ESPIPE);
+
+  status = write (fd, &buf, 8);
+  TEST_ASSERT_EQUAL (status, -1);
+  TEST_ASSERT_EQUAL (errno, EINVAL);
+
+  // Why this is so is beyond me but it's legal to call
+  // fstat on a timer fd.
+  struct stat stbuf;
+  status = fstat (fd, &stbuf);
+  TEST_ASSERT_EQUAL (status, 0);
+
+  status = close (fd);
+  TEST_ASSERT_EQUAL (status, 0);
+}
+
+
+
+
+int main (int argc, char *argv[])
+{
+  test_timerfd ();
+  test_otherops ();
+  test_file ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/wscript	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,36 @@
+def new_test(bld,name,libs):
+    obj = bld.create_simu_program(name)
+    obj.source = [name + '.cc']
+    obj.uselib = libs
+    obj.uselib_local = 'test'
+    
+
+def build(bld):
+    test = bld.new_task_gen('cc', 'shlib')
+    test.name = 'test'
+    test.target = test.name
+    test.env.append_value('CXXFLAGS', test.env['shlib_CXXFLAGS'])
+    test.env.append_value('CXXFLAGS', '-g')
+    test.source = ['test-macros.cc']
+
+    new_test(bld, 'test-empty', '')
+    new_test(bld, 'test-sleep', '')
+    new_test(bld, 'test-nanosleep', '')
+    new_test(bld, 'test-pthread', 'PTHREAD')
+    new_test(bld, 'test-mutex', 'PTHREAD')
+    new_test(bld, 'test-once', 'PTHREAD')
+    new_test(bld, 'test-pthread-key', 'PTHREAD')
+    new_test(bld, 'test-sem', 'PTHREAD')
+    new_test(bld, 'test-malloc', '')
+    new_test(bld, 'test-malloc-2', '')
+    new_test(bld, 'test-fd-simple', '')
+    new_test(bld, 'test-strerror', '')
+    new_test(bld, 'test-stdio', '')
+    new_test(bld, 'test-string', '')
+    new_test(bld, 'test-netdb', '')
+    new_test(bld, 'test-env', '')
+    new_test(bld, 'test-cond', 'PTHREAD')
+    new_test(bld, 'test-timer-fd', '')
+    new_test(bld, 'test-stdlib', '')
+    new_test(bld, 'test-select', '')
+    new_test(bld, 'test-random', '')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wscript	Tue Sep 14 12:41:32 2010 +0200
@@ -0,0 +1,22 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+import os
+
+def add_build_dir(conf,d):
+    build_dir = os.path.abspath(os.path.join(conf.blddir, conf.env.variant(), 'src', 'dce', d))
+    conf.env.append_value('NS3_MODULE_PATH', build_dir)
+
+
+def set_options(opt):
+    opt.sub_options('model')
+
+def configure(conf):
+    add_build_dir(conf, 'model')
+    add_build_dir(conf, 'vdl')
+    add_build_dir(conf, 'test')
+    add_build_dir(conf, 'example')
+    conf.sub_config('model')
+    conf.sub_config('vdl')
+
+def build(bld):
+    bld.add_subdirs(['model', 'helper', 'test', 'vdl', 'example'])