--- /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 ¤t->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, §ion, 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 (¤t->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 (¤t->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 (¤t->pendingSignals, i->signal);
+ }
+ if (sigismember (¤t->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 (¤t->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'])