--- a/.hgtags Mon Jul 30 14:48:56 2007 +0100
+++ b/.hgtags Wed Sep 05 18:35:39 2007 +0100
@@ -3,3 +3,4 @@
0dc81e76166c56aaae64da48b673b62155943aad packet-history-working
38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4
+08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5
--- a/AUTHORS Mon Jul 30 14:48:56 2007 +0100
+++ b/AUTHORS Wed Sep 05 18:35:39 2007 +0100
@@ -3,4 +3,5 @@
Craig Dowell (craigdo@ee.washington.edu)
Tom Henderson (tomhend@u.washington.edu)
Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
+Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
George F. Riley (riley@ece.gatech.edu)
--- a/RELEASE_NOTES Mon Jul 30 14:48:56 2007 +0100
+++ b/RELEASE_NOTES Wed Sep 05 18:35:39 2007 +0100
@@ -3,12 +3,16 @@
This file contains ns-3 release notes (most recent releases first).
-Release 3.0.5 (2007/08/XX)
+Release 3.0.5 (2007/08/15)
========================
- - Add CSMA/CD model (Emmanuelle Laprise)
- - Modularize ipv4 routing support (Gustavo Carneiro)
- - Add mobility framework and basic mobility models
+ - Refactoring to support win32-based unix environments (Cygwin, mingw)
+ - "Packet socket" for allowing applications to access NetDevices directly
+ - Generalized, polymorphic Address class
+ - Add CSMA NetDevice model (from Emmanuelle Laprise)
+ - Modularize IPv4 routing support (from Gustavo Carneiro)
+ - Add mobility framework and basic mobility models
+ - Global unicast centralized routing
Release 3.0.4 (2007/07/15)
========================
--- a/VERSION Mon Jul 30 14:48:56 2007 +0100
+++ b/VERSION Wed Sep 05 18:35:39 2007 +0100
@@ -1,1 +1,1 @@
-3.0.4
+3.0.5
--- a/doc/doxygen.conf Mon Jul 30 14:48:56 2007 +0100
+++ b/doc/doxygen.conf Wed Sep 05 18:35:39 2007 +0100
@@ -999,7 +999,7 @@
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
-PREDEFINED = RUN_SELF_TESTS NS3_DEBUG_ENABLE
+PREDEFINED = RUN_SELF_TESTS NS3_DEBUG_ENABLE NS3_ASSERT_ENABLE
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
--- a/doc/release_steps.txt Mon Jul 30 14:48:56 2007 +0100
+++ b/doc/release_steps.txt Wed Sep 05 18:35:39 2007 +0100
@@ -5,23 +5,20 @@
- revise and check in RELEASE_NOTES
- update and check in VERSION to the latest release number
2. make a new "architecture.pdf" document and place it in the doc/ directory
-3. add current version of waf script from subversion:
- - svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
- - build waf script and put it into top of ns-3-dev
-4. cd ns-3-dev; ./waf configure; ./waf dist
-5. test tarball on release platforms (run-tests and simple-p2p)
-6. tag ns-3-dev with "release ns-3.0.X"
+3. cd ns-3-dev; ./waf configure; ./waf dist
+4. test tarball on release platforms (waf check and maybe some other scripts)
+5. tag ns-3-dev with "release ns-3.0.X"
- hg tag "release ns-3.0.x"
- hg push
-7. clone the tagged ns-3-dev and place it on the repository
+6. clone the tagged ns-3-dev and place it on the repository
- ssh code.nsnam.org; sudo; su code;
- cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x
- cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately
-8. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server
-9. update web page
+7. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server
+8. update web page
- add link to news.html
- update download.html
- update roadmap.html
- build and update Doxygen directory on the server
- update and upload software architecture document (PDF, HTML)
-10. announce to ns-developers, with summary of release notes
+9. announce to ns-developers, with summary of release notes
--- a/examples/csma-cd-one-subnet.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * 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
- */
-
-// Port of ns-2/tcl/ex/simple.tcl to ns-3
-//
-// Network topology
-//
-// n0 n1 n2 n3
-// | | | |
-// =====================
-//
-// - CBR/UDP flows from n0 to n1, and from n3 to n0
-// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
-// (i.e., DataRate of 448,000 bps)
-// - DropTail queues
-// - Tracing of queues and packet receptions to file "csma-cd-one-subnet.tr"
-
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
-#include "ns3/command-line.h"
-#include "ns3/default-value.h"
-#include "ns3/ptr.h"
-#include "ns3/random-variable.h"
-#include "ns3/debug.h"
-
-#include "ns3/simulator.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-
-#include "ns3/ascii-trace.h"
-#include "ns3/pcap-trace.h"
-#include "ns3/internet-node.h"
-#include "ns3/csma-cd-channel.h"
-#include "ns3/csma-cd-net-device.h"
-#include "ns3/csma-cd-topology.h"
-#include "ns3/csma-cd-ipv4-topology.h"
-#include "ns3/mac-address.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/socket.h"
-#include "ns3/ipv4-route.h"
-#include "ns3/onoff-application.h"
-
-#include "ns3/ascii-trace.h"
-
-#include "ns3/trace-context.h"
-#include "ns3/trace-root.h"
-
-
-using namespace ns3;
-
-
-int main (int argc, char *argv[])
-{
-
- // Users may find it convenient to turn on explicit debugging
- // for selected modules; the below lines suggest how to do this
-#if 0
- DebugComponentEnable("CsmaCdNetDevice");
- DebugComponentEnable("Ipv4L3Protocol");
- DebugComponentEnable("NetDevice");
- DebugComponentEnable("Channel");
- DebugComponentEnable("CsmaCdChannel");
- DebugComponentEnable("PacketSocket");
-#endif
-
- // Set up some default values for the simulation. Use the Bind()
- // technique to tell the system what subclass of Queue to use,
- // and what the queue limit is
-
- // The below Bind command tells the queue factory which class to
- // instantiate, when the queue factory is invoked in the topology code
- Bind ("Queue", "DropTailQueue");
-
- // Allow the user to override any of the defaults and the above
- // Bind()s at run-time, via command-line arguments
- CommandLine::Parse (argc, argv);
-
- // Here, we will explicitly create four nodes. In more sophisticated
- // topologies, we could configure a node factory.
- Ptr<Node> n0 = Create<InternetNode> ();
- Ptr<Node> n1 = Create<InternetNode> ();
- Ptr<Node> n2 = Create<InternetNode> ();
- Ptr<Node> n3 = Create<InternetNode> ();
-
- // We create the channels first without any IP addressing information
- Ptr<CsmaCdChannel> channel0 =
- CsmaCdTopology::CreateCsmaCdChannel(
- DataRate(5000000), MilliSeconds(2));
-
- uint32_t n0ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n0, channel0,
- MacAddress("10:54:23:54:23:50"));
- uint32_t n1ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n1, channel0,
- MacAddress("10:54:23:54:23:51"));
- uint32_t n2ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n2, channel0,
- MacAddress("10:54:23:54:23:52"));
- uint32_t n3ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n3, channel0,
- MacAddress("10:54:23:54:23:53"));
-
- // Later, we add IP addresses.
- CsmaCdIpv4Topology::AddIpv4Address (
- n0, n0ifIndex, Ipv4Address("10.1.1.1"), Ipv4Mask("255.255.255.0"));
-
- CsmaCdIpv4Topology::AddIpv4Address (
- n1, n1ifIndex, Ipv4Address("10.1.1.2"), Ipv4Mask("255.255.255.0"));
-
- CsmaCdIpv4Topology::AddIpv4Address (
- n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0"));
-
- CsmaCdIpv4Topology::AddIpv4Address (
- n3, n3ifIndex, Ipv4Address("10.1.1.4"), Ipv4Mask("255.255.255.0"));
-
- // Create the OnOff application to send UDP datagrams of size
- // 210 bytes at a rate of 448 Kb/s
- // from n0 to n1
- Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
- n0,
- Ipv4Address("10.1.1.2"),
- 80,
- "Udp",
- ConstantVariable(1),
- ConstantVariable(0));
- // Start the application
- ooff->Start(Seconds(1.0));
- ooff->Stop (Seconds(10.0));
-
- // Create a similar flow from n3 to n0, starting at time 1.1 seconds
- ooff = Create<OnOffApplication> (
- n3,
- Ipv4Address("10.1.1.1"),
- 80,
- "Udp",
- ConstantVariable(1),
- ConstantVariable(0));
- // Start the application
- ooff->Start(Seconds(1.1));
- ooff->Stop (Seconds(10.0));
-
- // Configure tracing of all enqueue, dequeue, and NetDevice receive events
- // Trace output will be sent to the csma-cd-one-subnet.tr file
- AsciiTrace asciitrace ("csma-cd-one-subnet.tr");
- asciitrace.TraceAllNetDeviceRx ();
- asciitrace.TraceAllQueues ();
-
- // Also configure some tcpdump traces; each interface will be traced
- // The output files will be named
- // simple-point-to-point.pcap-<nodeId>-<interfaceId>
- // and can be read by the "tcpdump -r" command (use "-tt" option to
- // display timestamps correctly)
- PcapTrace pcaptrace ("csma-cd-one-subnet.pcap");
- pcaptrace.TraceAllIp ();
-
- Simulator::Run ();
-
- Simulator::Destroy ();
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-one-subnet.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,166 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+// n0 n1 n2 n3
+// | | | |
+// =====================
+//
+// - CBR/UDP flows from n0 to n1, and from n3 to n0
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+// (i.e., DataRate of 448,000 bps)
+// - DropTail queues
+// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/debug.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/eui48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/onoff-application.h"
+
+
+using namespace ns3;
+
+
+int main (int argc, char *argv[])
+{
+
+ // Users may find it convenient to turn on explicit debugging
+ // for selected modules; the below lines suggest how to do this
+#if 0
+ DebugComponentEnable("CsmaNetDevice");
+ DebugComponentEnable("Ipv4L3Protocol");
+ DebugComponentEnable("NetDevice");
+ DebugComponentEnable("Channel");
+ DebugComponentEnable("CsmaChannel");
+ DebugComponentEnable("PacketSocket");
+#endif
+
+ // Set up some default values for the simulation. Use the Bind()
+ // technique to tell the system what subclass of Queue to use,
+ // and what the queue limit is
+
+ // The below Bind command tells the queue factory which class to
+ // instantiate, when the queue factory is invoked in the topology code
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+
+ // Allow the user to override any of the defaults and the above
+ // Bind()s at run-time, via command-line arguments
+ CommandLine::Parse (argc, argv);
+
+ // Here, we will explicitly create four nodes. In more sophisticated
+ // topologies, we could configure a node factory.
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ // We create the channels first without any IP addressing information
+ Ptr<CsmaChannel> channel0 =
+ CsmaTopology::CreateCsmaChannel(
+ DataRate(5000000), MilliSeconds(2));
+
+ uint32_t n0ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0,
+ Eui48Address("10:54:23:54:23:50"));
+ uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0,
+ Eui48Address("10:54:23:54:23:51"));
+ uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel0,
+ Eui48Address("10:54:23:54:23:52"));
+ uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channel0,
+ Eui48Address("10:54:23:54:23:53"));
+
+ // Later, we add IP addresses.
+ CsmaIpv4Topology::AddIpv4Address (
+ n0, n0ifIndex, Ipv4Address("10.1.1.1"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n1, n1ifIndex, Ipv4Address("10.1.1.2"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n3, n3ifIndex, Ipv4Address("10.1.1.4"), Ipv4Mask("255.255.255.0"));
+
+ // Create the OnOff application to send UDP datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ // from n0 to n1
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("10.1.1.2", 80),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.0));
+ ooff->Stop (Seconds(10.0));
+
+ // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+ ooff = Create<OnOffApplication> (
+ n3,
+ InetSocketAddress ("10.1.1.1", 80),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.1));
+ ooff->Stop (Seconds(10.0));
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the csma-one-subnet.tr file
+ AsciiTrace asciitrace ("csma-one-subnet.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+
+ // Also configure some tcpdump traces; each interface will be traced
+ // The output files will be named
+ // simple-point-to-point.pcap-<nodeId>-<interfaceId>
+ // and can be read by the "tcpdump -r" command (use "-tt" option to
+ // display timestamps correctly)
+ PcapTrace pcaptrace ("csma-one-subnet.pcap");
+ pcaptrace.TraceAllIp ();
+
+ Simulator::Run ();
+
+ Simulator::Destroy ();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-packet-socket.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+// n0 n1 n2 n3
+// | | | |
+// =====================
+//
+// - CBR/UDP flows from n0 to n1, and from n3 to n0
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+// (i.e., DataRate of 448,000 bps)
+// - DropTail queues
+// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/debug.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/eui48-address.h"
+#include "ns3/packet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/onoff-application.h"
+#include "ns3/queue.h"
+
+using namespace ns3;
+
+static Ptr<CsmaNetDevice>
+CreateCsmaDevice (Ptr<Node> node, Ptr<CsmaChannel> channel)
+{
+ Ptr<CsmaNetDevice> device = Create<CsmaNetDevice> (node);
+ device->Attach (channel);
+ Ptr<Queue> queue = Queue::CreateDefault ();
+ device->AddQueue (queue);
+ return device;
+}
+
+
+int main (int argc, char *argv[])
+{
+ CommandLine::Parse (argc, argv);
+
+ // Here, we will explicitly create four nodes. In more sophisticated
+ // topologies, we could configure a node factory.
+ Ptr<Node> n0 = Create<Node> ();
+ Ptr<Node> n1 = Create<Node> ();
+ Ptr<Node> n2 = Create<Node> ();
+ Ptr<Node> n3 = Create<Node> ();
+
+ // create the shared medium used by all csma devices.
+ Ptr<CsmaChannel> channel = Create<CsmaChannel> (DataRate(5000000), MilliSeconds(2));
+
+ // use a helper function to connect our nodes to the shared channel.
+ Ptr<NetDevice> n0If = CreateCsmaDevice (n0, channel);
+ Ptr<NetDevice> n1If = CreateCsmaDevice (n1, channel);
+ Ptr<NetDevice> n2If = CreateCsmaDevice (n2, channel);
+ Ptr<NetDevice> n3If = CreateCsmaDevice (n3, channel);
+
+
+ // create the address which identifies n1 from n0
+ PacketSocketAddress n0ToN1;
+ n0ToN1.SetSingleDevice (n0If->GetIfIndex ()); // set outgoing interface for outgoing packets
+ n0ToN1.SetPhysicalAddress (n1If->GetAddress ()); // set destination address for outgoing packets
+ n0ToN1.SetProtocol (2); // set arbitrary protocol for outgoing packets
+
+ // create the address which identifies n0 from n3
+ PacketSocketAddress n3ToN0;
+ n3ToN0.SetSingleDevice (n3If->GetIfIndex ());
+ n3ToN0.SetPhysicalAddress (n0If->GetAddress ());
+ n3ToN0.SetProtocol (3);
+
+ // Create the OnOff application to send raw datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ // from n0 to n1
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ n0ToN1,
+ "Packet",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.0));
+ ooff->Stop (Seconds(10.0));
+
+ // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+ ooff = Create<OnOffApplication> (
+ n3,
+ n3ToN0,
+ "Packet",
+ ConstantVariable(1),
+ ConstantVariable(0));
+ // Start the application
+ ooff->Start(Seconds(1.1));
+ ooff->Stop (Seconds(10.0));
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the csma-packet-socket.tr file
+ AsciiTrace asciitrace ("csma-packet-socket.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+
+ Simulator::Run ();
+
+ Simulator::Destroy ();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mixed-global-routing.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,199 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ *
+ */
+
+// This script exercises global routing code in a mixed point-to-point
+// and csma/cd environment
+//
+// Network topology
+//
+// n0
+// \ p-p
+// \ (shared csma/cd)
+// n2 -------------------------n3
+// / | |
+// / p-p n4 n5 ---------- n6
+// n1 p-p
+//
+// - CBR/UDP flows from n0 to n6
+// - Tracing of queues and packet receptions to file "mixed-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/debug.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/eui48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+int main (int argc, char *argv[])
+{
+
+ // Users may find it convenient to turn on explicit debugging
+ // for selected modules; the below lines suggest how to do this
+#if 0
+ DebugComponentEnable ("Object");
+ DebugComponentEnable ("Queue");
+ DebugComponentEnable ("DropTailQueue");
+ DebugComponentEnable ("Channel");
+ DebugComponentEnable ("PointToPointChannel");
+ DebugComponentEnable ("PointToPointNetDevice");
+ DebugComponentEnable ("GlobalRouter");
+ DebugComponentEnable ("GlobalRouteManager");
+#endif
+
+ // Set up some default values for the simulation. Use the Bind ()
+ // technique to tell the system what subclass of Queue to use,
+ // and what the queue limit is
+
+ // The below DefaultValue::Bind command tells the queue factory which
+ // class to instantiate, when the queue factory is invoked in the
+ // topology code
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+
+ DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+ DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+ //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
+
+ // Allow the user to override any of the defaults and the above
+ // Bind ()s at run-time, via command-line arguments
+ CommandLine::Parse (argc, argv);
+
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+ Ptr<Node> n4 = Create<InternetNode> ();
+ Ptr<Node> n5 = Create<InternetNode> ();
+ Ptr<Node> n6 = Create<InternetNode> ();
+
+ // We create the channels first without any IP addressing information
+ Ptr<PointToPointChannel> channel0 =
+ PointToPointTopology::AddPointToPointLink (
+ n0, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel1 =
+ PointToPointTopology::AddPointToPointLink (
+ n1, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel2 =
+ PointToPointTopology::AddPointToPointLink (
+ n5, n6, DataRate (1500000), MilliSeconds (10));
+
+ // We create the channels first without any IP addressing information
+ Ptr<CsmaChannel> channelc0 =
+ CsmaTopology::CreateCsmaChannel(
+ DataRate(5000000), MilliSeconds(2));
+
+ uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channelc0,
+ Eui48Address("10:54:23:54:23:50"));
+ uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channelc0,
+ Eui48Address("10:54:23:54:23:51"));
+ uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n4, channelc0,
+ Eui48Address("10:54:23:54:23:52"));
+ uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n5, channelc0,
+ Eui48Address("10:54:23:54:23:53"));
+
+ // Later, we add IP addresses.
+ PointToPointTopology::AddIpv4Addresses (
+ channel0, n0, Ipv4Address ("10.1.1.1"),
+ n2, Ipv4Address ("10.1.1.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel1, n1, Ipv4Address ("10.1.2.1"),
+ n2, Ipv4Address ("10.1.2.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel2, n5, Ipv4Address ("10.1.3.1"),
+ n6, Ipv4Address ("10.1.3.2"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n2, n2ifIndex, Ipv4Address("10.250.1.1"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n3, n3ifIndex, Ipv4Address("10.250.1.2"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n4, n4ifIndex, Ipv4Address("10.250.1.3"), Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (
+ n5, n5ifIndex, Ipv4Address("10.250.1.4"), Ipv4Mask("255.255.255.0"));
+
+ // Create router nodes, initialize routing database and set up the routing
+ // tables in the nodes.
+ GlobalRouteManager::PopulateRoutingTables ();
+
+ // Create the OnOff application to send UDP datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("10.1.3.2", 80),
+ "Udp",
+ ConstantVariable (1),
+ ConstantVariable (0),
+ DataRate("300bps"),
+ 50);
+ // Start the application
+ ooff->Start (Seconds (1.0));
+ ooff->Stop (Seconds (10.0));
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the simple-global-routing.tr file
+ AsciiTrace asciitrace ("mixed-global-routing.tr");
+ asciitrace.TraceAllQueues ();
+ asciitrace.TraceAllNetDeviceRx ();
+
+ // Also configure some tcpdump traces; each interface will be traced
+ // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+ // and can be read by the "tcpdump -r" command (use "-tt" option to
+ // display timestamps correctly)
+ PcapTrace pcaptrace ("mixed-global-routing.pcap");
+ pcaptrace.TraceAllIp ();
+
+ Simulator::Run ();
+
+ Simulator::Destroy ();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/simple-global-routing.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,183 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ *
+ * ns-2 simple.tcl script (ported from ns-2)
+ * Originally authored by Steve McCanne, 12/19/1996
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+// n0
+// \ 5 Mb/s, 2ms
+// \ 1.5Mb/s, 10ms
+// n2 -------------------------n3
+// /
+// / 5 Mb/s, 2ms
+// n1
+//
+// - all links are point-to-point links with indicated one-way BW/delay
+// - CBR/UDP flows from n0 to n3, and from n3 to n1
+// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+// (i.e., DataRate of 448,000 bps)
+// - DropTail queues
+// - Tracing of queues and packet receptions to file "simple-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/debug.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+int main (int argc, char *argv[])
+{
+
+ // Users may find it convenient to turn on explicit debugging
+ // for selected modules; the below lines suggest how to do this
+#if 0
+ DebugComponentEnable ("Object");
+ DebugComponentEnable ("Queue");
+ DebugComponentEnable ("DropTailQueue");
+ DebugComponentEnable ("Channel");
+ DebugComponentEnable ("PointToPointChannel");
+ DebugComponentEnable ("PointToPointNetDevice");
+ DebugComponentEnable ("GlobalRouter");
+ DebugComponentEnable ("GlobalRouteMaager");
+#endif
+
+ // Set up some default values for the simulation. Use the DefaultValue::Bind ()
+ // technique to tell the system what subclass of Queue to use,
+ // and what the queue limit is
+
+ // The below Bind command tells the queue factory which class to
+ // instantiate, when the queue factory is invoked in the topology code
+ DefaultValue::Bind ("Queue", "DropTailQueue");
+
+ DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+ DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+ //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
+
+ // Allow the user to override any of the defaults and the above
+ // DefaultValue::Bind ()s at run-time, via command-line arguments
+ CommandLine::Parse (argc, argv);
+
+ // Here, we will explicitly create four nodes. In more sophisticated
+ // topologies, we could configure a node factory.
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+
+ // We create the channels first without any IP addressing information
+ Ptr<PointToPointChannel> channel0 =
+ PointToPointTopology::AddPointToPointLink (
+ n0, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel1 =
+ PointToPointTopology::AddPointToPointLink (
+ n1, n2, DataRate (5000000), MilliSeconds (2));
+
+ Ptr<PointToPointChannel> channel2 =
+ PointToPointTopology::AddPointToPointLink (
+ n2, n3, DataRate (1500000), MilliSeconds (10));
+
+ // Later, we add IP addresses.
+ PointToPointTopology::AddIpv4Addresses (
+ channel0, n0, Ipv4Address ("10.1.1.1"),
+ n2, Ipv4Address ("10.1.1.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel1, n1, Ipv4Address ("10.1.2.1"),
+ n2, Ipv4Address ("10.1.2.2"));
+
+ PointToPointTopology::AddIpv4Addresses (
+ channel2, n2, Ipv4Address ("10.1.3.1"),
+ n3, Ipv4Address ("10.1.3.2"));
+
+ // Create router nodes, initialize routing database and set up the routing
+ // tables in the nodes.
+ GlobalRouteManager::PopulateRoutingTables ();
+
+ // Create the OnOff application to send UDP datagrams of size
+ // 210 bytes at a rate of 448 Kb/s
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress ("10.1.3.2", 80),
+ "Udp",
+ ConstantVariable (1),
+ ConstantVariable (0));
+ // Start the application
+ ooff->Start (Seconds (1.0));
+ ooff->Stop (Seconds (10.0));
+
+ // Create a similar flow from n3 to n1, starting at time 1.1 seconds
+ ooff = Create<OnOffApplication> (
+ n3,
+ InetSocketAddress ("10.1.2.1", 80),
+ "Udp",
+ ConstantVariable (1),
+ ConstantVariable (0));
+ // Start the application
+ ooff->Start (Seconds (1.1));
+ ooff->Stop (Seconds (10.0));
+
+ // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+ // Trace output will be sent to the simple-global-routing.tr file
+ AsciiTrace asciitrace ("simple-global-routing.tr");
+ asciitrace.TraceAllQueues ();
+ asciitrace.TraceAllNetDeviceRx ();
+
+ // Also configure some tcpdump traces; each interface will be traced
+ // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+ // and can be read by the "tcpdump -r" command (use "-tt" option to
+ // display timestamps correctly)
+ PcapTrace pcaptrace ("simple-global-routing.pcap");
+ pcaptrace.TraceAllIp ();
+
+ Simulator::Run ();
+
+ Simulator::Destroy ();
+
+ return 0;
+}
--- a/examples/simple-point-to-point.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/examples/simple-point-to-point.cc Wed Sep 05 18:35:39 2007 +0100
@@ -57,8 +57,8 @@
#include "ns3/internet-node.h"
#include "ns3/point-to-point-channel.h"
#include "ns3/point-to-point-net-device.h"
-#include "ns3/mac-address.h"
#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
#include "ns3/ipv4.h"
#include "ns3/socket.h"
#include "ns3/ipv4-route.h"
@@ -72,6 +72,7 @@
// Users may find it convenient to turn on explicit debugging
// for selected modules; the below lines suggest how to do this
+ // remember to add #include "ns3/debug.h" before enabling these
#if 0
DebugComponentEnable("Object");
DebugComponentEnable("Queue");
@@ -87,12 +88,12 @@
// The below Bind command tells the queue factory which class to
// instantiate, when the queue factory is invoked in the topology code
- Bind ("Queue", "DropTailQueue");
+ DefaultValue::Bind ("Queue", "DropTailQueue");
- Bind ("OnOffApplicationPacketSize", "210");
- Bind ("OnOffApplicationDataRate", "448kb/s");
+ DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+ DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
- //Bind ("DropTailQueue::m_maxPackets", 30);
+ //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
// Allow the user to override any of the defaults and the above
// Bind()s at run-time, via command-line arguments
@@ -144,8 +145,7 @@
// 210 bytes at a rate of 448 Kb/s
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
n0,
- Ipv4Address("10.1.3.2"),
- 80,
+ InetSocketAddress ("10.1.3.2", 80),
"Udp",
ConstantVariable(1),
ConstantVariable(0));
@@ -156,8 +156,7 @@
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
ooff = Create<OnOffApplication> (
n3,
- Ipv4Address("10.1.2.1"),
- 80,
+ InetSocketAddress ("10.1.2.1", 80),
"Udp",
ConstantVariable(1),
ConstantVariable(0));
--- a/examples/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/examples/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -1,14 +1,23 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
def build(bld):
- def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
- obj = bld.create_obj('cpp', 'program')
- obj.target = name
- obj.uselib_local = ["ns3-%s" % dep for dep in deps]
- obj.source = source
- return obj
- obj = create_ns_prog('simple-point-to-point', 'simple-point-to-point.cc', deps=['point-to-point', 'internet-node'])
- obj = create_ns_prog('csma-cd-one-subnet', 'csma-cd-one-subnet.cc', deps=['csma-cd', 'internet-node'])
+ obj = bld.create_ns3_program('simple-global-routing',
+ ['point-to-point', 'internet-node', 'global-routing'])
+ obj.source = 'simple-global-routing.cc'
+
+ obj = bld.create_ns3_program('simple-point-to-point',
+ ['point-to-point', 'internet-node'])
+ obj.source = 'simple-point-to-point.cc'
+ obj = bld.create_ns3_program('csma-one-subnet',
+ ['csma', 'internet-node'])
+ obj.source = 'csma-one-subnet.cc'
+
+ obj = bld.create_ns3_program('csma-packet-socket',
+ ['csma', 'internet-node'])
+ obj.source = 'csma-packet-socket.cc'
+
+ obj = bld.create_ns3_program( 'mixed-global-routing',
+ ['point-to-point', 'internet-node', 'global-routing' , 'csma-cd'])
+ obj.source = 'mixed-global-routing.cc'
--- a/samples/main-default-value.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-default-value.cc Wed Sep 05 18:35:39 2007 +0100
@@ -73,7 +73,7 @@
// global variable and value (string) to overwrite the default.
// Here, the default value of 33 for testInt1 is overwritten with 57
//
- Bind("testInt1", "57");
+ DefaultValue::Bind("testInt1", "57");
TestClass* testclass = new TestClass ();
NS_DEBUG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-header.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,124 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#include "ns3/packet.h"
+#include "ns3/header.h"
+#include <iostream>
+
+using namespace ns3;
+
+/* A sample Header implementation
+ */
+class MyHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
+
+ MyHeader ();
+ virtual ~MyHeader ();
+
+ void SetData (uint16_t data);
+ uint16_t GetData (void) const;
+
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ void Serialize (Buffer::Iterator start) const;
+ uint32_t Deserialize (Buffer::Iterator start);
+ uint32_t GetSerializedSize (void) const;
+private:
+ uint16_t m_data;
+};
+
+MyHeader::MyHeader ()
+{
+ // we must provide a public default constructor,
+ // implicit or explicit, but never private.
+}
+MyHeader::~MyHeader ()
+{}
+
+uint32_t
+MyHeader::GetUid (void)
+{
+ // This string is used by the internals of the packet
+ // code to keep track of the packet metadata.
+ // You need to make sure that this string is absolutely
+ // unique. The code will detect any duplicate string.
+ static uint32_t uid = AllocateUid<MyHeader> ("MyHeader.test.nsnam.org");
+ return uid;
+}
+
+std::string
+MyHeader::GetName (void) const
+{
+ // This string is used to identify the type of
+ // my header by the packet printing routines.
+ return "MYHEADER";
+}
+void
+MyHeader::Print (std::ostream &os) const
+{
+ // This method is invoked by the packet printing
+ // routines to print the content of my header.
+ os << "data=" << m_data << std::endl;
+}
+uint32_t
+MyHeader::GetSerializedSize (void) const
+{
+ // we reserve 2 bytes for our header.
+ return 2;
+}
+void
+MyHeader::Serialize (Buffer::Iterator start) const
+{
+ // we can serialize two bytes at the start of the buffer.
+ // we write them in network byte order.
+ start.WriteHtonU16 (m_data);
+}
+uint32_t
+MyHeader::Deserialize (Buffer::Iterator start)
+{
+ // we can deserialize two bytes from the start of the buffer.
+ // we read them in network byte order and store them
+ // in host byte order.
+ m_data = start.ReadNtohU16 ();
+
+ // we return the number of bytes effectively read.
+ return 2;
+}
+
+void
+MyHeader::SetData (uint16_t data)
+{
+ m_data = data;
+}
+uint16_t
+MyHeader::GetData (void) const
+{
+ return m_data;
+}
+
+
+
+int main (int argc, char *argv[])
+{
+ // instantiate a header.
+ MyHeader sourceHeader;
+ sourceHeader.SetData (2);
+
+ // instantiate a packet
+ Packet p;
+ // and store my header into the packet.
+ p.AddHeader (sourceHeader);
+
+ // print the content of my packet on the standard output.
+ p.Print (std::cout);
+
+ // you can now remove the header from the packet:
+ MyHeader destinationHeader;
+ p.RemoveHeader (destinationHeader);
+
+ // and check that the destination and source
+ // headers contain the same values.
+ NS_ASSERT (sourceHeader.GetData () == destinationHeader.GetData ());
+
+ return 0;
+}
--- a/samples/main-packet-printer.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-packet-printer.cc Wed Sep 05 18:35:39 2007 +0100
@@ -90,15 +90,6 @@
std::cout << std::endl;
}
-// The below functions are used in place of default versions, in the
-// non-default case below. For instance, DoPrintIpv4Header will print
-// out less IPv4 header information than the default print function
-void
-DoPrintDefault (std::ostream &os,uint32_t packetUid, uint32_t size,
- std::string &name, struct PacketPrinter::FragmentInformation info)
-{
- os << name <<" (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
-}
void
DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
struct PacketPrinter::FragmentInformation info)
@@ -129,14 +120,10 @@
// set a string separator automatically inserted
// between each call to a printing function.
printer.SetSeparator (" - ");
- // set the default print function: invoked if no
- // specialized function has been provided for a header
- // or trailer
- printer.AddDefaultPrinter (MakeCallback (&DoPrintDefault));
// set the payload print function
- printer.AddPayloadPrinter (MakeCallback (&DoPrintPayload));
+ printer.SetPayloadPrinter (MakeCallback (&DoPrintPayload));
// set the print function for the header type Ipv4Header.
- printer.AddHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
+ printer.SetHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
MakeCallback (&DoPrintIpv4HeaderFragment));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-tag.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 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 "ns3/tag.h"
+#include "ns3/packet.h"
+#include <iostream>
+
+using namespace ns3;
+
+// define this class in a public header
+class MyTag : public Tag
+{
+public:
+ // we have to define a public constructor
+ MyTag ();
+ // we have to define a public copy constructor
+ MyTag (const MyTag &other);
+ // we have to define a public destructor
+ ~MyTag ();
+ // we have to define a public static GetUid method
+ static uint32_t GetUid (void);
+ // we have to define a public Print method
+ void Print (std::ostream &os) const;
+ // we have to define a public GetSerializedSize method
+ uint32_t GetSerializedSize (void) const;
+ // we have to define a public Serialize method
+ void Serialize (Buffer::Iterator i) const;
+ // we have to define a public Deserialize method
+ uint32_t Deserialize (Buffer::Iterator i);
+
+ // these are our accessors to our tag structure
+ void SetSimpleValue (uint8_t value);
+ uint8_t GetSimpleValue (void) const;
+private:
+ uint8_t m_simpleValue;
+};
+
+MyTag::MyTag ()
+{}
+MyTag::MyTag (const MyTag &other)
+ : m_simpleValue (other.m_simpleValue)
+{}
+MyTag::~MyTag ()
+{}
+uint32_t
+MyTag::GetUid (void)
+{
+ // we input a unique string to AllocateUid
+ // to avoid name collisions.
+ static uint32_t uid = AllocateUid<MyTag> ("MyTag.tests.nsnam.org");
+ return uid;
+}
+void
+MyTag::Print (std::ostream &os) const
+{
+ // print the content of this tag for Packet::PrintTags
+ os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec;
+}
+uint32_t
+MyTag::GetSerializedSize (void) const
+{
+ // we do not want to deal with parallel simulations
+ // so we return 0.
+ return 0;
+}
+void
+MyTag::Serialize (Buffer::Iterator i) const
+{
+ // we will never be invoked because we are not doing
+ // parallel simulations so, we assert.
+ NS_ASSERT (false);
+}
+uint32_t
+MyTag::Deserialize (Buffer::Iterator i)
+{
+ // we will never be invoked because we are not doing
+ // parallel simulations so, we assert.
+ NS_ASSERT (false);
+ // theoretically, return the number of bytes read
+ return 0;
+}
+
+
+void
+MyTag::SetSimpleValue (uint8_t value)
+{
+ m_simpleValue = value;
+}
+uint8_t
+MyTag::GetSimpleValue (void) const
+{
+ return m_simpleValue;
+}
+
+
+int main (int argc, char *argv[])
+{
+ // create a tag.
+ MyTag tag;
+ tag.SetSimpleValue (0x56);
+
+ // store the tag in a packet.
+ Packet p;
+ p.AddTag (tag);
+
+ // create a copy of the packet
+ Packet aCopy = p;
+
+ // read the tag from the packet copy
+ MyTag tagCopy;
+ p.PeekTag (tagCopy);
+
+ // the copy and the original are the same !
+ NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
+
+ aCopy.PrintTags (std::cout);
+ std::cout << std::endl;
+
+ return 0;
+}
--- a/samples/main-packet.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-#include "ns3/packet.h"
-#include "ns3/header.h"
-#include <iostream>
-
-using namespace ns3;
-
-/* A sample Header implementation
- */
-class MyHeader : public Header {
-public:
- MyHeader ();
- virtual ~MyHeader ();
-
- void SetData (uint16_t data);
- uint16_t GetData (void) const;
-private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
- virtual uint32_t GetSerializedSize (void) const;
-
- uint16_t m_data;
-};
-
-MyHeader::MyHeader ()
-{}
-MyHeader::~MyHeader ()
-{}
-std::string
-MyHeader::DoGetName (void) const
-{
- return "MyHeader";
-}
-void
-MyHeader::PrintTo (std::ostream &os) const
-{
- os << "MyHeader data=" << m_data << std::endl;
-}
-uint32_t
-MyHeader::GetSerializedSize (void) const
-{
- return 2;
-}
-void
-MyHeader::SerializeTo (Buffer::Iterator start) const
-{
- // serialize in head of buffer
- start.WriteHtonU16 (m_data);
-}
-uint32_t
-MyHeader::DeserializeFrom (Buffer::Iterator start)
-{
- // deserialize from head of buffer
- m_data = start.ReadNtohU16 ();
- return GetSerializedSize ();
-}
-
-void
-MyHeader::SetData (uint16_t data)
-{
- m_data = data;
-}
-uint16_t
-MyHeader::GetData (void) const
-{
- return m_data;
-}
-
-/* A sample Tag implementation
- */
-struct MyTag {
- uint16_t m_streamId;
-};
-
-static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
-
-
-static void
-Receive (Packet p)
-{
- MyHeader my;
- p.RemoveHeader (my);
- std::cout << "received data=" << my.GetData () << std::endl;
- struct MyTag myTag;
- p.PeekTag (myTag);
-}
-
-
-int main (int argc, char *argv[])
-{
- Packet p;
- MyHeader my;
- my.SetData (2);
- std::cout << "send data=2" << std::endl;
- p.AddHeader (my);
- struct MyTag myTag;
- myTag.m_streamId = 5;
- p.AddTag (myTag);
- Receive (p);
- return 0;
-}
--- a/samples/main-random-topology.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-random-topology.cc Wed Sep 05 18:35:39 2007 +0100
@@ -24,12 +24,12 @@
int main (int argc, char *argv[])
{
- Bind ("RandomDiscPositionX", "100");
- Bind ("RandomDiscPositionY", "50");
- Bind ("RandomDiscPositionRho", "Uniform:0:30");
+ DefaultValue::Bind ("RandomDiscPositionX", "100");
+ DefaultValue::Bind ("RandomDiscPositionY", "50");
+ DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
- Bind ("RandomTopologyPositionType", "RandomDiscPosition");
- Bind ("RandomTopologyMobilityType", "StaticMobilityModel");
+ DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition");
+ DefaultValue::Bind ("RandomTopologyMobilityType", "StaticMobilityModel");
CommandLine::Parse (argc, argv);
--- a/samples/main-simple.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-simple.cc Wed Sep 05 18:35:39 2007 +0100
@@ -4,7 +4,9 @@
#include "ns3/simulator.h"
#include "ns3/socket-factory.h"
#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
#include "ns3/nstime.h"
+#include "ns3/packet.h"
using namespace ns3;
@@ -12,7 +14,7 @@
GenerateTraffic (Ptr<Socket> socket, uint32_t size)
{
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl;
- socket->Send (0, size);
+ socket->Send (Packet (size));
if (size > 0)
{
Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50);
@@ -24,15 +26,15 @@
}
static void
-SocketPrinter (Ptr<Socket> socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort)
+SocketPrinter (Ptr<Socket> socket, const Packet &packet, const Address &from)
{
- std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl;
+ std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet.GetSize () << std::endl;
}
static void
PrintTraffic (Ptr<Socket> socket)
{
- socket->RecvDummy (MakeCallback (&SocketPrinter));
+ socket->SetRecvCallback (MakeCallback (&SocketPrinter));
}
void
@@ -44,10 +46,12 @@
Ptr<SocketFactory> socketFactory = a->QueryInterface<SocketFactory> (iid);
Ptr<Socket> sink = socketFactory->CreateSocket ();
- sink->Bind (80);
+ InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
+ sink->Bind (local);
Ptr<Socket> source = socketFactory->CreateSocket ();
- source->Connect (Ipv4Address::GetLoopback (), 80);
+ InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80);
+ source->Connect (remote);
GenerateTraffic (source, 500);
PrintTraffic (sink);
--- a/samples/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -1,28 +1,43 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
def build(bld):
- def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
- obj = bld.create_obj('cpp', 'program')
- obj.target = name
- obj.uselib_local = ["ns3-%s" % dep for dep in deps]
- obj.source = source
- return obj
-
- obj = create_ns_prog('main-debug', ['main-debug.cc', 'main-debug-other.cc'])
- obj = create_ns_prog('main-callback', 'main-callback.cc')
- obj = create_ns_prog('main-ptr', 'main-ptr.cc')
- #obj = create_ns_prog('main-trace', 'main-trace.cc')
- obj = create_ns_prog('main-simulator', 'main-simulator.cc')
- obj = create_ns_prog('main-packet', 'main-packet.cc')
- obj = create_ns_prog('main-test', 'main-test.cc')
- obj = create_ns_prog('main-simple', 'main-simple.cc',
- deps=['node', 'internet-node', 'applications'])
- #obj = create_ns_prog('main-simple-p2p', 'main-simple-p2p.cc', deps=['node', 'point-to-point'])
- obj = create_ns_prog('main-default-value', 'main-default-value.cc',
- deps=['core', 'simulator', 'node', 'point-to-point'])
- obj = create_ns_prog('main-grid-topology', 'main-grid-topology.cc',
- deps=['core', 'simulator', 'mobility', 'internet-node'])
- obj = create_ns_prog('main-random-topology', 'main-random-topology.cc',
- deps=['core', 'simulator', 'mobility'])
+ obj = bld.create_ns3_program('main-debug')
+ obj.source = ['main-debug.cc', 'main-debug-other.cc']
+
+ obj = bld.create_ns3_program('main-callback')
+ obj.source = 'main-callback.cc'
+
+ obj = bld.create_ns3_program('main-ptr')
+ obj.source = 'main-ptr.cc'
+
+ obj = bld.create_ns3_program('main-simulator')
+ obj.source = 'main-simulator.cc'
+
+ obj = bld.create_ns3_program('main-packet-header', ['common', 'simulator'])
+ obj.source = 'main-packet-header.cc'
+
+ obj = bld.create_ns3_program('main-packet-tag', ['common', 'simulator'])
+ obj.source = 'main-packet-tag.cc'
+ obj = bld.create_ns3_program('main-packet-printer', ['common', 'simulator', 'internet-node'])
+ obj.source = 'main-packet-printer.cc'
+
+ obj = bld.create_ns3_program('main-test')
+ obj.source = 'main-test.cc'
+
+ obj = bld.create_ns3_program('main-simple',
+ ['node', 'internet-node', 'applications'])
+ obj.source = 'main-simple.cc'
+
+ obj = bld.create_ns3_program('main-default-value',
+ ['core', 'simulator', 'node', 'point-to-point'])
+ obj.source = 'main-default-value.cc'
+
+ obj = bld.create_ns3_program('main-grid-topology',
+ ['core', 'simulator', 'mobility', 'internet-node'])
+ obj.source = 'main-grid-topology.cc'
+
+ obj = bld.create_ns3_program('main-random-topology',
+ ['core', 'simulator', 'mobility'])
+ obj.source = 'main-random-topology.cc'
+
--- a/src/applications/onoff-application.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/applications/onoff-application.cc Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,7 @@
// George F. Riley, Georgia Tech, Spring 2007
// Adapted from ApplicationOnOff in GTNetS.
-#include "ns3/ipv4-address.h"
+#include "ns3/address.h"
#include "ns3/node.h"
#include "ns3/nstime.h"
#include "ns3/data-rate.h"
@@ -31,6 +31,7 @@
#include "ns3/simulator.h"
#include "ns3/socket-factory.h"
#include "ns3/default-value.h"
+#include "ns3/packet.h"
#include "onoff-application.h"
using namespace std;
@@ -47,22 +48,20 @@
// Constructors
OnOffApplication::OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
+ const Address &remote,
std::string iid,
const RandomVariable& ontime,
const RandomVariable& offtime)
: Application(n),
m_cbrRate (g_defaultRate.GetValue ())
{
- Construct (n, rip, rport, iid,
+ Construct (n, remote, iid,
ontime, offtime,
g_defaultSize.GetValue ());
}
OnOffApplication::OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
+ const Address &remote,
std::string iid,
const RandomVariable& ontime,
const RandomVariable& offtime,
@@ -71,22 +70,20 @@
: Application(n),
m_cbrRate (rate)
{
- Construct (n, rip, rport, iid,
+ Construct (n, remote, iid,
ontime, offtime, size);
}
void
OnOffApplication::Construct (Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
+ const Address &remote,
std::string iid,
const RandomVariable& onTime,
const RandomVariable& offTime,
uint32_t size)
{
m_socket = 0;
- m_peerIp = rip;
- m_peerPort = rport;
+ m_peer = remote;
m_connected = false;
m_onTime = onTime.Copy ();
m_offTime = offTime.Copy ();
@@ -144,7 +141,7 @@
Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
m_socket = socketFactory->CreateSocket ();
m_socket->Bind ();
- m_socket->Connect (m_peerIp, m_peerPort);
+ m_socket->Connect (m_peer);
}
// Insure no pending event
StopApplication();
@@ -209,7 +206,7 @@
void OnOffApplication::SendPacket()
{
NS_ASSERT (m_sendEvent.IsExpired ());
- m_socket->Send(0, m_pktSize);
+ m_socket->Send(Packet (m_pktSize));
m_totBytes += m_pktSize;
m_lastStartTime = Simulator::Now();
m_residualBits = 0;
--- a/src/applications/onoff-application.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/applications/onoff-application.h Wed Sep 05 18:35:39 2007 +0100
@@ -28,13 +28,13 @@
#include "ns3/application.h"
#include "ns3/event-id.h"
#include "ns3/ptr.h"
+#include "ns3/data-rate.h"
namespace ns3 {
-class Ipv4Address;
+class Address;
class RandomVariable;
class Socket;
-class DataRate;
/**
* \brief Generate traffic to a single destination according to an
@@ -52,23 +52,20 @@
public:
/**
* \param n node associated to this application
- * \param rip remote ip address
- * \param rport remove port number
+ * \param remote remote ip address
* \param iid
* \param ontime on time random variable
* \param offtime off time random variable
*/
OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
+ const Address &remote,
std::string iid,
const RandomVariable& ontime,
const RandomVariable& offtime);
/**
* \param n node associated to this application
- * \param rip remote ip address
- * \param rport remove port number
+ * \param remote remote ip address
* \param iid
* \param ontime on time random variable
* \param offtime off time random variable
@@ -76,8 +73,7 @@
* \param size size of packets when sending data.
*/
OnOffApplication(Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
+ const Address &remote,
std::string iid,
const RandomVariable& ontime,
const RandomVariable& offtime,
@@ -112,8 +108,7 @@
virtual void StopApplication (void); // Called at time specified by Stop
void Construct (Ptr<Node> n,
- const Ipv4Address rip,
- uint16_t rport,
+ const Address &remote,
std::string iid,
const RandomVariable& ontime,
const RandomVariable& offtime,
@@ -126,8 +121,7 @@
void SendPacket();
Ptr<Socket> m_socket; // Associated socket
- Ipv4Address m_peerIp; // Peer IP address
- uint16_t m_peerPort; // Peer port
+ Address m_peer; // Peer address
bool m_connected; // True if connected
RandomVariable* m_onTime; // rng for On Time
RandomVariable* m_offTime; // rng for Off Time
--- a/src/applications/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/applications/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -1,10 +1,7 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- obj = bld.create_obj('cpp', 'shlib')
- obj.name = 'ns3-applications'
- obj.target = obj.name
- obj.uselib_local = ['ns3-node']
+ obj = bld.create_ns3_module('applications', ['node'])
obj.source = [
'onoff-application.cc',
]
--- a/src/common/array-trace-resolver.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/array-trace-resolver.h Wed Sep 05 18:35:39 2007 +0100
@@ -32,39 +32,11 @@
* \brief a helper class to offer trace resolution for an array of objects.
* \ingroup lowleveltracing
*/
-template <typename T>
+template <typename T, typename INDEX>
class ArrayTraceResolver : public TraceResolver
{
public:
/**
- * \brief array index trace context
- *
- * During namespace parsing, ns3::ArrayTraceResolver will
- * embed an instance of this class in the TraceContext
- * associated to every child object of the object stored
- * at the index.
- *
- * The reason why this class exists is to ensure that we
- * need to ensure that we can store a unique type as context
- * into the TraceContext associated to this trace resolver.
- */
- class Index
- {
- public:
- Index ();
- Index (uint32_t index);
- /**
- * The Index is automatically convertible to the
- * uin32_t type such that it really behaves like a uint32_t
- * array index for the user.
- *
- * \returns the index itself
- */
- operator uint32_t ();
- private:
- uint32_t m_index;
- };
- /**
* \param context trace context associated to this trace resolver
* \param getSize callback which returns dynamically the size of underlying array
* \param get callback which returns any element in the underlying array
@@ -81,51 +53,37 @@
*/
ArrayTraceResolver (TraceContext const &context,
Callback<uint32_t> getSize,
- Callback<T *, uint32_t> get);
+ Callback<T, uint32_t> get);
private:
virtual TraceResolverList DoLookup (std::string id) const;
Callback<uint32_t> m_getSize;
- Callback<T *, uint32_t> m_get;
+ Callback<T, uint32_t> m_get;
};
}//namespace ns3
namespace ns3 {
-template <typename T>
-ArrayTraceResolver<T>::Index::Index ()
- : m_index ()
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::Index (uint32_t index)
- : m_index (index)
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::operator uint32_t ()
-{
- return m_index;
-}
-
-template <typename T>
-ArrayTraceResolver<T>::ArrayTraceResolver (TraceContext const &context,
- Callback<uint32_t> getSize,
- Callback<T *, uint32_t> get)
+template <typename T, typename INDEX>
+ArrayTraceResolver<T,INDEX>::ArrayTraceResolver (TraceContext const &context,
+ Callback<uint32_t> getSize,
+ Callback<T, uint32_t> get)
: TraceResolver (context),
m_getSize (getSize),
m_get (get)
{}
-template <typename T>
+template <typename T, typename INDEX>
TraceResolver::TraceResolverList
-ArrayTraceResolver<T>::DoLookup (std::string id) const
+ArrayTraceResolver<T,INDEX>::DoLookup (std::string id) const
{
TraceResolverList list;
if (id == "*")
{
for (uint32_t i = 0; i < m_getSize (); i++)
{
- TraceContext context = GetContext ();
- typename ArrayTraceResolver<T>::Index index = typename ArrayTraceResolver<T>::Index (i);
- context.Add (index);
- list.push_back (m_get (i)->CreateTraceResolver (context));
+ TraceContext context = GetContext ();
+ INDEX index = i;
+ context.Add (index);
+ list.push_back (m_get (i)->CreateTraceResolver (context));
}
}
return list;
--- a/src/common/buffer.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/buffer.cc Wed Sep 05 18:35:39 2007 +0100
@@ -410,8 +410,8 @@
return tmp;
}
-void
-Buffer::TransformIntoRealBuffer (void) const
+Buffer
+Buffer::CreateFullCopy (void) const
{
if (m_zeroAreaSize != 0)
{
@@ -428,8 +428,16 @@
Buffer::Iterator i = tmp.End ();
i.Prev (dataEnd);
i.Write (m_data->m_data+m_data->m_initialStart,dataEnd);
- *const_cast<Buffer *> (this) = tmp;
+ return tmp;
}
+ return *this;
+}
+
+void
+Buffer::TransformIntoRealBuffer (void) const
+{
+ Buffer tmp = CreateFullCopy ();
+ *const_cast<Buffer *> (this) = tmp;
}
--- a/src/common/buffer.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/buffer.h Wed Sep 05 18:35:39 2007 +0100
@@ -320,7 +320,7 @@
*/
inline Buffer::Iterator End (void) const;
- void TransformIntoRealBuffer (void) const;
+ Buffer CreateFullCopy (void) const;
inline Buffer (Buffer const &o);
inline Buffer &operator = (Buffer const &o);
@@ -343,6 +343,7 @@
};
inline uint8_t *GetStart (void) const;
+ void TransformIntoRealBuffer (void) const;
static void Recycle (struct Buffer::BufferData *data);
static struct Buffer::BufferData *Create (void);
static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,117 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "chunk-registry.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+ChunkRegistry::InfoVector *
+ChunkRegistry::GetInfoVector (void)
+{
+ static InfoVector vec;
+ return &vec;
+}
+
+std::string
+ChunkRegistry::GetUidStringFromUid (uint32_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.uidString;
+}
+uint32_t
+ChunkRegistry::GetUidFromUidString (std::string uidString)
+{
+ uint32_t uid = 1;
+ InfoVector *vec = GetInfoVector ();
+ for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<<
+ "You could try calling NS_HEADER_ENSURE_REGISTER somewhere.");
+ return 0;
+}
+
+uint8_t *
+ChunkRegistry::GetStaticInstance (uint32_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.getStaticInstance ();
+}
+bool
+ChunkRegistry::IsHeader (uint32_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.isHeader;
+}
+bool
+ChunkRegistry::IsTrailer (uint32_t uid)
+{
+ return !IsHeader (uid);
+}
+uint32_t
+ChunkRegistry::Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.deserialize (instance, i);
+}
+void
+ChunkRegistry::Print (uint32_t uid, uint8_t *instance, std::ostream &os)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.print (instance, os);
+}
+std::string
+ChunkRegistry::GetName (uint32_t uid, uint8_t *instance)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ return info.getName (instance);
+}
+void
+ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback)
+{
+ InfoVector *vec = GetInfoVector ();
+ NS_ASSERT (uid >= 1 && uid <= vec->size ());
+ Info info = (*vec)[uid - 1];
+ info.invokePrintCallback (instance, os, packetUid, size, callback);
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,180 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef CHUNK_REGISTRY_H
+#define CHUNK_REGISTRY_H
+
+#include <stdint.h>
+#include <ostream>
+#include "buffer.h"
+#include "ns3/ptr.h"
+#include "ns3/callback.h"
+
+namespace ns3 {
+
+/**
+ * \brief this registry keeps track of all different
+ * types of headers and trailers and assigns to each of them
+ * a unique integer.
+ * \internal
+ */
+class ChunkRegistry
+{
+public:
+ template <typename T>
+ static uint32_t RegisterHeader (std::string uuid);
+ template <typename T>
+ static uint32_t RegisterTrailer (std::string uuid);
+
+ static std::string GetUidStringFromUid (uint32_t uid);
+ static uint32_t GetUidFromUidString (std::string uidString);
+ static uint8_t *GetStaticInstance (uint32_t uid);
+ static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i);
+ static void Print (uint32_t uid, uint8_t *instance, std::ostream &os);
+ static std::string GetName (uint32_t uid, uint8_t *instance);
+ static bool IsHeader (uint32_t uid);
+ static bool IsTrailer (uint32_t uid);
+ static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback);
+private:
+ typedef uint8_t *(*GetStaticInstanceCb) (void);
+ typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+ typedef void (*PrintCb) (uint8_t *,std::ostream &);
+ typedef std::string (*GetNameCb) (uint8_t *);
+ typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback);
+ struct Info {
+ std::string uidString;
+ bool isHeader;
+ GetStaticInstanceCb getStaticInstance;
+ DeserializeCb deserialize;
+ PrintCb print;
+ GetNameCb getName;
+ InvokePrintCallbackCb invokePrintCallback;
+ };
+ typedef std::vector<struct Info> InfoVector;
+ static InfoVector *GetInfoVector (void);
+ template <typename T>
+ static uint8_t *DoGetStaticInstance (void);
+ template <typename T>
+ static uint32_t DoDeserialize (uint8_t *instance, Buffer::Iterator i);
+ template <typename T>
+ static void DoPrint (uint8_t *instance, std::ostream &os);
+ template <typename T>
+ static std::string DoGetName (uint8_t *instance);
+ template <typename T>
+ static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback);
+ template <typename T>
+ static uint32_t GetUid (bool isHeader, std::string uidString);
+
+};
+
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+ChunkRegistry::RegisterHeader (std::string uuid)
+{
+ return GetUid<T> (true, uuid);
+}
+template <typename T>
+uint32_t
+ChunkRegistry::RegisterTrailer (std::string uuid)
+{
+ return GetUid<T> (false, uuid);
+}
+
+template <typename T>
+uint32_t
+ChunkRegistry::GetUid (bool isHeader, std::string uidString)
+{
+ InfoVector *vec = GetInfoVector ();
+ uint32_t uid = 1;
+ for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ Info info;
+ info.getStaticInstance = &ChunkRegistry::DoGetStaticInstance<T>;
+ info.print = &ChunkRegistry::DoPrint<T>;
+ info.getName = &ChunkRegistry::DoGetName<T>;
+ info.deserialize = &ChunkRegistry::DoDeserialize<T>;
+ info.invokePrintCallback = &ChunkRegistry::DoInvokePrintCallback<T>;
+ info.uidString = uidString;
+ info.isHeader = isHeader;
+ vec->push_back (info);
+ return vec->size ();
+}
+
+template <typename T>
+uint8_t *
+ChunkRegistry::DoGetStaticInstance ()
+{
+ static T instance;
+ return reinterpret_cast<uint8_t *> (&instance);
+}
+template <typename T>
+uint32_t
+ChunkRegistry::DoDeserialize (uint8_t *instance, Buffer::Iterator i)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ return obj->Deserialize (i);
+}
+template <typename T>
+void
+ChunkRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ obj->Print (os);
+}
+template <typename T>
+std::string
+ChunkRegistry::DoGetName (uint8_t *instance)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ return obj->GetName ();
+}
+template <typename T>
+void
+ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+ uint32_t packetUid, uint32_t size,
+ Ptr<CallbackImplBase> callback)
+{
+ T *obj = reinterpret_cast<T *> (instance);
+ Callback<void,std::ostream&,uint32_t,uint32_t,const T*> cb;
+ cb.Assign (callback);
+ cb (os, packetUid, size, obj);
+}
+
+} // namespace ns3
+
+#endif /* CHUNK_H */
--- a/src/common/chunk.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "chunk.h"
-#include "ns3/assert.h"
-
-namespace ns3 {
-
-Chunk::Chunk ()
-{}
-
-Chunk::~Chunk ()
-{}
-
-std::string
-Chunk::GetName (void) const
-{
- return DoGetName ();
-}
-void
-Chunk::Print (std::ostream &os) const
-{
- PrintTo (os);
-}
-uint32_t
-Chunk::GetSize (void) const
-{
- return GetSerializedSize ();
-}
-void
-Chunk::Serialize (Buffer::Iterator start) const
-{
- SerializeTo (start);
-}
-uint32_t
-Chunk::Deserialize (Buffer::Iterator start)
-{
- uint32_t deserialized = DeserializeFrom (start);
- return deserialized;
-}
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk)
-{
- chunk.Print (os);
- return os;
-}
-
-}; // namespace ns3
--- a/src/common/chunk.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef CHUNK_H
-#define CHUNK_H
-
-#include <stdint.h>
-#include <ostream>
-#include "buffer.h"
-
-namespace ns3 {
-
-class Chunk {
-public:
- Chunk ();
- virtual ~Chunk ();
-
- std::string GetName (void) const;
- void Print (std::ostream &os) const;
- uint32_t GetSize (void) const;
- void Serialize (Buffer::Iterator start) const;
- uint32_t Deserialize (Buffer::Iterator start);
-private:
- virtual std::string DoGetName (void) const = 0;
- virtual void PrintTo (std::ostream &os) const = 0;
- virtual uint32_t GetSerializedSize (void) const = 0;
- virtual void SerializeTo (Buffer::Iterator i) const = 0;
- virtual uint32_t DeserializeFrom (Buffer::Iterator i) = 0;
-};
-
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk);
-
-}; // namespace ns3
-
-#endif /* CHUNK_H */
--- a/src/common/composite-trace-resolver.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/composite-trace-resolver.cc Wed Sep 05 18:35:39 2007 +0100
@@ -30,6 +30,14 @@
{}
void
+CompositeTraceResolver::Add (std::string name,
+ Callback<TraceResolver *,TraceContext const &> createResolver)
+{
+ TraceContext traceContext = GetContext ();
+ DoAdd (name, createResolver, traceContext);
+}
+
+void
CompositeTraceResolver::DoAdd (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver,
TraceContext const &context)
@@ -107,20 +115,53 @@
#ifdef RUN_SELF_TESTS
#include "ns3/test.h"
+#include "trace-context-element.h"
namespace ns3 {
+class TraceSourceTest : public TraceContextElement
+{
+public:
+ enum Sources {
+ DOUBLEA,
+ DOUBLEB,
+ SUBRESOLVER,
+ };
+ static uint16_t GetUid (void)
+ {static uint16_t uid = AllocateUid<TraceSourceTest> ("TraceSourceTest"); return uid;}
+ void Print (std::ostream &os)
+ {os << "tracesource=";
+ if (m_sources == DOUBLEA) {os << "doubleA";}
+ else if (m_sources == DOUBLEB) {os << "doubleB";}
+ else if (m_sources == SUBRESOLVER) {os << "subresolver";}
+ }
+ TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {}
+ TraceSourceTest (enum Sources sources) :m_sources (sources) {}
+ bool IsDoubleA (void) {return m_sources == TraceSourceTest::DOUBLEA;}
+ bool IsDoubleB (void) {return m_sources == TraceSourceTest::DOUBLEB;}
+private:
+ enum TraceSourceTest::Sources m_sources;
+};
+
+class SubTraceSourceTest : public TraceContextElement
+{
+public:
+ enum Sources {
+ INT,
+ };
+ static uint16_t GetUid (void)
+ {static uint16_t uid = AllocateUid<SubTraceSourceTest> ("SubTraceSourceTest"); return uid;}
+ void Print (std::ostream &os)
+ {os << "subtracesource=int";}
+ SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {}
+ SubTraceSourceTest (enum Sources sources) : m_sources (sources) {}
+private:
+ enum Sources m_sources;
+};
+
class CompositeTraceResolverTest : public Test
{
public:
- enum TraceSources {
- TEST_TRACE_DOUBLEA,
- TEST_TRACE_DOUBLEB,
- TEST_TRACE_SUBRESOLVER,
- };
- enum SubTraceSources {
- TEST_SUBTRACE_INT,
- };
CompositeTraceResolverTest ();
virtual ~CompositeTraceResolverTest ();
virtual bool RunTests (void);
@@ -144,19 +185,19 @@
void
CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
{
- enum CompositeTraceResolverTest::TraceSources source;
+ TraceSourceTest source;
context.Get (source);
- switch (source)
+ if (source.IsDoubleA ())
{
- case TEST_TRACE_DOUBLEA:
m_gotDoubleA = true;
- break;
- case TEST_TRACE_DOUBLEB:
+ }
+ else if (source.IsDoubleB ())
+ {
m_gotDoubleB = true;
- break;
- default:
+ }
+ else
+ {
NS_FATAL_ERROR ("should not get any other trace source in this sink");
- break;
}
}
@@ -171,7 +212,8 @@
CompositeTraceResolverTest::CreateSubResolver (TraceContext const &context)
{
CompositeTraceResolver *subresolver = new CompositeTraceResolver (context);
- subresolver->Add ("trace-int", m_traceInt, TEST_SUBTRACE_INT);
+ subresolver->Add ("trace-int", m_traceInt,
+ SubTraceSourceTest (SubTraceSourceTest::INT));
return subresolver;
}
bool
@@ -185,8 +227,10 @@
CompositeTraceResolver resolver (context) ;
- resolver.Add ("trace-double-a", traceDoubleA, TEST_TRACE_DOUBLEA);
- resolver.Add ("trace-double-b", traceDoubleB, TEST_TRACE_DOUBLEB);
+ resolver.Add ("trace-double-a", traceDoubleA,
+ TraceSourceTest (TraceSourceTest::DOUBLEA));
+ resolver.Add ("trace-double-b", traceDoubleB,
+ TraceSourceTest (TraceSourceTest::DOUBLEB));
resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
@@ -279,7 +323,7 @@
resolver.Add ("subresolver",
MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this),
- TEST_TRACE_SUBRESOLVER);
+ TraceSourceTest (TraceSourceTest::SUBRESOLVER));
resolver.Connect ("/subresolver/trace-int",
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
--- a/src/common/composite-trace-resolver.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/composite-trace-resolver.h Wed Sep 05 18:35:39 2007 +0100
@@ -111,6 +111,18 @@
void Add (std::string name,
Callback<TraceResolver *,TraceContext const &> createResolver,
T const &context);
+
+ /**
+ * \param name name of child trace resolver
+ * \param createResolver a trace resolver constructor
+ *
+ * Add a child trace resolver to this resolver. This child
+ * trace resolver will match the name specified during
+ * namespace resolution. When this happens, the constructor
+ * will be invoked to create the child trace resolver.
+ */
+ void Add (std::string name,
+ Callback<TraceResolver *,TraceContext const &> createResolver);
private:
template <typename SOURCE, typename CONTEXT>
void DoAddTraceSource (std::string name,
@@ -205,7 +217,6 @@
DoAdd (name, createResolver, traceContext);
}
-
}//namespace ns3
#endif /* COMPOSITE_TRACE_RESOLVER_H */
--- a/src/common/header.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "header.h"
-
-namespace ns3 {
-
-Header::~Header ()
-{}
-
-}; // namespace ns3
--- a/src/common/header.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/header.h Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,29 @@
#ifndef HEADER_H
#define HEADER_H
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Header
+ * \brief this macro should be instantiated exactly once for each
+ * new type of Header
+ *
+ * This macro will ensure that your new Header type is registered
+ * within the packet header registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_HEADER_ENSURE_REGISTERED(x) \
+static class thisisaveryverylongclassname ##x \
+{ \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+} g_thisisanotherveryveryverylongname ## x;
+
namespace ns3 {
@@ -30,68 +52,64 @@
* \brief Protocol header serialization and deserialization.
*
* Every Protocol header which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- * - ns3::Header::SerializeTo
- * - ns3::Header::DeserializeFrom
- * - ns3::Header::GetSerializedSize
- * - ns3::Header::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ * - a default constructor: is used by the internal implementation
+ * if the Packet class.
+ * - a static method named GetUid: is used to uniquely identify
+ * the type of each header. This method shall return a unique
+ * integer allocated with Header::AllocateUid.
+ * - a method named Serialize: is used by Packet::AddHeader to
+ * store a header into the byte buffer of a packet.
+ * The input iterator points to the start of the byte buffer in
+ * which the header should write its data. The data written
+ * is expected to match bit-for-bit the representation of this
+ * header in a real network.
+ * - a method named GetSerializedSize: is used by Packet::AddHeader
+ * to store a header into the byte buffer of a packet. This method
+ * should return the number of bytes which are needed to store
+ * the full header data by Serialize.
+ * - a method named Deserialize: is used by Packet::RemoveHeader to
+ * re-create a header from the byte buffer of a packet. The input
+ * iterator points to the start of the byte buffer from which
+ * the header should read its data. The data read is expected to
+ * match bit-for-bit the representation of this header in real
+ * networks. This method shall return an integer which identifies
+ * the number of bytes read.
+ * - a method named Print: is used by Packet::Print to print the
+ * content of a header as ascii data to a c++ output stream.
+ * Although the header is free to format its output as it
+ * wishes, it is recommended to follow a few rules to integrate
+ * with the packet pretty printer: start with flags, small field
+ * values located between a pair of parens. Values should be separated
+ * by whitespace. Follow the parens with the important fields,
+ * separated by whitespace.
+ * i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ * - a method named GetName: is used by Packet::Print to print
+ * header fragments. This method should return a user-readable
+ * single word as all capitalized letters.
+ *
+ * Sample code which shows how to create a new type of Header, and how to use it,
+ * is shown in the sample file samples/main-packet-header.cc
*/
-class Header : public Chunk {
-public:
- virtual ~Header ();
-private:
- /**
- * \returns a user-readable name to identify this type of header.
- *
- * The string returned is expected to be a single word with
- * all capital letters
- */
- virtual std::string DoGetName (void) const = 0;
- /**
- * \param os the std output stream in which this
- * protocol header must print itself.
- *
- * Although the header is free to format its output as it
- * wishes, it is recommended to follow a few rules to integrate
- * with the packet pretty printer:
- * - start with flags, small field values located between a
- * pair of parens. Values should be separated by whitespace.
- * - follow the parens with the important fields, separated by
- * whitespace.
- * i.e.:
- * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
- */
- virtual void PrintTo (std::ostream &os) const = 0;
-
- /**
- * \returns the size of the serialized Header.
- *
- * This method is used by Packet::AddHeader to reserve
- * enough room in the packet byte buffer prior to calling
- * Header::Serialize.
- */
- virtual uint32_t GetSerializedSize (void) const = 0;
-
- /**
- * \param start the buffer iterator in which the protocol header
- * must serialize itself. This iterator identifies
- * the start of the buffer.
- */
- virtual void SerializeTo (Buffer::Iterator start) const = 0;
- /**
- * \param start the buffer iterator from which the protocol header must
- * deserialize itself. This iterator identifies
- * the start of the buffer.
- * \returns the number of bytes read from the buffer
- *
- * The value returned is used to trim the packet byte buffer of the
- * corresponding amount when this method is invoked from
- * Packet::RemoveHeader
- */
- virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0;
+class Header
+{
+protected:
+ template <typename T>
+ static uint32_t AllocateUid (std::string uuid);
};
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Header::AllocateUid (std::string uuid)
+{
+ return ChunkRegistry::RegisterHeader<T> (uuid);
+}
+
+} // namespace ns3
#endif /* HEADER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata-test.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,683 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 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>
+ */
+#ifdef RUN_SELF_TESTS
+
+#include <stdarg.h>
+#include <iostream>
+#include <sstream>
+#include "ns3/test.h"
+#include "header.h"
+#include "trailer.h"
+#include "packet.h"
+#include "packet-metadata.h"
+#include "packet-printer.h"
+
+namespace ns3 {
+
+template <int N>
+class HistoryHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
+ HistoryHeader ();
+ bool IsOk (void) const;
+ std::string GetName (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);
+private:
+ bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryHeader<N>::GetUid (void)
+{
+ std::ostringstream oss;
+ oss << N << "HistoryHeader.ns3";
+ static uint32_t uid = AllocateUid<HistoryHeader<N> > (oss.str());
+ return uid;
+}
+
+template <int N>
+HistoryHeader<N>::HistoryHeader ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryHeader<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+std::string
+HistoryHeader<N>::GetName (void) const
+{
+ std::ostringstream oss;
+ oss << N;
+ return oss.str ();
+}
+
+template <int N>
+void
+HistoryHeader<N>::Print (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+HistoryHeader<N>::Serialize (Buffer::Iterator start) const
+{
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::Deserialize (Buffer::Iterator start)
+{
+ m_ok = true;
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+template <int N>
+class HistoryTrailer : public Trailer
+{
+public:
+ static uint32_t GetUid (void);
+ HistoryTrailer ();
+ bool IsOk (void) const;
+ std::string GetName (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);
+private:
+ bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryTrailer<N>::GetUid (void)
+{
+ std::ostringstream oss;
+ oss << N << "HistoryTrailer.ns3";
+ static uint32_t uid = AllocateUid<HistoryTrailer<N> > (oss.str ());
+ return uid;
+}
+
+
+template <int N>
+HistoryTrailer<N>::HistoryTrailer ()
+ : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryTrailer<N>::IsOk (void) const
+{
+ return m_ok;
+}
+
+template <int N>
+std::string
+HistoryTrailer<N>::GetName (void) const
+{
+ std::ostringstream oss;
+ oss << N;
+ return oss.str ();
+}
+template <int N>
+void
+HistoryTrailer<N>::Print (std::ostream &os) const
+{
+ NS_ASSERT (false);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::GetSerializedSize (void) const
+{
+ return N;
+}
+template <int N>
+void
+HistoryTrailer<N>::Serialize (Buffer::Iterator start) const
+{
+ start.Prev (N);
+ start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::Deserialize (Buffer::Iterator start)
+{
+ m_ok = true;
+ start.Prev (N);
+ for (int i = 0; i < N; i++)
+ {
+ if (start.ReadU8 () != N)
+ {
+ m_ok = false;
+ }
+ }
+ return N;
+}
+
+
+
+class PacketMetadataTest : public Test {
+public:
+ PacketMetadataTest ();
+ virtual ~PacketMetadataTest ();
+ bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
+ virtual bool RunTests (void);
+private:
+ template <int N>
+ void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader<N> *header);
+ template <int N>
+ void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer<N> *trailer);
+ void PrintFragment (std::ostream &os,uint32_t packetUid,
+ uint32_t size,std::string & name,
+ struct PacketPrinter::FragmentInformation info);
+ void PrintPayload (std::ostream &os,uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info);
+ template <int N>
+ void RegisterHeader (void);
+ template <int N>
+ void RegisterTrailer (void);
+ void CleanupPrints (void);
+ Packet DoAddHeader (Packet p);
+ bool Check (const char *file, int line, std::list<int> expected);
+
+
+ bool m_headerError;
+ bool m_trailerError;
+ std::list<int> m_prints;
+ PacketPrinter m_printer;
+};
+
+PacketMetadataTest::PacketMetadataTest ()
+ : Test ("PacketMetadata")
+{
+ m_printer.SetPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this));
+ m_printer.SetSeparator ("");
+}
+
+PacketMetadataTest::~PacketMetadataTest ()
+{}
+
+template <int N>
+void
+PacketMetadataTest::RegisterHeader (void)
+{
+ static bool registered = false;
+ if (!registered)
+ {
+ m_printer.SetHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader<N>, this),
+ MakeCallback (&PacketMetadataTest::PrintFragment, this));
+ registered = true;
+ }
+}
+
+template <int N>
+void
+PacketMetadataTest::RegisterTrailer (void)
+{
+ static bool registered = false;
+ if (!registered)
+ {
+ m_printer.SetTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer<N>, this),
+ MakeCallback (&PacketMetadataTest::PrintFragment, this));
+ registered = true;
+ }
+}
+
+
+template <int N>
+void
+PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size,
+ const HistoryHeader<N> *header)
+{
+ if (!header->IsOk ())
+ {
+ m_headerError = true;
+ }
+ m_prints.push_back (N);
+}
+
+template <int N>
+void
+PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size,
+ const HistoryTrailer<N> *trailer)
+{
+ if (!trailer->IsOk ())
+ {
+ m_trailerError = true;
+ }
+ m_prints.push_back (N);
+}
+void
+PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid,
+ uint32_t size,std::string & name,
+ struct PacketPrinter::FragmentInformation info)
+{
+ m_prints.push_back (size - (info.end + info.start));
+}
+void
+PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid,
+ uint32_t size,
+ struct PacketPrinter::FragmentInformation info)
+{
+ m_prints.push_back (size - (info.end + info.start));
+}
+
+
+void
+PacketMetadataTest::CleanupPrints (void)
+{
+ m_prints.clear ();
+}
+
+bool
+PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
+{
+ if (m_headerError)
+ {
+ Failure () << "PacketMetadata header error. file=" << file
+ << ", line=" << line << std::endl;
+ return false;
+ }
+ if (m_trailerError)
+ {
+ Failure () << "PacketMetadata trailer error. file=" << file
+ << ", line=" << line << std::endl;
+ return false;
+ }
+ if (expected.size () != m_prints.size ())
+ {
+ goto error;
+ }
+ for (std::list<int>::iterator i = m_prints.begin (),
+ j = expected.begin ();
+ i != m_prints.end (); i++, j++)
+ {
+ NS_ASSERT (j != expected.end ());
+ if (*j != *i)
+ {
+ goto error;
+ }
+ }
+ return true;
+ error:
+ Failure () << "PacketMetadata error. file="<< file
+ << ", line=" << line << ", got:\"";
+ for (std::list<int>::iterator i = m_prints.begin ();
+ i != m_prints.end (); i++)
+ {
+ Failure () << *i << ", ";
+ }
+ Failure () << "\", expected: \"";
+ for (std::list<int>::iterator j = expected.begin ();
+ j != expected.end (); j++)
+ {
+ Failure () << *j << ", ";
+ }
+ Failure () << "\"" << std::endl;
+ return false;
+}
+
+bool
+PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
+{
+ m_headerError = false;
+ m_trailerError = false;
+ std::list<int> expected;
+ va_list ap;
+ va_start (ap, n);
+ for (uint32_t j = 0; j < n; j++)
+ {
+ int v = va_arg (ap, int);
+ expected.push_back (v);
+ }
+ va_end (ap);
+
+ m_printer.PrintForward ();
+ p.Print (Failure (), m_printer);
+ bool ok = Check (file, line, expected);
+ CleanupPrints ();
+ if (!ok)
+ {
+ return false;
+ }
+
+ m_printer.PrintBackward ();
+ p.Print (Failure (), m_printer);
+ expected.reverse ();
+ ok = Check (file, line, expected);
+ CleanupPrints ();
+ return ok;
+}
+
+#define ADD_HEADER(p, n) \
+ { \
+ HistoryHeader<n> header; \
+ RegisterHeader<n> (); \
+ p.AddHeader (header); \
+ }
+#define ADD_TRAILER(p, n) \
+ { \
+ HistoryTrailer<n> trailer; \
+ RegisterTrailer<n> (); \
+ p.AddTrailer (trailer); \
+ }
+#define REM_HEADER(p, n) \
+ { \
+ HistoryHeader<n> header; \
+ RegisterHeader<n> (); \
+ p.RemoveHeader (header); \
+ }
+#define REM_TRAILER(p, n) \
+ { \
+ HistoryTrailer<n> trailer; \
+ RegisterTrailer<n> (); \
+ p.RemoveTrailer (trailer); \
+ }
+#define CHECK_HISTORY(p, ...) \
+ { \
+ if (!CheckHistory (p, __FILE__, \
+ __LINE__, __VA_ARGS__)) \
+ { \
+ ok = false; \
+ } \
+ Buffer buffer; \
+ buffer = p.Serialize (); \
+ Packet otherPacket; \
+ otherPacket.Deserialize (buffer); \
+ if (!CheckHistory (otherPacket, __FILE__, \
+ __LINE__, __VA_ARGS__)) \
+ { \
+ ok = false; \
+ } \
+ }
+
+
+Packet
+PacketMetadataTest::DoAddHeader (Packet p)
+{
+ ADD_HEADER (p, 10);
+ return p;
+}
+
+bool
+PacketMetadataTest::RunTests (void)
+{
+ bool ok = true;
+
+ PacketMetadata::Enable ();
+
+ Packet p = Packet (0);
+ Packet p1 = Packet (0);
+
+ p = Packet (10);
+ ADD_TRAILER (p, 100);
+ CHECK_HISTORY (p, 2, 10, 100);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p, 5);
+ CHECK_HISTORY (p, 5,
+ 5, 3, 2, 1, 10);
+ ADD_HEADER (p, 6);
+ CHECK_HISTORY (p, 6,
+ 6, 5, 3, 2, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ CHECK_HISTORY (p, 3,
+ 2, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ REM_HEADER (p, 2);
+ CHECK_HISTORY (p, 2,
+ 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ REM_HEADER (p, 3);
+ REM_HEADER (p, 2);
+ REM_HEADER (p, 1);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 1);
+ ADD_HEADER (p, 2);
+ ADD_HEADER (p, 3);
+ p1 = p;
+ REM_HEADER (p1, 3);
+ REM_HEADER (p1, 2);
+ REM_HEADER (p1, 1);
+ CHECK_HISTORY (p1, 1, 10);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p1, 1);
+ ADD_HEADER (p1, 2);
+ CHECK_HISTORY (p1, 3,
+ 2, 1, 10);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 5,
+ 3, 3, 2, 1, 10);
+ ADD_TRAILER (p, 4);
+ CHECK_HISTORY (p, 6,
+ 3, 3, 2, 1, 10, 4);
+ ADD_TRAILER (p, 5);
+ CHECK_HISTORY (p, 7,
+ 3, 3, 2, 1, 10, 4, 5);
+ REM_HEADER (p, 3);
+ CHECK_HISTORY (p, 6,
+ 3, 2, 1, 10, 4, 5);
+ REM_TRAILER (p, 5);
+ CHECK_HISTORY (p, 5,
+ 3, 2, 1, 10, 4);
+ p1 = p;
+ REM_TRAILER (p, 4);
+ CHECK_HISTORY (p, 4,
+ 3, 2, 1, 10);
+ CHECK_HISTORY (p1, 5,
+ 3, 2, 1, 10, 4);
+ p1.RemoveAtStart (3);
+ CHECK_HISTORY (p1, 4,
+ 2, 1, 10, 4);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 4,
+ 1, 1, 10, 4);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 3,
+ 1, 10, 4);
+ p1.RemoveAtEnd (4);
+ CHECK_HISTORY (p1, 2,
+ 1, 10);
+ p1.RemoveAtStart (1);
+ CHECK_HISTORY (p1, 1, 10);
+
+ p = Packet (10);
+ ADD_HEADER (p, 8);
+ ADD_TRAILER (p, 8);
+ ADD_TRAILER (p, 8);
+ p.RemoveAtStart (8+10+8);
+ CHECK_HISTORY (p, 1, 8);
+
+ p = Packet (10);
+ ADD_HEADER (p, 10);
+ ADD_HEADER (p, 8);
+ ADD_TRAILER (p, 6);
+ ADD_TRAILER (p, 7);
+ ADD_TRAILER (p, 9);
+ p.RemoveAtStart (5);
+ p.RemoveAtEnd (12);
+ CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
+
+ p = Packet (10);
+ ADD_HEADER (p, 10);
+ ADD_TRAILER (p, 6);
+ p.RemoveAtEnd (18);
+ ADD_TRAILER (p, 5);
+ ADD_HEADER (p, 3);
+ CHECK_HISTORY (p, 3, 3, 8, 5);
+ p.RemoveAtStart (12);
+ CHECK_HISTORY (p, 1, 4);
+ p.RemoveAtEnd (2);
+ CHECK_HISTORY (p, 1, 2);
+ ADD_HEADER (p, 10);
+ CHECK_HISTORY (p, 2, 10, 2);
+ p.RemoveAtEnd (5);
+ CHECK_HISTORY (p, 1, 7);
+
+ Packet p2 = Packet (0);
+ Packet p3 = Packet (0);
+
+ p = Packet (40);
+ ADD_HEADER (p, 5);
+ ADD_HEADER (p, 8);
+ CHECK_HISTORY (p, 3, 8, 5, 40);
+ p1 = p.CreateFragment (0, 5);
+ p2 = p.CreateFragment (5, 5);
+ p3 = p.CreateFragment (10, 43);
+ CHECK_HISTORY (p1, 1, 5);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ CHECK_HISTORY (p3, 2, 3, 40);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 8, 2);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ p1.AddAtEnd (p3);
+ CHECK_HISTORY (p1, 3, 8, 5, 40);
+ CHECK_HISTORY (p2, 2, 3, 2);
+ CHECK_HISTORY (p3, 2, 3, 40);
+ p1 = p.CreateFragment (0, 5);
+ CHECK_HISTORY (p1, 1, 5);
+
+ p3 = Packet (50);
+ ADD_HEADER (p3, 8);
+ CHECK_HISTORY (p3, 2, 8, 50);
+ CHECK_HISTORY (p1, 1, 5);
+ p1.AddAtEnd (p3);
+ CHECK_HISTORY (p1, 3, 5, 8, 50);
+ ADD_HEADER (p1, 5);
+ CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
+ ADD_TRAILER (p1, 2);
+ CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
+ REM_HEADER (p1, 5);
+ CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
+ p1.RemoveAtEnd (60);
+ CHECK_HISTORY (p1, 1, 5);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 8, 2);
+ CHECK_HISTORY (p2, 2, 3, 2);
+
+ p3 = Packet (40);
+ ADD_HEADER (p3, 5);
+ ADD_HEADER (p3, 5);
+ CHECK_HISTORY (p3, 3, 5, 5, 40);
+ p1 = p3.CreateFragment (0, 5);
+ p2 = p3.CreateFragment (5, 5);
+ CHECK_HISTORY (p1, 1, 5);
+ CHECK_HISTORY (p2, 1, 5);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 5, 5);
+
+ p = Packet (0);
+ CHECK_HISTORY (p, 0);
+
+ p3 = Packet (0);
+ ADD_HEADER (p3, 5);
+ ADD_HEADER (p3, 5);
+ CHECK_HISTORY (p3, 2, 5, 5);
+ p1 = p3.CreateFragment (0, 4);
+ p2 = p3.CreateFragment (9, 1);
+ CHECK_HISTORY (p1, 1, 4);
+ CHECK_HISTORY (p2, 1, 1);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p1, 2, 4, 1);
+
+
+ p = Packet (2000);
+ CHECK_HISTORY (p, 1, 2000);
+
+ p = Packet ();
+ ADD_TRAILER (p, 10);
+ ADD_HEADER (p, 5);
+ p1 = p.CreateFragment (0, 8);
+ p2 = p.CreateFragment (8, 7);
+ p1.AddAtEnd (p2);
+ CHECK_HISTORY (p, 2, 5, 10);
+
+ p = Packet ();
+ ADD_TRAILER (p, 10);
+ REM_TRAILER (p, 10);
+ ADD_TRAILER (p, 10);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet ();
+ ADD_HEADER (p, 10);
+ REM_HEADER (p, 10);
+ ADD_HEADER (p, 10);
+ CHECK_HISTORY (p, 1, 10);
+
+ p = Packet ();
+ ADD_HEADER (p, 10);
+ p = DoAddHeader (p);
+ CHECK_HISTORY (p, 2, 10, 10);
+
+ return ok;
+}
+
+static PacketMetadataTest g_packetHistoryTest;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- a/src/common/packet-metadata.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-metadata.cc Wed Sep 05 18:35:39 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006,2007 INRIA
- * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,8 +23,8 @@
#include "ns3/fatal-error.h"
#include "ns3/debug.h"
#include "packet-metadata.h"
-#include "chunk.h"
#include "buffer.h"
+#include "chunk-registry.h"
NS_DEBUG_COMPONENT_DEFINE ("PacketMetadata");
@@ -965,19 +964,13 @@
NS_ASSERT (leftToRemove == 0);
}
-void
-PacketMetadata::PrintDefault (std::ostream &os, Buffer buffer) const
-{
- Print (os, buffer, PacketPrinter::GetDefault ());
-}
-
uint32_t
PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item,
const struct PacketMetadata::ExtraItem *extraItem,
Buffer data, uint32_t offset, const PacketPrinter &printer,
std::ostream &os) const
{
- uint32_t uid = item->typeUid & 0xfffffffe;
+ uint32_t uid = (item->typeUid & 0xfffffffe) >> 1;
if (uid == 0)
{
// payload.
@@ -992,13 +985,13 @@
extraItem->fragmentStart,
item->size - extraItem->fragmentEnd);
}
- else if (PacketPrinter::IsHeader (uid))
+ else if (ChunkRegistry::IsHeader (uid))
{
ns3::Buffer::Iterator j = data.Begin ();
j.Next (offset);
printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
}
- else if (PacketPrinter::IsTrailer (uid))
+ else if (ChunkRegistry::IsTrailer (uid))
{
ns3::Buffer::Iterator j = data.End ();
j.Prev (data.GetSize () - (offset + item->size));
@@ -1094,629 +1087,145 @@
}
}
-
-
-}; // namespace ns3
-
-#include <stdarg.h>
-#include <iostream>
-#include <sstream>
-#include "ns3/test.h"
-#include "header.h"
-#include "trailer.h"
-#include "packet.h"
-
-namespace ns3 {
-
-template <int N>
-class HistoryHeader : public Header
-{
-public:
- HistoryHeader ();
- bool IsOk (void) const;
-private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
- bool m_ok;
-};
-
-template <int N>
-HistoryHeader<N>::HistoryHeader ()
- : m_ok (false)
-{}
-
-template <int N>
-bool
-HistoryHeader<N>::IsOk (void) const
-{
- return m_ok;
-}
-
-template <int N>
-std::string
-HistoryHeader<N>::DoGetName (void) const
-{
- std::ostringstream oss;
- oss << N;
- return oss.str ();
-}
-
-template <int N>
-void
-HistoryHeader<N>::PrintTo (std::ostream &os) const
-{
- NS_ASSERT (false);
-}
-template <int N>
uint32_t
-HistoryHeader<N>::GetSerializedSize (void) const
-{
- return N;
-}
-template <int N>
-void
-HistoryHeader<N>::SerializeTo (Buffer::Iterator start) const
-{
- start.WriteU8 (N, N);
-}
-template <int N>
-uint32_t
-HistoryHeader<N>::DeserializeFrom (Buffer::Iterator start)
-{
- m_ok = true;
- for (int i = 0; i < N; i++)
- {
- if (start.ReadU8 () != N)
- {
- m_ok = false;
- }
- }
- return N;
-}
-
-template <int N>
-class HistoryTrailer : public Trailer
-{
-public:
- HistoryTrailer ();
- bool IsOk (void) const;
-private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
- bool m_ok;
-};
-
-template <int N>
-HistoryTrailer<N>::HistoryTrailer ()
- : m_ok (false)
-{}
-
-template <int N>
-bool
-HistoryTrailer<N>::IsOk (void) const
-{
- return m_ok;
-}
-
-template <int N>
-std::string
-HistoryTrailer<N>::DoGetName (void) const
-{
- std::ostringstream oss;
- oss << N;
- return oss.str ();
-}
-template <int N>
-void
-HistoryTrailer<N>::PrintTo (std::ostream &os) const
+PacketMetadata::GetSerializedSize (void) const
{
- NS_ASSERT (false);
-}
-template <int N>
-uint32_t
-HistoryTrailer<N>::GetSerializedSize (void) const
-{
- return N;
-}
-template <int N>
-void
-HistoryTrailer<N>::SerializeTo (Buffer::Iterator start) const
-{
- start.Prev (N);
- start.WriteU8 (N, N);
-}
-template <int N>
-uint32_t
-HistoryTrailer<N>::DeserializeFrom (Buffer::Iterator start)
-{
- m_ok = true;
- start.Prev (N);
- for (int i = 0; i < N; i++)
+ uint32_t totalSize = 0;
+ totalSize += 4;
+ if (!m_enable)
{
- if (start.ReadU8 () != N)
- {
- m_ok = false;
- }
+ return totalSize;
}
- return N;
-}
-
-
-
-class PacketMetadataTest : public Test {
-public:
- PacketMetadataTest ();
- virtual ~PacketMetadataTest ();
- bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
- virtual bool RunTests (void);
-private:
- template <int N>
- void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader<N> *header);
- template <int N>
- void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer<N> *trailer);
- void PrintFragment (std::ostream &os,uint32_t packetUid,
- uint32_t size,std::string & name,
- struct PacketPrinter::FragmentInformation info);
- void PrintDefault (std::ostream& os,uint32_t packetUid,
- uint32_t size,std::string& name,
- struct PacketPrinter::FragmentInformation info);
- void PrintPayload (std::ostream &os,uint32_t packetUid,
- uint32_t size,
- struct PacketPrinter::FragmentInformation info);
- template <int N>
- void RegisterHeader (void);
- template <int N>
- void RegisterTrailer (void);
- void CleanupPrints (void);
- bool Check (const char *file, int line, std::list<int> expected);
-
-
- bool m_headerError;
- bool m_trailerError;
- std::list<int> m_prints;
- PacketPrinter m_printer;
-};
-
-PacketMetadataTest::PacketMetadataTest ()
- : Test ("PacketMetadata")
-{
- m_printer.AddPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this));
- m_printer.AddDefaultPrinter (MakeCallback (&PacketMetadataTest::PrintDefault, this));
-}
-
-PacketMetadataTest::~PacketMetadataTest ()
-{}
-
-template <int N>
-void
-PacketMetadataTest::RegisterHeader (void)
-{
- static bool registered = false;
- if (!registered)
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t current = m_head;
+ while (current != 0xffff)
{
- m_printer.AddHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader<N>, this),
- MakeCallback (&PacketMetadataTest::PrintFragment, this));
- registered = true;
- }
-}
-
-template <int N>
-void
-PacketMetadataTest::RegisterTrailer (void)
-{
- static bool registered = false;
- if (!registered)
- {
- m_printer.AddTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer<N>, this),
- MakeCallback (&PacketMetadataTest::PrintFragment, this));
- registered = true;
+ ReadItems (current, &item, &extraItem);
+ uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+ if (uid == 0)
+ {
+ totalSize += 4;
+ }
+ else
+ {
+ totalSize += 4 + ChunkRegistry::GetUidStringFromUid (uid).size ();
+ }
+ totalSize += 1 + 4 + 2 + 4 + 4 + 4;
+ if (current == m_tail)
+ {
+ break;
+ }
+ NS_ASSERT (current != item.next);
+ current = item.next;
}
-}
-
-
-template <int N>
-void
-PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size,
- const HistoryHeader<N> *header)
-{
- if (!header->IsOk ())
- {
- m_headerError = true;
- }
- m_prints.push_back (N);
-}
-
-template <int N>
-void
-PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size,
- const HistoryTrailer<N> *trailer)
-{
- if (!trailer->IsOk ())
- {
- m_trailerError = true;
- }
- m_prints.push_back (N);
+ return totalSize;
}
void
-PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid,
- uint32_t size,std::string & name,
- struct PacketPrinter::FragmentInformation info)
+PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const
{
- m_prints.push_back (size - (info.end + info.start));
+ uint32_t bytesWritten = 0;
+ i.WriteU32 (size);
+ bytesWritten += 4;
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t current = m_head;
+ while (current != 0xffff)
+ {
+ ReadItems (current, &item, &extraItem);
+ NS_DEBUG ("bytesWritten=" << bytesWritten << ", typeUid="<<item.typeUid <<
+ ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+ ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<extraItem.fragmentEnd<<
+ ", packetUid="<<extraItem.packetUid);
+ uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+ if (uid != 0)
+ {
+ std::string uidString = ChunkRegistry::GetUidStringFromUid (uid);
+ i.WriteU32 (uidString.size ());
+ bytesWritten += 4;
+ i.Write ((uint8_t *)uidString.c_str (), uidString.size ());
+ bytesWritten += uidString.size ();
+ }
+ else
+ {
+ i.WriteU32 (0);
+ bytesWritten += 4;
+ }
+ uint8_t isBig = item.typeUid & 0x1;
+ i.WriteU8 (isBig);
+ bytesWritten += 1;
+ i.WriteU32 (item.size);
+ bytesWritten += 4;
+ i.WriteU16 (item.chunkUid);
+ bytesWritten += 2;
+ i.WriteU32 (extraItem.fragmentStart);
+ bytesWritten += 4;
+ i.WriteU32 (extraItem.fragmentEnd);
+ bytesWritten += 4;
+ i.WriteU32 (extraItem.packetUid);
+ bytesWritten += 4;
+ if (current == m_tail)
+ {
+ break;
+ }
+
+ NS_ASSERT (current != item.next);
+ current = item.next;
+ }
+ NS_ASSERT (bytesWritten == size);
}
-void
-PacketMetadataTest::PrintDefault (std::ostream& os,uint32_t packetUid,
- uint32_t size,std::string& name,
- struct PacketPrinter::FragmentInformation info)
+uint32_t
+PacketMetadata::Deserialize (Buffer::Iterator i)
{
- NS_ASSERT (false);
-}
-void
-PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid,
- uint32_t size,
- struct PacketPrinter::FragmentInformation info)
-{
- m_prints.push_back (size - (info.end + info.start));
+ struct PacketMetadata::SmallItem item;
+ struct PacketMetadata::ExtraItem extraItem;
+ uint32_t totalSize = i.ReadU32 ();
+ uint32_t size = totalSize;
+ size -= 4;
+ while (size > 0)
+ {
+ uint32_t uidStringSize = i.ReadU32 ();
+ size -= 4;
+ uint32_t uid;
+ if (uidStringSize == 0)
+ {
+ // uid zero for payload.
+ uid = 0;
+ }
+ else
+ {
+ std::string uidString;
+ for (uint32_t j = 0; j < uidStringSize; j++)
+ {
+ uidString.push_back (i.ReadU8 ());
+ size --;
+ }
+ uid = ChunkRegistry::GetUidFromUidString (uidString);
+ }
+ uint8_t isBig = i.ReadU8 ();
+ size --;
+ item.typeUid = (uid << 1) | isBig;
+ item.size = i.ReadU32 ();
+ size -= 4;
+ item.chunkUid = i.ReadU16 ();
+ size -= 2;
+ extraItem.fragmentStart = i.ReadU32 ();
+ size -= 4;
+ extraItem.fragmentEnd = i.ReadU32 ();
+ size -= 4;
+ extraItem.packetUid = i.ReadU32 ();
+ size -= 4;
+ NS_DEBUG ("size=" << size << ", typeUid="<<item.typeUid <<
+ ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+ ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<extraItem.fragmentEnd<<
+ ", packetUid="<<extraItem.packetUid);
+ uint32_t tmp = AddBig (0xffff, m_tail, &item, &extraItem);
+ UpdateTail (tmp);
+ }
+ NS_ASSERT (size == 0);
+ return totalSize;
}
-void
-PacketMetadataTest::CleanupPrints (void)
-{
- m_prints.clear ();
-}
-
-bool
-PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
-{
- if (m_headerError)
- {
- std::cout << "PacketMetadata header error. file=" << file
- << ", line=" << line << std::endl;
- return false;
- }
- if (m_trailerError)
- {
- std::cout << "PacketMetadata trailer error. file=" << file
- << ", line=" << line << std::endl;
- return false;
- }
- if (expected.size () != m_prints.size ())
- {
- goto error;
- }
- for (std::list<int>::iterator i = m_prints.begin (),
- j = expected.begin ();
- i != m_prints.end (); i++, j++)
- {
- NS_ASSERT (j != expected.end ());
- if (*j != *i)
- {
- goto error;
- }
- }
- return true;
- error:
- std::cout << "PacketMetadata error. file="<< file
- << ", line=" << line << ", got:\"";
- for (std::list<int>::iterator i = m_prints.begin ();
- i != m_prints.end (); i++)
- {
- std::cout << *i << ", ";
- }
- std::cout << "\", expected: \"";
- for (std::list<int>::iterator j = expected.begin ();
- j != expected.end (); j++)
- {
- std::cout << *j << ", ";
- }
- std::cout << "\"" << std::endl;
- return false;
-}
-
-bool
-PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
-{
- m_headerError = false;
- m_trailerError = false;
- std::list<int> expected;
- va_list ap;
- va_start (ap, n);
- for (uint32_t j = 0; j < n; j++)
- {
- int v = va_arg (ap, int);
- expected.push_back (v);
- }
- va_end (ap);
-
- m_printer.PrintForward ();
- p.Print (std::cerr, m_printer);
- bool ok = Check (file, line, expected);
- CleanupPrints ();
- if (!ok)
- {
- return false;
- }
-
- m_printer.PrintBackward ();
- p.Print (std::cerr, m_printer);
- expected.reverse ();
- ok = Check (file, line, expected);
- CleanupPrints ();
- return ok;
-}
-
-#define ADD_HEADER(p, n) \
- { \
- HistoryHeader<n> header; \
- RegisterHeader<n> (); \
- p.AddHeader (header); \
- }
-#define ADD_TRAILER(p, n) \
- { \
- HistoryTrailer<n> trailer; \
- RegisterTrailer<n> (); \
- p.AddTrailer (trailer); \
- }
-#define REM_HEADER(p, n) \
- { \
- HistoryHeader<n> header; \
- RegisterHeader<n> (); \
- p.RemoveHeader (header); \
- }
-#define REM_TRAILER(p, n) \
- { \
- HistoryTrailer<n> trailer; \
- RegisterTrailer<n> (); \
- p.RemoveTrailer (trailer); \
- }
-#define CHECK_HISTORY(p, ...) \
- { \
- if (!CheckHistory (p, __FILE__, \
- __LINE__, __VA_ARGS__)) \
- { \
- ok = false; \
- } \
- }
-
-bool
-PacketMetadataTest::RunTests (void)
-{
- bool ok = true;
-
- PacketMetadata::Enable ();
-
- Packet p = Packet (0);
- Packet p1 = Packet (0);
-
- p = Packet (10);
- ADD_TRAILER (p, 100);
- CHECK_HISTORY (p, 2, 10, 100);
-
- p = Packet (10);
- ADD_HEADER (p, 1);
- ADD_HEADER (p, 2);
- ADD_HEADER (p, 3);
- CHECK_HISTORY (p, 4,
- 3, 2, 1, 10);
- ADD_HEADER (p, 5);
- CHECK_HISTORY (p, 5,
- 5, 3, 2, 1, 10);
- ADD_HEADER (p, 6);
- CHECK_HISTORY (p, 6,
- 6, 5, 3, 2, 1, 10);
-
- p = Packet (10);
- ADD_HEADER (p, 1);
- ADD_HEADER (p, 2);
- ADD_HEADER (p, 3);
- REM_HEADER (p, 3);
- CHECK_HISTORY (p, 3,
- 2, 1, 10);
-
- p = Packet (10);
- ADD_HEADER (p, 1);
- ADD_HEADER (p, 2);
- ADD_HEADER (p, 3);
- REM_HEADER (p, 3);
- REM_HEADER (p, 2);
- CHECK_HISTORY (p, 2,
- 1, 10);
-
- p = Packet (10);
- ADD_HEADER (p, 1);
- ADD_HEADER (p, 2);
- ADD_HEADER (p, 3);
- REM_HEADER (p, 3);
- REM_HEADER (p, 2);
- REM_HEADER (p, 1);
- CHECK_HISTORY (p, 1, 10);
+} // namespace ns3
- p = Packet (10);
- ADD_HEADER (p, 1);
- ADD_HEADER (p, 2);
- ADD_HEADER (p, 3);
- p1 = p;
- REM_HEADER (p1, 3);
- REM_HEADER (p1, 2);
- REM_HEADER (p1, 1);
- CHECK_HISTORY (p1, 1, 10);
- CHECK_HISTORY (p, 4,
- 3, 2, 1, 10);
- ADD_HEADER (p1, 1);
- ADD_HEADER (p1, 2);
- CHECK_HISTORY (p1, 3,
- 2, 1, 10);
- CHECK_HISTORY (p, 4,
- 3, 2, 1, 10);
- ADD_HEADER (p, 3);
- CHECK_HISTORY (p, 5,
- 3, 3, 2, 1, 10);
- ADD_TRAILER (p, 4);
- CHECK_HISTORY (p, 6,
- 3, 3, 2, 1, 10, 4);
- ADD_TRAILER (p, 5);
- CHECK_HISTORY (p, 7,
- 3, 3, 2, 1, 10, 4, 5);
- REM_HEADER (p, 3);
- CHECK_HISTORY (p, 6,
- 3, 2, 1, 10, 4, 5);
- REM_TRAILER (p, 5);
- CHECK_HISTORY (p, 5,
- 3, 2, 1, 10, 4);
- p1 = p;
- REM_TRAILER (p, 4);
- CHECK_HISTORY (p, 4,
- 3, 2, 1, 10);
- CHECK_HISTORY (p1, 5,
- 3, 2, 1, 10, 4);
- p1.RemoveAtStart (3);
- CHECK_HISTORY (p1, 4,
- 2, 1, 10, 4);
- p1.RemoveAtStart (1);
- CHECK_HISTORY (p1, 4,
- 1, 1, 10, 4);
- p1.RemoveAtStart (1);
- CHECK_HISTORY (p1, 3,
- 1, 10, 4);
- p1.RemoveAtEnd (4);
- CHECK_HISTORY (p1, 2,
- 1, 10);
- p1.RemoveAtStart (1);
- CHECK_HISTORY (p1, 1, 10);
-
- p = Packet (10);
- ADD_HEADER (p, 8);
- ADD_TRAILER (p, 8);
- ADD_TRAILER (p, 8);
- p.RemoveAtStart (8+10+8);
- CHECK_HISTORY (p, 1, 8);
-
- p = Packet (10);
- ADD_HEADER (p, 10);
- ADD_HEADER (p, 8);
- ADD_TRAILER (p, 6);
- ADD_TRAILER (p, 7);
- ADD_TRAILER (p, 9);
- p.RemoveAtStart (5);
- p.RemoveAtEnd (12);
- CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
-
- p = Packet (10);
- ADD_HEADER (p, 10);
- ADD_TRAILER (p, 6);
- p.RemoveAtEnd (18);
- ADD_TRAILER (p, 5);
- ADD_HEADER (p, 3);
- CHECK_HISTORY (p, 3, 3, 8, 5);
- p.RemoveAtStart (12);
- CHECK_HISTORY (p, 1, 4);
- p.RemoveAtEnd (2);
- CHECK_HISTORY (p, 1, 2);
- ADD_HEADER (p, 10);
- CHECK_HISTORY (p, 2, 10, 2);
- p.RemoveAtEnd (5);
- CHECK_HISTORY (p, 1, 7);
-
- Packet p2 = Packet (0);
- Packet p3 = Packet (0);
-
- p = Packet (40);
- ADD_HEADER (p, 5);
- ADD_HEADER (p, 8);
- CHECK_HISTORY (p, 3, 8, 5, 40);
- p1 = p.CreateFragment (0, 5);
- p2 = p.CreateFragment (5, 5);
- p3 = p.CreateFragment (10, 43);
- CHECK_HISTORY (p1, 1, 5);
- CHECK_HISTORY (p2, 2, 3, 2);
- CHECK_HISTORY (p3, 2, 3, 40);
- p1.AddAtEnd (p2);
- CHECK_HISTORY (p1, 2, 8, 2);
- CHECK_HISTORY (p2, 2, 3, 2);
- p1.AddAtEnd (p3);
- CHECK_HISTORY (p1, 3, 8, 5, 40);
- CHECK_HISTORY (p2, 2, 3, 2);
- CHECK_HISTORY (p3, 2, 3, 40);
- p1 = p.CreateFragment (0, 5);
- CHECK_HISTORY (p1, 1, 5);
-
- p3 = Packet (50);
- ADD_HEADER (p3, 8);
- CHECK_HISTORY (p3, 2, 8, 50);
- CHECK_HISTORY (p1, 1, 5);
- p1.AddAtEnd (p3);
- CHECK_HISTORY (p1, 3, 5, 8, 50);
- ADD_HEADER (p1, 5);
- CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
- ADD_TRAILER (p1, 2);
- CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
- REM_HEADER (p1, 5);
- CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
- p1.RemoveAtEnd (60);
- CHECK_HISTORY (p1, 1, 5);
- p1.AddAtEnd (p2);
- CHECK_HISTORY (p1, 2, 8, 2);
- CHECK_HISTORY (p2, 2, 3, 2);
-
- p3 = Packet (40);
- ADD_HEADER (p3, 5);
- ADD_HEADER (p3, 5);
- CHECK_HISTORY (p3, 3, 5, 5, 40);
- p1 = p3.CreateFragment (0, 5);
- p2 = p3.CreateFragment (5, 5);
- CHECK_HISTORY (p1, 1, 5);
- CHECK_HISTORY (p2, 1, 5);
- p1.AddAtEnd (p2);
- CHECK_HISTORY (p1, 2, 5, 5);
-
- p = Packet (0);
- CHECK_HISTORY (p, 0);
-
- p3 = Packet (0);
- ADD_HEADER (p3, 5);
- ADD_HEADER (p3, 5);
- CHECK_HISTORY (p3, 2, 5, 5);
- p1 = p3.CreateFragment (0, 4);
- p2 = p3.CreateFragment (9, 1);
- CHECK_HISTORY (p1, 1, 4);
- CHECK_HISTORY (p2, 1, 1);
- p1.AddAtEnd (p2);
- CHECK_HISTORY (p1, 2, 4, 1);
-
-
- p = Packet (2000);
- CHECK_HISTORY (p, 1, 2000);
-
- p = Packet ();
- ADD_TRAILER (p, 10);
- ADD_HEADER (p, 5);
- p1 = p.CreateFragment (0, 8);
- p2 = p.CreateFragment (8, 7);
- p1.AddAtEnd (p2);
- CHECK_HISTORY (p, 2, 5, 10);
-
- p = Packet ();
- ADD_TRAILER (p, 10);
- REM_TRAILER (p, 10);
- ADD_TRAILER (p, 10);
- CHECK_HISTORY (p, 1, 10);
-
- p = Packet ();
- ADD_HEADER (p, 10);
- REM_HEADER (p, 10);
- ADD_HEADER (p, 10);
- CHECK_HISTORY (p, 1, 10);
-
- return ok;
-}
-
-static PacketMetadataTest g_packetHistoryTest;
-
-}//namespace ns3
--- a/src/common/packet-metadata.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-metadata.h Wed Sep 05 18:35:39 2007 +0100
@@ -100,9 +100,12 @@
uint32_t GetUid (void) const;
- void PrintDefault (std::ostream &os, Buffer buffer) const;
void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator i, uint32_t size) const;
+ uint32_t Deserialize (Buffer::Iterator i);
+
static void PrintStats (void);
private:
@@ -254,26 +257,26 @@
void
PacketMetadata::AddHeader (T const &header, uint32_t size)
{
- DoAddHeader (PacketPrinter::GetHeaderUid<T> (), size);
+ DoAddHeader (T::GetUid () << 1, size);
}
template <typename T>
void
PacketMetadata::RemoveHeader (T const &header, uint32_t size)
{
- DoRemoveHeader (PacketPrinter::GetHeaderUid<T> (), size);
+ DoRemoveHeader (T::GetUid () << 1, size);
}
template <typename T>
void
PacketMetadata::AddTrailer (T const &trailer, uint32_t size)
{
- DoAddTrailer (PacketPrinter::GetTrailerUid<T> (), size);
+ DoAddTrailer (T::GetUid () << 1, size);
}
template <typename T>
void
PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size)
{
- DoRemoveTrailer (PacketPrinter::GetTrailerUid<T> (), size);
+ DoRemoveTrailer (T::GetUid () << 1, size);
}
@@ -303,24 +306,23 @@
PacketMetadata &
PacketMetadata::operator = (PacketMetadata const& o)
{
- if (m_data == o.m_data)
+ if (m_data != o.m_data)
{
- // self assignment
- return *this;
+ // not self assignment
+ NS_ASSERT (m_data != 0);
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ PacketMetadata::Recycle (m_data);
+ }
+ m_data = o.m_data;
+ NS_ASSERT (m_data != 0);
+ m_data->m_count++;
}
- NS_ASSERT (m_data != 0);
- m_data->m_count--;
- if (m_data->m_count == 0)
- {
- PacketMetadata::Recycle (m_data);
- }
- m_data = o.m_data;
m_head = o.m_head;
m_tail = o.m_tail;
m_used = o.m_used;
m_packetUid = o.m_packetUid;
- NS_ASSERT (m_data != 0);
- m_data->m_count++;
return *this;
}
PacketMetadata::~PacketMetadata ()
--- a/src/common/packet-printer.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-printer.cc Wed Sep 05 18:35:39 2007 +0100
@@ -20,12 +20,13 @@
*/
#include "packet-printer.h"
+#include "chunk-registry.h"
namespace ns3 {
PacketPrinter::PacketPrinter ()
: m_forward (true),
- m_separator ("")
+ m_separator (" ")
{}
void
@@ -44,44 +45,10 @@
m_separator = separator;
}
void
-PacketPrinter::AddPayloadPrinter (PayloadPrinter printer)
+PacketPrinter::SetPayloadPrinter (PayloadPrinter printer)
{
m_payloadPrinter = printer;
}
-void
-PacketPrinter::AddDefaultPrinter (DefaultPrinter printer)
-{
- m_defaultPrinter = printer;
-}
-
-PacketPrinter::RegisteredChunks *
-PacketPrinter::GetRegisteredChunks (void)
-{
- static RegisteredChunks registeredChunks;
- return ®isteredChunks;
-}
-
-PacketPrinter
-PacketPrinter::GetDefault (void)
-{
- return *(PacketPrinter::PeekDefault ());
-}
-PacketPrinter *
-PacketPrinter::PeekDefault (void)
-{
- static PacketPrinter *tmp = PacketPrinter::CreateStaticDefault ();
- return tmp;
-}
-PacketPrinter *
-PacketPrinter::CreateStaticDefault (void)
-{
- static PacketPrinter tmp;
- tmp.PrintForward ();
- tmp.AddPayloadPrinter (MakeCallback (&PacketPrinter::DoDefaultPrintPayload));
- tmp.SetSeparator (" ");
- return &tmp;
-}
-
void
PacketPrinter::PrintChunk (uint32_t chunkUid,
@@ -90,26 +57,22 @@
uint32_t packetUid,
uint32_t size) const
{
- RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
- NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
+ uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+ ChunkRegistry::Deserialize (chunkUid, instance, start);
+
for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
{
if (i->m_chunkUid == chunkUid)
{
- DoPrintCallback cb = (*registeredChunks)[chunkUid/2-1].printCallback;
- cb (i->m_printer, start, os, packetUid, size);
+ ChunkRegistry::InvokePrintCallback (chunkUid, instance, os, packetUid, size, i->m_printer);
return;
}
}
- DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
- std::string name = cb ();
- struct PacketPrinter::FragmentInformation info;
- info.start = 0;
- info.end = 0;
- if (!m_defaultPrinter.IsNull ())
- {
- m_defaultPrinter (os, packetUid, size, name, info);
- }
+ // if the over did not override this type of chunk,
+ // we print something by default.
+ std::string name = ChunkRegistry::GetName (chunkUid, instance);
+ os << name;
+ ChunkRegistry::Print (chunkUid, instance, os);
}
void
PacketPrinter::PrintChunkFragment (uint32_t chunkUid,
@@ -119,10 +82,8 @@
uint32_t fragmentStart,
uint32_t fragmentEnd) const
{
- RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
- NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
- DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
- std::string name = cb ();
+ uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+ std::string name = ChunkRegistry::GetName (chunkUid, instance);
struct PacketPrinter::FragmentInformation info;
info.start = fragmentStart;
info.end = fragmentEnd;
@@ -130,14 +91,20 @@
{
if (i->m_chunkUid == chunkUid)
{
+
i->m_fragmentPrinter (os, packetUid, size, name, info);
return;
}
}
- if (!m_defaultPrinter.IsNull ())
- {
- m_defaultPrinter (os, packetUid, size, name, info);
- }
+ // if the user did not override this type of chunk,
+ // we print something by default.
+ NS_ASSERT (info.start != 0 || info.end != 0);
+ os << name << " "
+ << "("
+ << "length " << size - (info.end + info.start) << " "
+ << "trim_start " << info.start << " "
+ << "trim_end " << info.end
+ << ")";
}
void
PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
@@ -149,15 +116,10 @@
if (!m_payloadPrinter.IsNull ())
{
m_payloadPrinter (os, packetUid, size, info);
+ return;
}
-}
-
-void
-PacketPrinter::DoDefaultPrintPayload (std::ostream & os,
- uint32_t packetUid,
- uint32_t size,
- struct PacketPrinter::FragmentInformation info)
-{
+ // if the user did not override the payload printer,
+ // we print something anyway.
os << "DATA ("
<< "length " << size - (info.end + info.start);
if (info.start != 0 || info.end != 0)
@@ -167,69 +129,7 @@
<< "trim_end " << info.end;
}
os << ")";
-}
-void
-PacketPrinter::DoDefaultPrintDefault (std::ostream & os,
- uint32_t packetUid,
- uint32_t size,
- std::string &name,
- struct PacketPrinter::FragmentInformation info)
-{
- NS_ASSERT_MSG (false, "This should never happen because we provide a printer for _all_ chunk types.");
-}
-
-void
-PacketPrinter::DoDefaultPrintFragment (std::ostream & os,
- uint32_t packetUid,
- uint32_t size,
- std::string &name,
- struct PacketPrinter::FragmentInformation info)
-{
- NS_ASSERT (info.start != 0 || info.end != 0);
- os << name << " "
- << "("
- << "length " << size - (info.end + info.start) << " "
- << "trim_start " << info.start << " "
- << "trim_end " << info.end
- << ")"
- ;
}
-void
-PacketPrinter::DoAddPrinter (uint32_t uid,
- Ptr<CallbackImplBase> printer,
- Callback<void,
- std::ostream &,
- uint32_t,
- uint32_t,
- std::string &,
- struct PacketPrinter::FragmentInformation> fragmentPrinter)
-{
- struct PacketPrinter::Printer p;
- p.m_chunkUid = uid;
- p.m_printer = printer;
- p.m_fragmentPrinter = fragmentPrinter;
- m_printerList.push_back (p);
-}
-
-bool
-PacketPrinter::IsTrailer (uint32_t uid)
-{
- RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
- NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
- bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
- return !isHeader;
-}
-bool
-PacketPrinter::IsHeader (uint32_t uid)
-{
- RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
- NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
- bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
- return isHeader;
-}
-
-
-
} // namespace ns3
--- a/src/common/packet-printer.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-printer.h Wed Sep 05 18:35:39 2007 +0100
@@ -26,14 +26,8 @@
#include "buffer.h"
#include <vector>
-namespace {
- class ItemList;
-}
-
namespace ns3 {
-class Chunk;
-
/**
* \brief hold a list of print callbacks for packet headers and trailers
*
@@ -92,99 +86,38 @@
* Print the content of the packet backward.
*/
void PrintBackward (void);
+ /**
+ * \param separator the new separator
+ *
+ * The default separator is a single space character.
+ */
void SetSeparator (std::string separator);
/**
* \param printer printer for payload
*/
- void AddPayloadPrinter (PayloadPrinter printer);
+ void SetPayloadPrinter (PayloadPrinter printer);
/**
* \param printer printer for the specified chunk
* \param fragmentPrinter printer for a fragment of the specified chunk
*
- * If the user has not specified a callback for a specific header present
- * in a packet, the "default" callback is invoked. If no such callback
- * was specified, nothing happens.
+ * If the user does not force a user-specific printing function through
+ * a call to SetHeaderPrinter, the default print output is generated.
*/
template <typename T>
- void AddHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ void SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
ChunkFragmentPrinter fragmentPrinter);
/**
* \param printer printer for the specified chunk
* \param fragmentPrinter printer for a fragment of the specified chunk
*
- * If the user has not specified a callback for a specific trailer present
- * in a packet, the "default" callback is invoked. If no such callback
- * was specified, nothing happens.
+ * If the user does not force a user-specific printing function through
+ * a call to SetTrailerPrinter, the default print output is generated.
*/
template <typename T>
- void AddTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
- ChunkFragmentPrinter fragmentPrinter);
- /**
- * \param printer printer for a chunk for which no callback was specified explicitely
- */
- void AddDefaultPrinter (DefaultPrinter printer);
-
+ void SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter);
private:
friend class PacketMetadata;
- typedef void (*DoPrintCallback) (Ptr<CallbackImplBase>, Buffer::Iterator, std::ostream &,
- uint32_t, uint32_t);
- typedef std::string (*DoGetNameCallback) (void);
- struct Printer
- {
- uint32_t m_chunkUid;
- Ptr<CallbackImplBase> m_printer;
- Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
- m_fragmentPrinter;
- };
- struct RegisteredChunk
- {
- DoPrintCallback printCallback;
- DoGetNameCallback getNameCallback;
- bool isHeader;
- };
- typedef std::vector<struct PacketPrinter::Printer> PrinterList;
- typedef std::vector<struct RegisteredChunk> RegisteredChunks;
-
-
- static PacketPrinter GetDefault (void);
- static PacketPrinter *PeekDefault (void);
- static PacketPrinter *CreateStaticDefault (void);
- static void DoDefaultPrintPayload (std::ostream & os,
- uint32_t packetUid,
- uint32_t size,
- struct PacketPrinter::FragmentInformation info);
- static void DoDefaultPrintDefault (std::ostream & os,
- uint32_t packetUid,
- uint32_t size,
- std::string &name,
- struct PacketPrinter::FragmentInformation info);
- template <typename T>
- static void DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk);
- static void DoDefaultPrintFragment (std::ostream & os,
- uint32_t packetUid,
- uint32_t size,
- std::string &name,
- struct PacketPrinter::FragmentInformation info);
-
- template <typename T>
- static void DoPrint (Ptr<CallbackImplBase> callbackPrinter,
- Buffer::Iterator i,
- std::ostream &os,
- uint32_t packetUid,
- uint32_t size);
- template <typename T>
- static std::string DoGetName (void);
- template <typename T>
- static uint32_t GetTrailerUid (void);
- template <typename T>
- static uint32_t GetHeaderUid (void);
- template <typename T>
- static uint32_t AllocateUid (bool isHeader);
- static RegisteredChunks *GetRegisteredChunks (void);
- static bool IsTrailer (uint32_t uid);
- static bool IsHeader (uint32_t uid);
-
-
void PrintChunk (uint32_t uid,
Buffer::Iterator i,
std::ostream &os,
@@ -198,16 +131,15 @@
uint32_t fragmentEnd) const;
void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
uint32_t fragmentStart, uint32_t fragmentEnd) const;
- void DoAddPrinter (uint32_t uid,
- Ptr<CallbackImplBase> printer,
- Callback<void,
- std::ostream &,
- uint32_t,
- uint32_t,
- std::string &,
- struct PacketPrinter::FragmentInformation> fragmentPrinter);
-
- static PacketPrinter m_defaultPacketPrinter;
+ struct Printer
+ {
+ uint32_t m_chunkUid;
+ Ptr<CallbackImplBase> m_printer;
+ Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,
+ struct PacketPrinter::FragmentInformation> m_fragmentPrinter;
+ };
+ typedef std::vector<struct PacketPrinter::Printer> PrinterList;
+
PrinterList m_printerList;
PayloadPrinter m_payloadPrinter;
DefaultPrinter m_defaultPrinter;
@@ -221,97 +153,28 @@
template <typename T>
void
-PacketPrinter::AddHeaderPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
- Callback<void,
- std::ostream &,
- uint32_t,
- uint32_t,
- std::string &,
- struct PacketPrinter::FragmentInformation> fragmentPrinter)
+PacketPrinter::SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter)
{
- static uint32_t uid = PacketPrinter::GetHeaderUid<T> ();
- DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
+ Printer p;
+ p.m_chunkUid = T::GetUid ();
+ p.m_printer = printer.GetImpl ();
+ p.m_fragmentPrinter = fragmentPrinter;
+ m_printerList.push_back (p);
}
template <typename T>
void
-PacketPrinter::AddTrailerPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
- Callback<void,
- std::ostream &,
- uint32_t,
- uint32_t,
- std::string &,
- struct PacketPrinter::FragmentInformation> fragmentPrinter)
+PacketPrinter::SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+ ChunkFragmentPrinter fragmentPrinter)
{
- static uint32_t uid = PacketPrinter::GetTrailerUid<T> ();
- DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
-}
-
-template <typename T>
-void
-PacketPrinter::DoPrint (Ptr<CallbackImplBase> printerCallback,
- Buffer::Iterator i,
- std::ostream &os,
- uint32_t packetUid,
- uint32_t size)
-{
- T chunk = T ();
- chunk.Deserialize (i);
- Callback<void,std::ostream&,uint32_t,uint32_t,const T*> callback;
- callback.Assign (printerCallback);
- callback (os, packetUid, size, &chunk);
-}
-
-template <typename T>
-std::string
-PacketPrinter::DoGetName (void)
-{
- T chunk = T ();
- return chunk.GetName ();
+ Printer p;
+ p.m_chunkUid = T::GetUid ();
+ p.m_printer = printer.GetImpl ();
+ p.m_fragmentPrinter = fragmentPrinter;
+ m_printerList.push_back (p);
}
-template <typename T>
-uint32_t
-PacketPrinter::GetHeaderUid (void)
-{
- static uint32_t uid = PacketPrinter::AllocateUid<T> (true);
- return uid;
-}
-
-template <typename T>
-uint32_t
-PacketPrinter::GetTrailerUid (void)
-{
- static uint32_t uid = PacketPrinter::AllocateUid<T> (false);
- return uid;
-}
-
-template <typename T>
-uint32_t
-PacketPrinter::AllocateUid (bool isHeader)
-{
- RegisteredChunks *chunks = PacketPrinter::GetRegisteredChunks ();
- RegisteredChunk chunk;
- chunk.printCallback = &PacketPrinter::DoPrint<T>;
- chunk.getNameCallback = &PacketPrinter::DoGetName<T>;
- chunk.isHeader = isHeader;
- chunks->push_back (chunk);
- uint32_t uid = chunks->size () * 2;
- PacketPrinter::PeekDefault ()->DoAddPrinter (uid,
- MakeCallback (&PacketPrinter::DoDefaultPrint<T>).GetImpl (),
- MakeCallback (&PacketPrinter::DoDefaultPrintFragment));
- return uid;
-}
-
-template <typename T>
-void
-PacketPrinter::DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk)
-{
- os << chunk->GetName () << " ";
- chunk->Print (os);
-}
-
-
} // namespace ns3
--- a/src/common/packet.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet.cc Wed Sep 05 18:35:39 2007 +0100
@@ -74,14 +74,14 @@
void
Packet::AddAtEnd (Packet packet)
{
- packet.m_buffer.TransformIntoRealBuffer ();
- m_buffer.TransformIntoRealBuffer ();
+ Buffer src = packet.m_buffer.CreateFullCopy ();
+ Buffer dst = m_buffer.CreateFullCopy ();
- Buffer src = packet.m_buffer;
- m_buffer.AddAtEnd (src.GetSize ());
- Buffer::Iterator destStart = m_buffer.End ();
+ dst.AddAtEnd (src.GetSize ());
+ Buffer::Iterator destStart = dst.End ();
destStart.Prev (src.GetSize ());
destStart.Write (src.Begin (), src.End ());
+ m_buffer = dst;
/**
* XXX: we might need to merge the tag list of the
* other packet into the current packet.
@@ -126,9 +126,15 @@
}
void
+Packet::PrintTags (std::ostream &os) const
+{
+ m_tags.Print (os, " ");
+}
+
+void
Packet::Print (std::ostream &os) const
{
- m_metadata.PrintDefault (os, m_buffer);
+ m_metadata.Print (os, m_buffer, PacketPrinter ());
}
void
@@ -143,7 +149,58 @@
PacketMetadata::Enable ();
}
-}; // namespace ns3
+Buffer
+Packet::Serialize (void) const
+{
+ Buffer buffer;
+ uint32_t reserve;
+
+ // write metadata
+ reserve = m_metadata.GetSerializedSize ();
+ buffer.AddAtStart (reserve);
+ m_metadata.Serialize (buffer.Begin (), reserve);
+
+ // write tags
+ reserve = m_tags.GetSerializedSize ();
+ buffer.AddAtStart (reserve);
+ m_tags.Serialize (buffer.Begin (), reserve);
+
+ // aggregate byte buffer, metadata, and tags
+ Buffer tmp = m_buffer.CreateFullCopy ();
+ buffer.AddAtStart (tmp.GetSize ());
+ buffer.Begin ().Write (tmp.Begin (), tmp.End ());
+
+ // write byte buffer size.
+ buffer.AddAtStart (4);
+ buffer.Begin ().WriteU32 (m_buffer.GetSize ());
+
+ return buffer;
+}
+void
+Packet::Deserialize (Buffer buffer)
+{
+ Buffer buf = buffer;
+ // read size
+ uint32_t packetSize = buf.Begin ().ReadU32 ();
+ buf.RemoveAtStart (4);
+
+ // read buffer.
+ buf.RemoveAtEnd (buf.GetSize () - packetSize);
+ m_buffer = buf;
+
+ // read tags
+ buffer.RemoveAtStart (4 + packetSize);
+ uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
+ buffer.RemoveAtStart (tagsDeserialized);
+
+ // read metadata
+ uint32_t metadataDeserialized =
+ m_metadata.Deserialize (buffer.Begin ());
+ buffer.RemoveAtStart (metadataDeserialized);
+}
+
+
+} // namespace ns3
--- a/src/common/packet.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet.h Wed Sep 05 18:35:39 2007 +0100
@@ -27,6 +27,7 @@
#include "trailer.h"
#include "tags.h"
#include "packet-metadata.h"
+#include "tag.h"
#include "ns3/callback.h"
#include "ns3/assert.h"
@@ -37,12 +38,15 @@
/**
* \brief network packets
*
- * Each network packet contains a byte buffer and a list of tags.
+ * Each network packet contains a byte buffer, a list of tags, and
+ * metadata.
+ *
* - The byte buffer stores the serialized content of the headers and trailers
* added to a packet. The serialized representation of these headers is expected
* to match that of real network packets bit for bit (although nothing
* forces you to do this) which means that the content of a packet buffer
* is expected to be that of a real packet.
+ *
* - The list of tags stores an arbitrarily large set of arbitrary
* user-provided data structures in the packet: only one instance of
* each type of data structure is allowed in a list of tags.
@@ -51,43 +55,22 @@
* 16 bytes big. Trying to attach bigger data structures will trigger
* crashes at runtime.
*
- * Implementing a new type of Header for a new protocol is pretty easy
- * and is a matter of creating a subclass of the ns3::Header base class,
- * and implementing the 4 pure virtual methods defined in ns3::Header.
- * Sample code which shows how to create such a new Header, how to use
- * it, and how to manipulate tags is shown below:
- * \include samples/main-packet.cc
- *
- * The current implementation of the byte buffers and tag list is based
- * on COW (Copy On Write. An introduction to COW can be found in Scott
- * Meyer's "More Effective C++", items 17 and 29). What this means is that
- * copying packets without modifying them is very cheap (in terms of cpu
- * and memory usage) and modifying them can be also very cheap. What is
- * key for proper COW implementations is being
- * able to detect when a given modification of the state of a packet triggers
- * a full copy of the data prior to the modification: COW systems need
- * to detect when an operation is "dirty".
+ * - The metadata describes the type of the headers and trailers which
+ * were serialized in the byte buffer. The maintenance of metadata is
+ * optional and disabled by default. To enable it, you must call
+ * Packet::EnableMetadata and this will allow you to get non-empty
+ * output from Packet::Print and Packet::Print.
*
- * Dirty operations:
- * - ns3::Packet::RemoveTag
- * - ns3::Packet::Add
- * - both versions of ns3::Packet::AddAtEnd
+ * Implementing a new type of Header or Trailer for a new protocol is
+ * pretty easy and is a matter of creating a subclass of the ns3::Header
+ * or of the ns3::Trailer base class, and implementing the methods
+ * described in their respective API documentation.
*
- * Non-dirty operations:
- * - ns3::Packet::AddTag
- * - ns3::Packet::RemoveAllTags
- * - ns3::Packet::PeekTag
- * - ns3::Packet::Peek
- * - ns3::Packet::Remove
- * - ns3::Packet::CreateFragment
- * - ns3::Packet::RemoveAtStart
- * - ns3::Packet::RemoveAtEnd
+ * Implementing a new type of Tag requires roughly the same amount of
+ * work and this work is described in the ns3::Tag API documentation.
*
- * Dirty operations will always be slower than non-dirty operations,
- * sometimes by several orders of magnitude. However, even the
- * dirty operations have been optimized for common use-cases which
- * means that most of the time, these operations will not trigger
- * data copies and will thus be still very fast.
+ * The performance aspects of the Packet API are discussed in
+ * \ref packetperf
*/
class Packet {
public:
@@ -132,7 +115,7 @@
uint32_t GetSize (void) const;
/**
* Add header to this packet. This method invokes the
- * ns3::Chunk::GetSerializedSize and ns3::Chunk::SerializeTo
+ * GetSerializedSize and Serialize
* methods to reserve space in the buffer and request the
* header to serialize itself in the packet buffer.
*
@@ -142,7 +125,7 @@
void AddHeader (T const &header);
/**
* Deserialize and remove the header from the internal buffer.
- * This method invokes ns3::Chunk::DeserializeFrom.
+ * This method invokes Deserialize.
*
* \param header a reference to the header to remove from the internal buffer.
* \returns the number of bytes removed from the packet.
@@ -151,7 +134,7 @@
uint32_t RemoveHeader (T &header);
/**
* Add trailer to this packet. This method invokes the
- * ns3::Chunk::GetSerializedSize and ns3::Trailer::serializeTo
+ * GetSerializedSize and Serialize
* methods to reserve space in the buffer and request the trailer
* to serialize itself in the packet buffer.
*
@@ -161,7 +144,7 @@
void AddTrailer (T const &trailer);
/**
* Remove a deserialized trailer from the internal buffer.
- * This method invokes the ns3::Chunk::DeserializeFrom method.
+ * This method invokes the Deserialize method.
*
* \param trailer a reference to the trailer to remove from the internal buffer.
* \returns the number of bytes removed from the end of the packet.
@@ -171,7 +154,8 @@
/**
* Attach a tag to this packet. The tag is fully copied
* in a packet-specific internal buffer. This operation
- * is expected to be really fast.
+ * is expected to be really fast. The copy constructor of the
+ * tag is invoked to copy it into the tag buffer.
*
* \param tag a pointer to the tag to attach to this packet.
*/
@@ -198,6 +182,8 @@
/**
* Copy a tag stored internally to the input tag. If no instance
* of this tag is present internally, the input tag is not modified.
+ * The copy constructor of the tag is invoked to copy it into the
+ * input tag variable.
*
* \param tag a pointer to the tag to read from this packet
* \returns true if an instance of this tag type is stored
@@ -211,6 +197,14 @@
*/
void RemoveAllTags (void);
/**
+ * \param os output stream in which the data should be printed.
+ *
+ * Iterate over the tags present in this packet, and
+ * invoke the Print method of each tag stored in the packet.
+ */
+ void PrintTags (std::ostream &os) const;
+
+ /**
* Concatenate the input packet at the end of the current
* packet. This does not alter the uid of either packet.
*
@@ -294,6 +288,38 @@
* errors will be detected and will abort the program.
*/
static void EnableMetadata (void);
+
+ /**
+ * \returns a byte buffer
+ *
+ * This method creates a serialized representation of a Packet object
+ * ready to be transmitted over a network to another system. This
+ * serialized representation contains a copy of the packet byte buffer,
+ * the tag list, and the packet metadata (if there is one).
+ *
+ * This method will trigger calls to the Serialize and GetSerializedSize
+ * methods of each tag stored in this packet.
+ *
+ * This method will typically be used by parallel simulations where
+ * the simulated system is partitioned and each partition runs on
+ * a different CPU.
+ */
+ Buffer Serialize (void) const;
+ /**
+ * \param buffer a byte buffer
+ *
+ * This method reads a byte buffer as created by Packet::Serialize
+ * and restores the state of the Packet to what it was prior to
+ * calling Serialize.
+ *
+ * This method will trigger calls to the Deserialize method
+ * of each tag stored in this packet.
+ *
+ * This method will typically be used by parallel simulations where
+ * the simulated system is partitioned and each partition runs on
+ * a different CPU.
+ */
+ void Deserialize (Buffer buffer);
private:
Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
Buffer m_buffer;
@@ -302,7 +328,42 @@
static uint32_t m_globalUid;
};
-}; // namespace ns3
+/**
+ * \defgroup packetperf Packet Performance
+ * The current implementation of the byte buffers and tag list is based
+ * on COW (Copy On Write. An introduction to COW can be found in Scott
+ * Meyer's "More Effective C++", items 17 and 29). What this means is that
+ * copying packets without modifying them is very cheap (in terms of cpu
+ * and memory usage) and modifying them can be also very cheap. What is
+ * key for proper COW implementations is being
+ * able to detect when a given modification of the state of a packet triggers
+ * a full copy of the data prior to the modification: COW systems need
+ * to detect when an operation is "dirty".
+ *
+ * Dirty operations:
+ * - ns3::Packet::RemoveTag
+ * - ns3::Packet::AddHeader
+ * - ns3::Packet::AddTrailer
+ * - both versions of ns3::Packet::AddAtEnd
+ *
+ * Non-dirty operations:
+ * - ns3::Packet::AddTag
+ * - ns3::Packet::RemoveAllTags
+ * - ns3::Packet::PeekTag
+ * - ns3::Packet::RemoveHeader
+ * - ns3::Packet::RemoveTrailer
+ * - ns3::Packet::CreateFragment
+ * - ns3::Packet::RemoveAtStart
+ * - ns3::Packet::RemoveAtEnd
+ *
+ * Dirty operations will always be slower than non-dirty operations,
+ * sometimes by several orders of magnitude. However, even the
+ * dirty operations have been optimized for common use-cases which
+ * means that most of the time, these operations will not trigger
+ * data copies and will thus be still very fast.
+ */
+
+} // namespace ns3
/**************************************************
@@ -316,9 +377,11 @@
void
Packet::AddHeader (T const &header)
{
- NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0,
- "Must pass Header subclass to Packet::AddHeader");
- uint32_t size = header.GetSize ();
+ const Header *testHeader;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Header class
+ testHeader = &header;
+ uint32_t size = header.GetSerializedSize ();
m_buffer.AddAtStart (size);
header.Serialize (m_buffer.Begin ());
m_metadata.AddHeader (header, size);
@@ -327,8 +390,10 @@
uint32_t
Packet::RemoveHeader (T &header)
{
- NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0,
- "Must pass Header subclass to Packet::RemoveHeader");
+ Header *testHeader;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Header class
+ testHeader = &header;
uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
m_buffer.RemoveAtStart (deserialized);
m_metadata.RemoveHeader (header, deserialized);
@@ -338,9 +403,11 @@
void
Packet::AddTrailer (T const &trailer)
{
- NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0,
- "Must pass Trailer subclass to Packet::AddTrailer");
- uint32_t size = trailer.GetSize ();
+ const Trailer *testTrailer;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Trailer class
+ testTrailer = &trailer;
+ uint32_t size = trailer.GetSerializedSize ();
m_buffer.AddAtEnd (size);
Buffer::Iterator end = m_buffer.End ();
trailer.Serialize (end);
@@ -350,8 +417,10 @@
uint32_t
Packet::RemoveTrailer (T &trailer)
{
- NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0,
- "Must pass Trailer subclass to Packet::RemoveTrailer");
+ Trailer *testTrailer;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Trailer class
+ testTrailer = &trailer;
uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
m_buffer.RemoveAtEnd (deserialized);
m_metadata.RemoveTrailer (trailer, deserialized);
@@ -362,18 +431,31 @@
template <typename T>
void Packet::AddTag (T const& tag)
{
+ const Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
m_tags.Add (tag);
}
template <typename T>
bool Packet::RemoveTag (T & tag)
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
return m_tags.Remove (tag);
}
template <typename T>
bool Packet::PeekTag (T & tag) const
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
return m_tags.Peek (tag);
}
-}; // namespace ns3
+
+} // namespace ns3
#endif /* PACKET_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "tag-registry.h"
+#include "ns3/fatal-error.h"
+
+namespace ns3 {
+
+TagRegistry::TagInfoVector *
+TagRegistry::GetInfo (void)
+{
+ static TagRegistry::TagInfoVector vector;
+ return &vector;
+}
+
+std::string
+TagRegistry::GetUidString (uint32_t uid)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ return info.uidString;
+}
+uint32_t
+TagRegistry::GetUidFromUidString (std::string uidString)
+{
+ TagInfoVector *vec = GetInfo ();
+ uint32_t uid = 1;
+ for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work.");
+ return 0;
+}
+
+void
+TagRegistry::Destruct (uint32_t uid, uint8_t *data)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ info.destruct (data);
+}
+void
+TagRegistry::Print (uint32_t uid, uint8_t *data, std::ostream &os)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ info.print (data, os);
+}
+uint32_t
+TagRegistry::GetSerializedSize (uint32_t uid, uint8_t *data)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ return info.getSerializedSize (data);
+}
+void
+TagRegistry::Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ info.serialize (data, start);
+}
+uint32_t
+TagRegistry::Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+ TagInfo info = (*GetInfo ())[uid - 1];
+ return info.deserialize (data, start);
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAG_REGISTRY_H
+#define TAG_REGISTRY_H
+
+#include <string>
+#include <stdint.h>
+#include "buffer.h"
+
+namespace ns3 {
+
+/**
+ * \brief a registry of all existing tag types.
+ * \internal
+ *
+ * This class is used to give polymorphic access to the methods
+ * exported by a tag. It also is used to associate a single
+ * reliable uid to each unique type.
+ */
+class TagRegistry
+{
+public:
+ template <typename T>
+ static uint32_t Register (std::string uidString);
+ static std::string GetUidString (uint32_t uid);
+ static uint32_t GetUidFromUidString (std::string uidString);
+ static void Destruct (uint32_t uid, uint8_t *data);
+ static void Print (uint32_t uid, uint8_t *data, std::ostream &os);
+ static uint32_t GetSerializedSize (uint32_t uid, uint8_t *data);
+ static void Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+ static uint32_t Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+private:
+ typedef void (*DestructCb) (uint8_t *);
+ typedef void (*PrintCb) (uint8_t *, std::ostream &);
+ typedef uint32_t (*GetSerializedSizeCb) (uint8_t *);
+ typedef void (*SerializeCb) (uint8_t *, Buffer::Iterator);
+ typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+ struct TagInfo
+ {
+ std::string uidString;
+ DestructCb destruct;
+ PrintCb print;
+ GetSerializedSizeCb getSerializedSize;
+ SerializeCb serialize;
+ DeserializeCb deserialize;
+ };
+ typedef std::vector<struct TagInfo> TagInfoVector;
+
+ template <typename T>
+ static void DoDestruct (uint8_t *data);
+ template <typename T>
+ static void DoPrint (uint8_t *data, std::ostream &os);
+ template <typename T>
+ static uint32_t DoGetSerializedSize (uint8_t *data);
+ template <typename T>
+ static void DoSerialize (uint8_t *data, Buffer::Iterator start);
+ template <typename T>
+ static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start);
+
+ static TagInfoVector *GetInfo (void);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void
+TagRegistry::DoDestruct (uint8_t *data)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ tag->~T ();
+}
+template <typename T>
+void
+TagRegistry::DoPrint (uint8_t *data, std::ostream &os)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ tag->Print (os);
+}
+template <typename T>
+uint32_t
+TagRegistry::DoGetSerializedSize (uint8_t *data)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ return tag->GetSerializedSize ();
+}
+template <typename T>
+void
+TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ tag->Serialize (start);
+}
+template <typename T>
+uint32_t
+TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start)
+{
+ T *tag = reinterpret_cast<T *> (data);
+ return tag->Deserialize (start);
+}
+
+template <typename T>
+uint32_t
+TagRegistry::Register (std::string uidString)
+{
+ TagInfoVector *vec = GetInfo ();
+ uint32_t j = 0;
+ for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == uidString)
+ {
+ return j;
+ }
+ j++;
+ }
+ TagInfo info;
+ info.uidString = uidString;
+ info.destruct = &TagRegistry::DoDestruct<T>;
+ info.print = &TagRegistry::DoPrint<T>;
+ info.getSerializedSize = &TagRegistry::DoGetSerializedSize<T>;
+ info.serialize = &TagRegistry::DoSerialize<T>;
+ info.deserialize = &TagRegistry::DoDeserialize<T>;
+ vec->push_back (info);
+ uint32_t uid = vec->size ();
+ return uid;
+}
+
+} // namespace ns3
+
+#endif /* TAG_REGISTRY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,126 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAG_H
+#define TAG_H
+
+#include <stdint.h>
+#include <string>
+
+/**
+ * \relates ns3::Tag
+ * \brief this macro should be instantiated exactly once for each
+ * new type of Tag
+ *
+ * This macro will ensure that your new Tag type is registered
+ * within the tag registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TAG_ENSURE_REGISTERED(x) \
+static class thisisaveryverylongclassname ##x \
+{ \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+} g_thisisanotherveryveryverylongname ## x;
+
+namespace ns3 {
+
+/**
+ * \brief a tag can be stored in a packet.
+ *
+ * A tag is a blob of 16 bytes of data which can be stored in
+ * a packet: a packet can contain an arbitrary number of tags
+ * and these tags are considered as "on-the-side" per-packet
+ * data structures which are not taken into account when calculating
+ * the size of the payload of a packet. They exist solely as
+ * simulation-specific objects.
+ *
+ * Tags are typically used to:
+ * - implement per-packet cross-layer communication
+ * - implement packet coloring: you could store a "color" tag
+ * in a packet to mark various types of packet for
+ * simulation analysis
+ *
+ * To create a new type of tag, you must create a subclass
+ * of the Tag base class which defines:
+ * - a public default constructor: needed for implementation
+ * purposes of the Packet code.
+ * - a public copy constructor: needed to copy a tag into
+ * a packet tag buffer when the user invokes Packet::AddTag
+ * - a public destructor: needed to destroy the copy of a tag
+ * stored in a packet buffer when the user invokes Packet::RemoveTag
+ * or when the packet is destroyed and the last reference to
+ * a tag instance disapears.
+ * - a public static method named GetUid: needed to uniquely
+ * the type of each tag instance.
+ * - a public method named Print: needed to print the content
+ * of a tag when the user calls Packet::PrintTags
+ * - a public method named GetSerializedSize: needed to serialize
+ * the content of a tag to a byte buffer when a packet must
+ * be sent from one computing node to another in a parallel
+ * simulation. If this method returns 0, it means that the
+ * tag does not need to be transfered from computing node to
+ * computing node
+ * - a public method named Serialize: perform the serialization
+ * to a byte buffer upon transfer to a new computing node in a
+ * parallel simulation.
+ * - a public method named Deserialize: invert the serialization
+ * from a byte buffer after being transfered to a new computing
+ * node in a parallel simulation.
+ *
+ * A detailed example of what these methods should look like
+ * and how they should be implemented is described in samples/main-packet-tag.cc
+ */
+class Tag
+{
+protected:
+ /**
+ * \param name the unique name of the new type of tag
+ * \returns a newly-allocated uid
+ *
+ * This method should be used by subclasses to implement
+ * their static public GetUid method.
+ */
+ template <typename T>
+ static uint32_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+// implementation below.
+#include "tag-registry.h"
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Tag::AllocateUid (std::string name)
+{
+ return TagRegistry::Register<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TAG_H */
--- a/src/common/tags.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/tags.cc Wed Sep 05 18:35:39 2007 +0100
@@ -20,84 +20,10 @@
*/
#include "tags.h"
#include <string.h>
+#include "ns3/fatal-error.h"
namespace ns3 {
-TagRegistry *
-TagRegistry::GetInstance (void)
-{
- static TagRegistry registry;
- return ®istry;
-}
-
-TagRegistry::TagRegistry ()
- : m_sorted (false)
-{}
-
-
-void
-TagRegistry::Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor)
-{
- NS_ASSERT (!m_sorted);
- struct TagInfoItem item;
- item.uuid = uuid;
- item.printer = prettyPrinter;
- item.destructor = destructor;
- m_registry.push_back (item);
-}
-bool
-TagRegistry::CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b)
-{
- return a.uuid < b.uuid;
-}
-uint32_t
-TagRegistry::LookupUid (std::string uuid)
-{
- if (!m_sorted)
- {
- std::sort (m_registry.begin (), m_registry.end (), &TagRegistry::CompareItem);
- m_sorted = true;
- }
- NS_ASSERT (m_sorted);
- uint32_t uid = 1;
- for (TagsDataCI i = m_registry.begin (); i != m_registry.end (); i++)
- {
- if (i->uuid == uuid)
- {
- return uid;
- }
- uid++;
- }
- // someone asked for a uid for an unregistered uuid.
- NS_ASSERT (!"You tried to use unregistered tag: make sure you create an instance of type TagRegistration<YouTagType>.");
- // quiet compiler
- return 0;
-}
-void
-TagRegistry::PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os)
-{
- NS_ASSERT (uid > 0);
- uint32_t index = uid - 1;
- NS_ASSERT (m_registry.size () > index);
- PrettyPrinter prettyPrinter = m_registry[index].printer;
- if (prettyPrinter != 0)
- {
- prettyPrinter (buf, os);
- }
-}
-void
-TagRegistry::Destruct (uint32_t uid, uint8_t buf[Tags::SIZE])
-{
- NS_ASSERT (uid > 0);
- uint32_t index = uid - 1;
- NS_ASSERT (m_registry.size () > index);
- Destructor destructor = m_registry[index].destructor;
- NS_ASSERT (destructor != 0);
- destructor (buf);
-}
-
-
-
#ifdef USE_FREE_LIST
struct Tags::TagData *Tags::gFree = 0;
@@ -193,13 +119,102 @@
}
void
-Tags::PrettyPrint (std::ostream &os)
+Tags::Print (std::ostream &os, std::string separator) const
{
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
{
- TagRegistry::GetInstance ()->PrettyPrint (cur->m_id, cur->m_data, os);
+ TagRegistry::Print (cur->m_id, cur->m_data, os);
+ if (cur->m_next != 0)
+ {
+ os << separator;
+ }
+ }
+}
+
+uint32_t
+Tags::GetSerializedSize (void) const
+{
+ uint32_t totalSize = 4; // reserve space for the size of the tag data.
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
+ {
+ uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+ if (size != 0)
+ {
+ std::string uidString = TagRegistry::GetUidString (cur->m_id);
+ totalSize += 4; // for the size of the string itself.
+ totalSize += uidString.size ();
+ totalSize += size;
+ }
+ }
+ return totalSize;
+}
+
+void
+Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const
+{
+ i.WriteU32 (totalSize);
+ for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
+ {
+ uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+ if (size != 0)
+ {
+ std::string uidString = TagRegistry::GetUidString (cur->m_id);
+ i.WriteU32 (uidString.size ());
+ uint8_t *buf = (uint8_t *)uidString.c_str ();
+ i.Write (buf, uidString.size ());
+ TagRegistry::Serialize (cur->m_id, cur->m_data, i);
+ }
}
}
+uint32_t
+Tags::Deserialize (Buffer::Iterator i)
+{
+ uint32_t totalSize = i.ReadU32 ();
+ uint32_t bytesRead = 4;
+ while (bytesRead < totalSize)
+ {
+ uint32_t uidStringSize = i.ReadU32 ();
+ bytesRead += 4;
+ std::string uidString;
+ uidString.reserve (uidStringSize);
+ for (uint32_t j = 0; j < uidStringSize; j++)
+ {
+ uint32_t c = i.ReadU8 ();
+ uidString.push_back (c);
+ }
+ bytesRead += uidStringSize;
+ uint32_t uid = TagRegistry::GetUidFromUidString (uidString);
+ struct TagData *newStart = AllocData ();
+ newStart->m_count = 1;
+ newStart->m_next = 0;
+ newStart->m_id = uid;
+ bytesRead += TagRegistry::Deserialize (uid, newStart->m_data, i);
+ newStart->m_next = m_next;
+ m_next = newStart;
+ }
+ NS_ASSERT (bytesRead == totalSize);
+ /**
+ * The process of serialization/deserialization
+ * results in an inverted linked-list after
+ * deserialization so, we invert the linked-list
+ * in-place here.
+ * Note: the algorithm below is pretty classic
+ * but whenever I get to code it, it makes my
+ * brain hurt :)
+ */
+ struct TagData *prev = 0;
+ struct TagData *cur = m_next;
+ while (cur != 0)
+ {
+ struct TagData *next = cur->m_next;
+ cur->m_next = prev;
+ prev = cur;
+ cur = next;
+ }
+ m_next = prev;
+ return totalSize;
+}
+
}; // namespace ns3
@@ -224,25 +239,67 @@
virtual bool RunTests (void);
};
-struct myTagA {
+class myTagA : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagA> ("myTagA.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_a = true;}
+ uint32_t GetSerializedSize (void) const {return 1;}
+ void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);}
+ uint32_t Deserialize (Buffer::Iterator i) {a = i.ReadU8 (); return 1;}
+
uint8_t a;
};
-struct myTagB {
+class myTagB : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagB> ("myTagB.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_b = true;}
+ uint32_t GetSerializedSize (void) const {return 4;}
+ void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);}
+ uint32_t Deserialize (Buffer::Iterator i) {b = i.ReadU32 (); return 4;}
+
uint32_t b;
};
-struct myTagC {
+class myTagC : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagC> ("myTagC.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_c = true;}
+ uint32_t GetSerializedSize (void) const {return Tags::SIZE;}
+ void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);}
+ uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;}
uint8_t c [Tags::SIZE];
};
-struct myInvalidTag {
+class myInvalidTag : public Tag
+{
+public:
+ static uint32_t GetUid (void)
+ {static uint32_t uid = AllocateUid<myInvalidTag> ("myinvalidTag.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {}
+ uint32_t GetSerializedSize (void) const {return 0;}
+ void Serialize (Buffer::Iterator i) const {}
+ uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
uint8_t invalid [Tags::SIZE+1];
};
-struct myTagZ {
+class myTagZ : public Tag
+{
+public:
+ static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagZ> ("myTagZ.test.nsnam.org"); return uid;}
+ void Print (std::ostream &os) const {g_z = true;}
+ uint32_t GetSerializedSize (void) const {return 0;}
+ void Serialize (Buffer::Iterator i) const {}
+ uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
uint8_t z;
};
-class MySmartTag
+class MySmartTag : public Tag
{
public:
+ static uint32_t GetUid (void)
+ {static uint32_t uid = AllocateUid<MySmartTag> ("MySmartTag.test.nsnam.org"); return uid;}
MySmartTag ()
{
//std::cout << "construct" << std::endl;
@@ -260,43 +317,12 @@
//std::cout << "assign" << std::endl;
return *this;
}
- static void PrettyPrinterCb (const MySmartTag *a, std::ostream &os)
- {}
+ void Print (std::ostream &os) const {}
+ uint32_t GetSerializedSize (void) const {return 0;}
+ void Serialize (Buffer::Iterator i) const {}
+ uint32_t Deserialize (Buffer::Iterator i) {return 0;}
};
-static void
-myTagAPrettyPrinterCb (struct myTagA const*a, std::ostream &os)
-{
- //os << "struct myTagA, a="<<(uint32_t)a->a<<std::endl;
- g_a = true;
-}
-static void
-myTagBPrettyPrinterCb (struct myTagB const*b, std::ostream &os)
-{
- //os << "struct myTagB, b="<<b->b<<std::endl;
- g_b = true;
-}
-static void
-myTagCPrettyPrinterCb (struct myTagC const*c, std::ostream &os)
-{
- //os << "struct myTagC, c="<<(uint32_t)c->c[0]<<std::endl;
- g_c = true;
-}
-static void
-myTagZPrettyPrinterCb (struct myTagZ const*z, std::ostream &os)
-{
- //os << "struct myTagZ" << std::endl;
- g_z = true;
-}
-
-
-static TagRegistration<struct myTagA> gMyTagARegistration ("A", &myTagAPrettyPrinterCb);
-static TagRegistration<struct myTagB> gMyTagBRegistration ("B", &myTagBPrettyPrinterCb);
-static TagRegistration<struct myTagC> gMyTagCRegistration ("C", &myTagCPrettyPrinterCb);
-static TagRegistration<struct myTagZ> g_myTagZRegistration ("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
- &myTagZPrettyPrinterCb);
-static TagRegistration<MySmartTag> g_myTagSmartRegistration ("SmartTag", &MySmartTag::PrettyPrinterCb);
-
TagsTest::TagsTest ()
: Test ("Tags")
@@ -311,7 +337,7 @@
// build initial tag.
Tags tags;
- struct myTagA a;
+ myTagA a;
a.a = 10;
tags.Add (a);
a.a = 0;
@@ -321,12 +347,12 @@
ok = false;
}
g_a = false;
- tags.PrettyPrint (std::cout);
+ tags.Print (std::cout, "");
if (!g_a)
{
ok = false;
}
- struct myTagB b;
+ myTagB b;
b.b = 0xff;
tags.Add (b);
b.b = 0;
@@ -337,7 +363,7 @@
}
g_b = false;
g_a = false;
- tags.PrettyPrint (std::cout);
+ tags.Print (std::cout, "");
if (!g_a || !g_b)
{
ok = false;
@@ -346,26 +372,26 @@
Tags other = tags;
g_b = false;
g_a = false;
- other.PrettyPrint (std::cout);
+ other.Print (std::cout, "");
if (!g_a || !g_b)
{
ok = false;
}
g_b = false;
g_a = false;
- tags.PrettyPrint (std::cout);
+ tags.Print (std::cout, "");
if (!g_a || !g_b)
{
ok = false;
}
- struct myTagA oA;
+ myTagA oA;
oA.a = 0;
other.Peek (oA);
if (oA.a != 10)
{
ok = false;
}
- struct myTagB oB;
+ myTagB oB;
oB.b = 1;
other.Peek (oB);
if (oB.b != 0xff)
@@ -380,7 +406,7 @@
}
g_b = false;
g_a = false;
- other.PrettyPrint (std::cout);
+ other.Print (std::cout, "");
if (g_a || !g_b)
{
ok = false;
@@ -401,7 +427,7 @@
other = tags;
Tags another = other;
- struct myTagC c;
+ myTagC c;
memset (c.c, 0x66, 16);
another.Add (c);
c.c[0] = 0;
@@ -421,12 +447,12 @@
//struct myInvalidTag invalid;
//tags.add (&invalid);
- struct myTagZ tagZ;
+ myTagZ tagZ;
Tags testLastTag;
tagZ.z = 0;
testLastTag.Add (tagZ);
g_z = false;
- testLastTag.PrettyPrint (std::cout);
+ testLastTag.Print (std::cout, "");
if (!g_z)
{
ok = false;
@@ -440,6 +466,58 @@
tmp.Remove (smartTag);
}
+ {
+ Tags source;
+ myTagA aSource;
+ aSource.a = 0x66;
+ source.Add (aSource);
+ Buffer buffer;
+ uint32_t serialized = source.GetSerializedSize ();
+ buffer.AddAtStart (serialized);
+ source.Serialize (buffer.Begin (), serialized);
+ Tags dest;
+ dest.Deserialize (buffer.Begin ());
+ myTagA aDest;
+ aDest.a = 0x55;
+ dest.Peek (aDest);
+ if (aDest.a != 0x66)
+ {
+ ok = false;
+ }
+ }
+
+ {
+ Tags source;
+ myTagA aSource;
+ aSource.a = 0x66;
+ source.Add (aSource);
+ myTagZ zSource;
+ zSource.z = 0x77;
+ source.Add (zSource);
+
+ Buffer buffer;
+ uint32_t serialized = source.GetSerializedSize ();
+ buffer.AddAtStart (serialized);
+ source.Serialize (buffer.Begin (), serialized);
+ Tags dest;
+ dest.Deserialize (buffer.Begin ());
+
+ myTagA aDest;
+ aDest.a = 0x55;
+ dest.Peek (aDest);
+ if (aDest.a != 0x66)
+ {
+ ok = false;
+ }
+ myTagZ zDest;
+ zDest.z = 0x44;
+ dest.Peek (zDest);
+ if (zDest.z != 0x44)
+ {
+ ok = false;
+ }
+ }
+
return ok;
}
--- a/src/common/tags.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/tags.h Wed Sep 05 18:35:39 2007 +0100
@@ -24,12 +24,10 @@
#include <stdint.h>
#include <ostream>
#include <vector>
+#include "buffer.h"
namespace ns3 {
-template <typename T>
-class TagPrettyPrinter;
-
/**
* \ingroup constants
* \brief Tag maximum size
@@ -54,7 +52,10 @@
template <typename T>
bool Peek (T &tag) const;
- void PrettyPrint (std::ostream &os);
+ void Print (std::ostream &os, std::string separator) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator i, uint32_t size) const;
+ uint32_t Deserialize (Buffer::Iterator i);
inline void RemoveAll (void);
@@ -79,161 +80,39 @@
struct TagData *m_next;
};
-/**
- * \brief pretty print packet tags
- *
- * This class is used to register a pretty-printer
- * callback function to print in a nice user-friendly
- * way the content of the target type. To register
- * such a type, all you need to do is instantiate
- * an instance of this type as a static variable.
- */
-template <typename T>
-class TagRegistration {
-public:
- /**
- * \param uuid a uuid generated with uuidgen
- * \param fn a function which can pretty-print an instance
- * of type T in the output stream.
- */
- TagRegistration<T> (std::string uuid, void(*fn) (T const*, std::ostream &));
-private:
- static void PrettyPrinterCb (uint8_t *buf, std::ostream &os);
- static void DestructorCb (uint8_t *buf);
- static void(*m_prettyPrinter) (T const*, std::ostream &);
-};
-
-}; // namespace ns3
+} // namespace ns3
/**************************************************************
An implementation of the templates defined above
*************************************************************/
+#include "tag-registry.h"
+#include "tag.h"
#include "ns3/assert.h"
#include <string>
namespace ns3 {
-class TagRegistry {
-public:
- typedef void (*PrettyPrinter) (uint8_t [Tags::SIZE], std::ostream &);
- typedef void (*Destructor) (uint8_t [Tags::SIZE]);
- void Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor);
- /**
- * returns a numeric integer which uniquely identifies the input string.
- * that integer cannot be zero which is a reserved value.
- */
- uint32_t LookupUid (std::string uuid);
- void PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os);
- void Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]);
-
- static TagRegistry *GetInstance (void);
-private:
- TagRegistry ();
- struct TagInfoItem
- {
- std::string uuid;
- PrettyPrinter printer;
- Destructor destructor;
- };
- typedef std::vector<struct TagInfoItem> TagsData;
- typedef std::vector<struct TagInfoItem>::const_iterator TagsDataCI;
- static bool CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b);
- bool m_sorted;
- TagsData m_registry;
-};
-/**
- * The TypeUid class is used to create a mapping Type --> uid
- * Note that we use a static getUuid function which contains a
- * static std::string variable rather than a simpler static
- * member std::string variable to ensure the proper order
- * of initialization when these methods are invoked
- * from the constructor of another static variable.
- */
-template <typename T>
-class TypeUid {
-public:
- static void Record (std::string uuid);
- static const uint32_t GetUid (void);
-private:
- static std::string *GetUuid (void);
- T m_realType;
-};
-
-template <typename T>
-void TypeUid<T>::Record (std::string uuid)
-{
- *(GetUuid ()) = uuid;
-}
-
-template <typename T>
-const uint32_t TypeUid<T>::GetUid (void)
-{
- static const uint32_t uid = TagRegistry::GetInstance ()->
- LookupUid (*(GetUuid ()));
- return uid;
-}
-
-template <typename T>
-std::string *TypeUid<T>::GetUuid (void)
-{
- static std::string uuid;
- return &uuid;
-}
-
-
-
-/**
- * Implementation of the TagRegistration registration class.
- * It records a callback with the TagRegistry
- * This callback performs type conversion before forwarding
- * the call to the user-provided function.
- */
-template <typename T>
-TagRegistration<T>::TagRegistration (std::string uuid, void (*prettyPrinter) (T const*, std::ostream &))
-{
- NS_ASSERT (sizeof (T) <= Tags::SIZE);
- m_prettyPrinter = prettyPrinter;
- TagRegistry::GetInstance ()->
- Record (uuid, &TagRegistration<T>::PrettyPrinterCb, &TagRegistration<T>::DestructorCb);
- TypeUid<T>::Record (uuid);
-}
-template <typename T>
-void
-TagRegistration<T>::PrettyPrinterCb (uint8_t *buf, std::ostream &os)
-{
- NS_ASSERT (sizeof (T) <= Tags::SIZE);
- T *tag = reinterpret_cast<T *> (buf);
- (*m_prettyPrinter) (tag, os);
-}
-template <typename T>
-void
-TagRegistration<T>::DestructorCb (uint8_t *buf)
-{
- T *tag = reinterpret_cast<T *> (buf);
- tag->~T ();
-}
-template <typename T>
-void (*TagRegistration<T>::m_prettyPrinter) (T const*, std::ostream &) = 0;
-
-
-
-
template <typename T>
void
Tags::Add (T const&tag)
{
+ const Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
+
NS_ASSERT (sizeof (T) <= Tags::SIZE);
// ensure this id was not yet added
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
{
- NS_ASSERT (cur->m_id != TypeUid<T>::GetUid ());
+ NS_ASSERT (cur->m_id != T::GetUid ());
}
struct TagData *newStart = AllocData ();
newStart->m_count = 1;
newStart->m_next = 0;
- newStart->m_id = TypeUid<T>::GetUid ();
+ newStart->m_id = T::GetUid ();
void *buf = &newStart->m_data;
new (buf) T (tag);
newStart->m_next = m_next;
@@ -244,18 +123,26 @@
bool
Tags::Remove (T &tag)
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
NS_ASSERT (sizeof (T) <= Tags::SIZE);
- return Remove (TypeUid<T>::GetUid ());
+ return Remove (T::GetUid ());
}
template <typename T>
bool
Tags::Peek (T &tag) const
{
+ Tag *parent;
+ // if the following assignment fails, it is because the
+ // input to this function is not a subclass of the Tag class.
+ parent = &tag;
NS_ASSERT (sizeof (T) <= Tags::SIZE);
for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next)
{
- if (cur->m_id == TypeUid<T>::GetUid ())
+ if (cur->m_id == T::GetUid ())
{
/* found tag */
T *data = reinterpret_cast<T *> (&cur->m_data);
@@ -315,16 +202,14 @@
}
if (prev != 0)
{
- TagRegistry::GetInstance ()->
- Destruct (prev->m_id, prev->m_data);
+ TagRegistry::Destruct (prev->m_id, prev->m_data);
FreeData (prev);
}
prev = cur;
}
if (prev != 0)
{
- TagRegistry::GetInstance ()->
- Destruct (prev->m_id, prev->m_data);
+ TagRegistry::Destruct (prev->m_id, prev->m_data);
FreeData (prev);
}
m_next = 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/trace-context-element.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,34 @@
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+uint32_t
+ElementRegistry::GetSize (uint16_t uid)
+{
+ InfoVector *vec = GetInfoVector ();
+ struct Info info = (*vec)[uid - 1];
+ return info.size;
+}
+void
+ElementRegistry::Print (uint16_t uid, uint8_t *instance, std::ostream &os)
+{
+ InfoVector *vec = GetInfoVector ();
+ struct Info info = (*vec)[uid - 1];
+ info.print (instance, os);
+}
+void
+ElementRegistry::Destroy (uint16_t uid, uint8_t *instance)
+{
+ InfoVector *vec = GetInfoVector ();
+ struct Info info = (*vec)[uid - 1];
+ info.destroy (instance);
+}
+ElementRegistry::InfoVector *
+ElementRegistry::GetInfoVector (void)
+{
+ static InfoVector vector;
+ return &vector;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/trace-context-element.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,189 @@
+#ifndef TRACE_CONTEXT_ELEMENT_H
+#define TRACE_CONTEXT_ELEMENT_H
+
+#include <string>
+#include <vector>
+
+#define NS_TRACE_CONTEXT_ELEMENT_ENSURE_REGISTERED(x) \
+namespace { \
+static class thisisaveryverylongclassname ##x \
+ { \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+ } g_thisisanotherveryveryverylongname ##x ; \
+}
+
+namespace ns3 {
+
+/**
+ * \brief an item stored in a TraceContext
+ *
+ * To store trace context information in a TraceContext instance,
+ * users must subclass this base class and store subclass instances
+ * in a TraceContext with TraceContext::Add.
+ *
+ * Each subclass should define and implement:
+ * - a public default constructor: it is used by the internals
+ * of the implementation of TraceContext.
+ * - a public destructor: it is also used by the internals of
+ * the implementation of TraceContext.
+ * - a public static method named GetUid which returns a 16 bit
+ * integer. The integer returned from this method should be
+ * allocated with the protected AllocatedUid method.
+ * - a public Print method: this method is used by the
+ * TraceContext::Print method to print the content of each
+ * of the trace context element stored in the trace context.
+ * This method takes a c++ output stream and argument and is
+ * expected to write an ascii string describing its content
+ * in this output stream.
+ *
+ * A typical subclass should look like this:
+ * \code
+ * class MyContext : public TraceContextElement
+ * {
+ * public:
+ * // the _required_ public API
+ * static uint16_t GetUid (void);
+ * MyContext ();
+ * ~MyContext ();
+ * void Print (std::ostream &os) const;
+ *
+ * // the user-specific API to manipulate the context.
+ * void SetData (uint8_t data);
+ * uint8_t GetData (void) const;
+ * private:
+ * uint8_t m_myContextData;
+ * };
+ *
+ * uint16_t
+ * MyContext::GetUid (void)
+ * {
+ * static uint16_t uid = AllocateUid<MyContext> ("MyContext");
+ * return uid;
+ * }
+ * MyContext::MyContext ()
+ * {}
+ * MyContext::~MyContext ()
+ * {}
+ * void
+ * MyContext::Print (std::ostream &os) const
+ * {
+ * os << "mycontext=" << (uint32_t) m_myContextData;
+ * }
+ * void
+ * MyContext::SetData (uint8_t data)
+ * {
+ * m_myContextData = data;
+ * }
+ * uint8_t
+ * MyContext::GetData (void) const
+ * {
+ * return m_myContextData;
+ * }
+ * \endcode
+ */
+class TraceContextElement
+{
+protected:
+ /**
+ * \param name a string which uniquely identifies the type
+ * of the subclass which is calling this method.
+ * \returns a unique 32 bit integer associated to the
+ * input string.
+ *
+ * Subclasses are expected to call this method from their
+ * public static GetUid method.
+ */
+ template <typename T>
+ static uint16_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+/**
+ * \brief a registry of TraceContextElement subclasses
+ * \internal
+ */
+class ElementRegistry
+{
+public:
+ template <typename T>
+ static uint16_t AllocateUid (std::string name);
+
+ static uint32_t GetSize (uint16_t uid);
+ static void Print (uint16_t uid, uint8_t *instance, std::ostream &os);
+ static void Destroy (uint16_t uid, uint8_t *instance);
+private:
+ typedef void (*PrintCb) (uint8_t *instance, std::ostream &os);
+ typedef void (*DestroyCb) (uint8_t *instance);
+ struct Info {
+ uint32_t size;
+ std::string uidString;
+ PrintCb print;
+ DestroyCb destroy;
+ };
+ typedef std::vector<struct Info> InfoVector;
+ static InfoVector *GetInfoVector (void);
+ template <typename T>
+ static void DoPrint (uint8_t *instance, std::ostream &os);
+ template <typename T>
+ static void DoDestroy (uint8_t *instance);
+};
+
+template <typename T>
+void
+ElementRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+ static T obj;
+ // make sure we are aligned.
+ memcpy ((void*)&obj, instance, sizeof (T));
+ obj.Print (os);
+}
+template <typename T>
+void
+ElementRegistry::DoDestroy (uint8_t *instance)
+{
+ static T obj;
+ // make sure we are aligned.
+ memcpy ((void*)&obj, instance, sizeof (T));
+ obj.~T ();
+}
+
+template <typename T>
+uint16_t
+ElementRegistry::AllocateUid (std::string name)
+{
+ InfoVector *vec = GetInfoVector ();
+ uint16_t uid = 1;
+ for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+ {
+ if (i->uidString == name)
+ {
+ return uid;
+ }
+ uid++;
+ }
+ struct Info info;
+ info.size = sizeof (T);
+ info.uidString = name;
+ info.print = &ElementRegistry::DoPrint<T>;
+ info.destroy = &ElementRegistry::DoDestroy<T>;
+ vec->push_back (info);
+ return vec->size ();
+}
+
+
+
+template <typename T>
+uint16_t
+TraceContextElement::AllocateUid (std::string name)
+{
+ return ElementRegistry::AllocateUid<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TRACE_CONTEXT_ELEMENT_H */
--- a/src/common/trace-context.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-context.cc Wed Sep 05 18:35:39 2007 +0100
@@ -19,12 +19,11 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "trace-context.h"
+#include "trace-context-element.h"
#include "ns3/assert.h"
namespace ns3 {
-std::vector<uint8_t> TraceContext::m_sizes;
-
TraceContext::TraceContext ()
: m_data (0)
{}
@@ -68,12 +67,6 @@
}
}
-uint8_t
-TraceContext::GetSize (uint8_t uid)
-{
- return m_sizes[uid];
-}
-
void
TraceContext::Add (TraceContext const &o)
{
@@ -81,12 +74,12 @@
{
return;
}
- uint8_t currentUid;
+ uint16_t currentUid;
uint16_t i = 0;
while (i < o.m_data->size)
{
currentUid = o.m_data->data[i];
- uint8_t size = TraceContext::GetSize (currentUid);
+ uint8_t size = ElementRegistry::GetSize (currentUid);
uint8_t *selfBuffer = CheckPresent (currentUid);
uint8_t *otherBuffer = &(o.m_data->data[i+1]);
if (selfBuffer != 0)
@@ -116,7 +109,7 @@
uint16_t i = 0;
do {
currentUid = m_data->data[i];
- uint8_t size = TraceContext::GetSize (currentUid);
+ uint8_t size = ElementRegistry::GetSize (currentUid);
if (currentUid == uid)
{
return &m_data->data[i+1];
@@ -131,7 +124,7 @@
TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
{
NS_ASSERT (uid != 0);
- uint8_t size = TraceContext::GetSize (uid);
+ uint8_t size = ElementRegistry::GetSize (uid);
uint8_t *present = CheckPresent (uid);
if (present != 0) {
if (memcmp (present, buffer, size) == 0)
@@ -201,7 +194,7 @@
uint16_t i = 0;
do {
currentUid = m_data->data[i];
- uint8_t size = TraceContext::GetSize (currentUid);
+ uint8_t size = ElementRegistry::GetSize (currentUid);
if (currentUid == uid)
{
memcpy (buffer, &m_data->data[i+1], size);
@@ -212,31 +205,48 @@
return false;
}
-uint8_t
-TraceContext::DoGetNextUid (void)
+void
+TraceContext::Print (std::ostream &os) const
{
- static uint8_t uid = 0;
- if (uid == 0)
+ if (m_data == 0)
{
- m_sizes.push_back (0);
+ return;
}
- uid++;
- return uid;
+ uint8_t currentUid;
+ uint16_t i = 0;
+ do {
+ currentUid = m_data->data[i];
+ uint8_t size = ElementRegistry::GetSize (currentUid);
+ uint8_t *instance = &m_data->data[i+1];
+ ElementRegistry::Print (currentUid, instance, os);
+ i += 1 + size;
+ if (i < m_data->size && currentUid != 0)
+ {
+ os << " ";
+ }
+ else
+ {
+ break;
+ }
+ } while (true);
}
-
}//namespace ns3
#include "ns3/test.h"
+#include <sstream>
namespace ns3 {
template <int N>
-class Ctx
+class Ctx : public TraceContextElement
{
public:
+ static uint16_t GetUid (void) {static uint16_t uid = AllocateUid<Ctx<N> > (GetName ()); return uid;}
+ static std::string GetName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();}
Ctx () : m_v (0) {}
Ctx (int v) : m_v (v) {}
+ void Print (std::ostream &os) {os << N;}
int Get (void) const { return N;}
private:
int m_v;
--- a/src/common/trace-context.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-context.h Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <vector>
#include "ns3/fatal-error.h"
+#include "trace-context-element.h"
namespace ns3 {
@@ -77,25 +78,20 @@
*/
template <typename T>
void Get (T &context) const;
+
+ void Print (std::ostream &os) const;
private:
friend class TraceContextTest;
// used exclusively for testing code.
template <typename T>
bool SafeGet (T &context) const;
template <typename T>
- bool SafeAdd (T &context);
+ bool SafeAdd (const T &context);
- template <typename T>
- static uint8_t GetUid (void);
- template <typename T>
- static uint8_t GetNextUid (void);
- static uint8_t DoGetNextUid (void);
- static uint8_t GetSize (uint8_t uid);
uint8_t *CheckPresent (uint8_t uid) const;
bool DoAdd (uint8_t uid, uint8_t const *buffer);
bool DoGet (uint8_t uid, uint8_t *buffer) const;
- static std::vector<uint8_t> m_sizes;
struct Data {
uint16_t count;
uint16_t size;
@@ -111,8 +107,12 @@
void
TraceContext::Add (T const &context)
{
+ const TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
uint8_t *data = (uint8_t *) &context;
- bool ok = DoAdd (TraceContext::GetUid<T> (), data);
+ bool ok = DoAdd (T::GetUid (), data);
if (!ok)
{
NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid.");
@@ -122,8 +122,12 @@
void
TraceContext::Get (T &context) const
{
+ TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
uint8_t *data = (uint8_t *) &context;
- bool found = DoGet (TraceContext::GetUid<T> (), data);
+ bool found = DoGet (T::GetUid (), data);
if (!found)
{
NS_FATAL_ERROR ("Type not stored in TraceContext");
@@ -133,35 +137,26 @@
bool
TraceContext::SafeGet (T &context) const
{
+ TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
uint8_t *data = (uint8_t *) &context;
- bool found = DoGet (TraceContext::GetUid<T> (), data);
+ bool found = DoGet (T::GetUid (), data);
return found;
}
template <typename T>
bool
-TraceContext::SafeAdd (T &context)
+TraceContext::SafeAdd (const T &context)
{
+ const TraceContextElement *parent;
+ // if the following assignment fails, it is because the input
+ // to this function is not a subclass of the TraceContextElement class.
+ parent = &context;
uint8_t *data = (uint8_t *) &context;
- bool ok = DoAdd (TraceContext::GetUid<T> (), data);
+ bool ok = DoAdd (T::GetUid (), data);
return ok;
}
-template <typename T>
-uint8_t
-TraceContext::GetUid (void)
-{
- static uint8_t uid = GetNextUid<T> ();
- return uid;
-}
-
-template <typename T>
-uint8_t
-TraceContext::GetNextUid (void)
-{
- uint8_t uid = DoGetNextUid ();
- m_sizes.push_back (sizeof (T));
- return uid;
-}
-
}//namespace ns3
#endif /* TRACE_CONTEXT_H */
--- a/src/common/trace-root.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-root.cc Wed Sep 05 18:35:39 2007 +0100
@@ -41,7 +41,7 @@
Callback<TraceResolver *,TraceContext const &> createResolver)
{
CompositeTraceResolver *resolver = GetComposite ();
- resolver->Add (name, createResolver, TraceRoot::NOTHING);
+ resolver->Add (name, createResolver);
}
CompositeTraceResolver *
--- a/src/common/trace-root.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-root.h Wed Sep 05 18:35:39 2007 +0100
@@ -328,9 +328,6 @@
Callback<TraceResolver *,TraceContext const &> createResolver);
private:
static CompositeTraceResolver *GetComposite (void);
- enum TraceType {
- NOTHING,
- };
};
}// namespace ns3
--- a/src/common/trailer.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "trailer.h"
-
-namespace ns3 {
-
-Trailer::~Trailer ()
-{}
-
-}; // namespace ns3
--- a/src/common/trailer.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trailer.h Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,28 @@
#ifndef TRAILER_H
#define TRAILER_H
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Trailer
+ * \brief this macro should be instantiated exactly once for each
+ * new type of Trailer
+ *
+ * This macro will ensure that your new Trailer type is registered
+ * within the packet trailer registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TRAILER_ENSURE_REGISTERED(x) \
+static class thisisaveryverylongclassname ##x \
+{ \
+ public: \
+ thisisaveryverylongclassname ##x () \
+ { uint32_t uid; uid = x::GetUid ();} \
+} g_thisisanotherveryveryverylongname ##x;
namespace ns3 {
@@ -30,98 +51,66 @@
* \brief Protocol trailer serialization and deserialization.
*
* Every Protocol trailer which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- * - ns3::Trailer::SerializeTo
- * - ns3::Trailer::DeserializeFrom
- * - ns3::Trailer::GetSerializedSize
- * - ns3::Trailer::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ * - a default constructor: is used by the internal implementation
+ * if the Packet class.
+ * - a static method named GetUid: is used to uniquely identify
+ * the type of each trailer. This method shall return a unique
+ * integer allocated with Trailer::AllocateUid.
+ * - a method named Serialize: is used by Packet::AddTrailer to
+ * store a trailer into the byte buffer of a packet.
+ * The input iterator points to the end of the byte buffer in
+ * which the trailer should write its data: the user is thus
+ * required to call Buffer::Iterator::Prev prior to writing
+ * any data in the buffer. The data written is expected to
+ * match bit-for-bit the representation of this trailer in a
+ * real network.
+ * - a method named GetSerializedSize: is used by Packet::AddTrailer
+ * to store a trailer into the byte buffer of a packet. This method
+ * should return the number of bytes which are needed to store
+ * the full trailer data by Serialize.
+ * - a method named Deserialize: is used by Packet::RemoveTrailer to
+ * re-create a trailer from the byte buffer of a packet. The input
+ * iterator points to the end of the byte buffer from which
+ * the trailer should read its data: the user is thus required to
+ * call Buffer::Iterator::Prev prior to reading any data from the
+ * buffer. The data read is expected to match bit-for-bit the
+ * representation of this trailer in real networks. This method
+ * shall return an integer which identifies the number of bytes read.
+ * - a method named Print: is used by Packet::Print to print the
+ * content of a trailer as ascii data to a c++ output stream.
+ * Although the trailer is free to format its output as it
+ * wishes, it is recommended to follow a few rules to integrate
+ * with the packet pretty printer: start with flags, small field
+ * values located between a pair of parens. Values should be separated
+ * by whitespace. Follow the parens with the important fields,
+ * separated by whitespace.
+ * i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ * - a method named GetName: is used by Packet::Print to print
+ * trailer fragments. This method should return a user-readable
+ * single word as all capitalized letters.
*
- * Note that the SerializeTo and DeserializeFrom methods behave
- * in a way which might seem surprising to users: the input iterator
- * really points to the end of the buffer to which and from which
- * the user is expected to write and read respectively. This means that
- * if the trailer has a fixed size and if the user wishes to read or
- * write that trailer from front to back, the user must rewind the
- * iterator by hand to go to the start of the trailer. Typical code
- * looks like this:
- * \code
- * void CrcTrailer::SerializeTo (Buffer::Iterator end)
- * {
- * end.Prev (4);
- * end.WriteHtonU32 (m_crc);
- * }
- * \endcode
- *
- * Some users would have expected that the iterator would be rewinded
- * to the "start" of the trailer before calling SerializeTo and DeserializeFrom.
- * However, this behavior was not implemented because it cannot be made to
- * work reliably for trailers which have a variable size. i.e., if the trailer
- * contains options, the code which calls DeserializeFrom cannot rewind
- * to the start of the trailer because it does not know the real size of the
- * trailer. Hence, to make this legitimate use-case work (variable-sized
- * trailers), the input iterator to DeserializeFrom and SerializeTo points
- * to the end of the trailer, and not its start.
*/
-class Trailer : public Chunk {
-public:
- virtual ~Trailer ();
-private:
- /**
- * \returns a user-readable name to identify this type of header.
- *
- * The string returned is expected to be a single word with
- * all capital letters
- */
- virtual std::string DoGetName (void) const = 0;
- /**
- * \param os the std output stream in which this
- * protocol trailer must print itself.
- *
- * Although the header is free to format its output as it
- * wishes, it is recommended to follow a few rules to integrate
- * with the packet pretty printer:
- * - start with flags, small field values located between a
- * pair of parens. Values should be separated by whitespace.
- * - follow the parens with the important fields, separated by
- * whitespace.
- * i.e.:
- * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
- */
- virtual void PrintTo (std::ostream &os) const = 0;
-
- /**
- * \returns the size of the serialized Trailer.
- *
- * This method is used by Packet::AddTrailer to reserve
- * enough room in the packet byte buffer prior to calling
- * Trailer::Serialize.
- */
- virtual uint32_t GetSerializedSize (void) const = 0;
-
- /**
- * \param end the buffer iterator in which the protocol trailer
- * must serialize itself. This iterator identifies
- * the end of the buffer.
- *
- * This iterator must be typically moved with the Buffer::Iterator::Prev
- * method before writing any byte in the buffer.
- */
- virtual void SerializeTo (Buffer::Iterator end) const = 0;
- /**
- * \param end the buffer iterator from which the protocol trailer must
- * deserialize itself. This iterator identifies
- * the end of the buffer.
- * \returns the number of bytes read from the buffer
- *
- * This iterator must be typically moved with the Buffer::Iterator::Prev
- * method before reading any byte in the buffer. The value returned
- * is used to trim the packet byte buffer of the corresponding
- * amount when this method is invoked from Packet::RemoveTrailer
- */
- virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0;
+class Trailer
+{
+protected:
+ template <typename T>
+ static uint32_t AllocateUid (std::string uidString);
};
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Trailer::AllocateUid (std::string uidString)
+{
+ return ChunkRegistry::RegisterTrailer<T> (uidString);
+}
+
+
+} // namespace ns3
#endif /* TRAILER_H */
--- a/src/common/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -1,22 +1,20 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- common = bld.create_obj('cpp', 'shlib')
- common.name = 'ns3-common'
- common.target = common.name
- common.uselib_local = ['ns3-core', 'ns3-simulator']
+ common = bld.create_ns3_module('common', ['core', 'simulator'])
common.source = [
'buffer.cc',
- 'chunk.cc',
- 'header.cc',
- 'trailer.cc',
+ 'chunk-registry.cc',
'packet-printer.cc',
'packet-metadata.cc',
+ 'packet-metadata-test.cc',
'packet.cc',
'tags.cc',
+ 'tag-registry.cc',
'pcap-writer.cc',
'variable-tracer-test.cc',
'trace-context.cc',
+ 'trace-context-element.cc',
'trace-resolver.cc',
'callback-trace-source.cc',
'empty-trace-resolver.cc',
@@ -28,10 +26,12 @@
headers = bld.create_obj('ns3header')
headers.source = [
'buffer.h',
- 'chunk.h',
+ 'chunk-registry.h',
'header.h',
'trailer.h',
'tags.h',
+ 'tag-registry.h',
+ 'tag.h',
'packet.h',
'packet-printer.h',
'packet-metadata.h',
@@ -41,6 +41,7 @@
'pcap-writer.h',
'callback-trace-source.h',
'trace-context.h',
+ 'trace-context-element.h',
'trace-resolver.h',
'empty-trace-resolver.h',
'composite-trace-resolver.h',
--- a/src/core/assert.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include "assert.h"
-
-namespace ns3 {
-
-void
-AssertBreakpoint (void)
-{
- int *a = 0;
- /**
- * we test here to allow a debugger to change the value of
- * the variable 'a' to allow the debugger to avoid the
- * subsequent segfault.
- */
- if (a == 0)
- {
- *a = 0;
- }
-}
-
-}//namespace ns3
--- a/src/core/assert.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/assert.h Wed Sep 05 18:35:39 2007 +0100
@@ -21,6 +21,12 @@
#ifndef ASSERT_H
#define ASSERT_H
+#ifdef NS3_ASSERT_ENABLE
+
+#include <iostream>
+
+#include "breakpoint.h"
+
/**
* \defgroup assert Assert
* \brief assert functions and macros
@@ -32,25 +38,6 @@
* removed in optimized builds.
*/
-namespace ns3 {
-
-/**
- * \ingroup debugging
- *
- * When an NS_ASSERT cannot verify its condition,
- * this function is called. This is where you should
- * be able to put a breakpoint with a debugger if
- * you want to catch assertions before the program
- * halts.
- */
-void AssertBreakpoint (void);
-
-}//namespace ns3
-
-#ifdef NS3_ASSERT_ENABLE
-
-#include <iostream>
-
/**
* \ingroup assert
* \param condition condition to verifiy.
@@ -65,10 +52,10 @@
{ \
if (!(condition)) \
{ \
- std::cout << "assert failed. file=" << __FILE__ << \
+ std::cerr << "assert failed. file=" << __FILE__ << \
", line=" << __LINE__ << ", cond=\""#condition << \
"\"" << std::endl; \
- ns3::AssertBreakpoint (); \
+ NS_BREAKPOINT (); \
} \
} \
while (false)
@@ -88,8 +75,8 @@
{ \
if (!(condition)) \
{ \
- std::cout << message << std::endl; \
- ns3::AssertBreakpoint (); \
+ std::cerr << message << std::endl; \
+ NS_BREAKPOINT (); \
} \
} \
while (false)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,58 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA, INESC Porto
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ */
+
+#include "breakpoint.h"
+#include "ns3/core-config.h"
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+namespace ns3 {
+
+#if defined (HAVE_SIGNAL_H) && defined (SIGTRAP)
+
+void
+BreakpointFallback (void)
+{
+ raise (SIGTRAP);
+}
+
+#else
+
+void
+BreakpointFallback (void)
+{
+ int *a = 0;
+ /**
+ * we test here to allow a debugger to change the value of
+ * the variable 'a' to allow the debugger to avoid the
+ * subsequent segfault.
+ */
+ if (a == 0)
+ {
+ *a = 0;
+ }
+}
+
+#endif // HAVE_SIGNAL_H
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INESC Porto, INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef BREAKPOINT_H
+#define BREAKPOINT_H
+
+namespace ns3 {
+
+/* Hacker macro to place breakpoints for selected machines.
+ * Actual use is strongly discouraged of course ;)
+ * Copied from GLib 2.12.9.
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/**
+ * \ingroup debugging
+ *
+ * Inserts a breakpoint instruction (or equivalent system call) into
+ * the code for selected machines. When an NS_ASSERT cannot verify its condition,
+ * this macro is used. Falls back to calling
+ * AssertBreakpoint() for architectures where breakpoint assembly
+ * instructions are not supported.
+ */
+#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2
+# define NS_BREAKPOINT() \
+ do{ __asm__ __volatile__ ("int $03"); }while(false)
+#elif defined (_MSC_VER) && defined (_M_IX86)
+# define NS_BREAKPOINT() \
+ do{ __asm int 3h }while(false)
+#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2
+# define NS_BREAKPOINT() \
+ do{ __asm__ __volatile__ ("bpt"); }while(false)
+#else /* !__i386__ && !__alpha__ */
+# define NS_BREAKPOINT() ns3::BreakpointFallback ()
+#endif
+
+/**
+ * \brief fallback breakpoint function
+ *
+ * This function is used by the NS_BREAKPOINT() macro as a fallback
+ * for when breakpoint assembly instructions are not available. It
+ * attempts to halt program execution either by a raising SIGTRAP, on
+ * unix systems, or by dereferencing a null pointer.
+ *
+ * Normally you should not call this function directly.
+ */
+void BreakpointFallback (void);
+
+
+}//namespace ns3
+
+
+#endif /* BREAKPOINT_H */
--- a/src/core/callback.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/callback.h Wed Sep 05 18:35:39 2007 +0100
@@ -358,7 +358,7 @@
/**
* \ingroup MakeCallback
- * \param mem_ptr class method member pointer
+ * \param memPtr class method member pointer
* \param objPtr class instance
* \return a wrapper Callback
* Build Callbacks for class method members which takes no arguments
--- a/src/core/component-manager.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/component-manager.h Wed Sep 05 18:35:39 2007 +0100
@@ -348,7 +348,7 @@
* result.
*/
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
- static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5);
+ static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
private:
friend void RegisterCallback (ClassId classId, CallbackBase *callback,
--- a/src/core/debug.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/debug.cc Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
#include "debug.h"
#include "assert.h"
#include "ns3/core-config.h"
+#include "fatal-error.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -53,6 +54,7 @@
{
return;
}
+ bool allFound = true;
std::string env = envVar;
std::string::size_type cur = 0;
std::string::size_type next = 0;
@@ -88,7 +90,7 @@
}
if (!found)
{
- std::cout << "No debug component named=\"" << tmp << "\"" << std::endl;
+ allFound = false;
}
if (next == std::string::npos)
{
@@ -100,6 +102,11 @@
break;
}
}
+ if (allFound)
+ {
+ g_firstDebug = true;
+ }
+
#endif
}
@@ -122,7 +129,6 @@
if (g_firstDebug)
{
DebugComponentEnableEnvVar ();
- g_firstDebug = false;
}
return m_isEnabled;
}
--- a/src/core/debug.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/debug.h Wed Sep 05 18:35:39 2007 +0100
@@ -110,7 +110,7 @@
{ \
if (g_debug.IsEnabled ()) \
{ \
- std::cout << msg << std::endl; \
+ std::cerr << msg << std::endl; \
} \
} \
while (false)
@@ -125,7 +125,7 @@
#define NS_DEBUG_UNCOND(msg) \
do \
{ \
- std::cout << msg << std::endl; \
+ std::cerr << msg << std::endl; \
} \
while (false)
--- a/src/core/default-value.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/default-value.cc Wed Sep 05 18:35:39 2007 +0100
@@ -23,6 +23,52 @@
namespace ns3 {
+namespace DefaultValue {
+
+enum BindStatus {
+ OK,
+ INVALID_VALUE,
+ NOT_FOUND
+};
+
+
+static
+enum BindStatus
+BindSafe (std::string name, std::string value)
+{
+ for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
+ i != DefaultValueList::End (); i++)
+ {
+ DefaultValueBase *cur = *i;
+ if (cur->GetName () == name)
+ {
+ if (!cur->ParseValue (value))
+ {
+ return INVALID_VALUE;
+ }
+ return OK;
+ }
+ }
+ return NOT_FOUND;
+}
+
+void
+Bind (std::string name, std::string value)
+{
+ switch (BindSafe (name, value)) {
+ case INVALID_VALUE:
+ NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
+ break;
+ case NOT_FOUND:
+ NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
+ break;
+ case OK:
+ break;
+ }
+}
+
+}
+
DefaultValueBase::DefaultValueBase (const std::string &name,
const std::string &help)
: m_name (name),
@@ -112,48 +158,6 @@
return &list;
}
-enum BindStatus {
- OK,
- INVALID_VALUE,
- NOT_FOUND
-};
-
-
-static
-enum BindStatus
-BindSafe (std::string name, std::string value)
-{
- for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
- i != DefaultValueList::End (); i++)
- {
- DefaultValueBase *cur = *i;
- if (cur->GetName () == name)
- {
- if (!cur->ParseValue (value))
- {
- return INVALID_VALUE;
- }
- return OK;
- }
- }
- return NOT_FOUND;
-}
-
-void
-Bind (std::string name, std::string value)
-{
- switch (BindSafe (name, value)) {
- case INVALID_VALUE:
- NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
- break;
- case NOT_FOUND:
- NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
- break;
- case OK:
- break;
- }
-}
-
BooleanDefaultValue::BooleanDefaultValue (std::string name,
std::string help,
bool defaultValue)
@@ -341,85 +345,40 @@
bool
DefaultValueTest::RunTests (void)
{
- bool ok = true;
+ bool result = true;
BooleanDefaultValue a ("bool-a", "help a", true);
- if (!a.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-a", "false");
- if (a.GetValue ())
- {
- ok = false;
- }
+ NS_TEST_ASSERT (a.GetValue ());
+ DefaultValue::Bind ("bool-a", "false");
+ NS_TEST_ASSERT (!a.GetValue ());
BooleanDefaultValue b ("bool-b", "help b", false);
- Bind ("bool-b", "true");
- if (!b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "0");
- if (b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "1");
- if (!b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "f");
- if (b.GetValue ())
- {
- ok = false;
- }
- Bind ("bool-b", "t");
- if (!b.GetValue ())
- {
- ok = false;
- }
+ DefaultValue::Bind ("bool-b", "true");
+ NS_TEST_ASSERT (b.GetValue ());
+ DefaultValue::Bind ("bool-b", "0");
+ NS_TEST_ASSERT (!b.GetValue ());
+ DefaultValue::Bind ("bool-b", "1");
+ NS_TEST_ASSERT (b.GetValue ());
+ DefaultValue::Bind ("bool-b", "f");
+ NS_TEST_ASSERT (!b.GetValue ());
+ DefaultValue::Bind ("bool-b", "t");
+ NS_TEST_ASSERT (b.GetValue ());
- Bind ("bool-b", "false");
- if (b.GetValue ())
- {
- ok = false;
- }
- if (BindSafe ("bool-b", "tr") != INVALID_VALUE)
- {
- ok = false;
- }
+ DefaultValue::Bind ("bool-b", "false");
+ NS_TEST_ASSERT (!b.GetValue ());
+ NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("bool-b", "tr"), DefaultValue::INVALID_VALUE)
- NumericDefaultValue<int> i ("test-i", "help-i", -1);
- if (i.GetValue () != -1)
- {
- ok = false;
- }
- Bind ("test-i", "-2");
- if (i.GetValue () != -2)
- {
- ok = false;
- }
- Bind ("test-i", "+2");
- if (i.GetValue () != 2)
- {
- ok = false;
- }
- if (i.GetType () != "int32_t(-2147483648:2147483647)")
- {
- ok = false;
- }
+ NumericDefaultValue<int32_t> i ("test-i", "help-i", -1);
+ NS_TEST_ASSERT_EQUAL (i.GetValue (), -1);
+ DefaultValue::Bind ("test-i", "-2");
+ NS_TEST_ASSERT_EQUAL (i.GetValue (), -2);
+ DefaultValue::Bind ("test-i", "+2");
+ NS_TEST_ASSERT_EQUAL (i.GetValue (), 2);
+ NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)");
NumericDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
- if (ui32.GetType () != "uint32_t(0:4294967295)")
- {
- ok = false;
- }
- NumericDefaultValue<char> c ("test-c", "help-c", 10);
- if (c.GetValue () != 10)
- {
- ok = false;
- }
- Bind ("test-c", "257");
+ NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)");
+ NumericDefaultValue<int8_t> c ("test-c", "help-c", 10);
+ NS_TEST_ASSERT_EQUAL (c.GetValue (), 10);
+ DefaultValue::Bind ("test-c", "257");
NumericDefaultValue<float> x ("test-x", "help-x", 10.0);
NumericDefaultValue<double> y ("test-y", "help-y", 10.0);
@@ -429,19 +388,10 @@
MY_ENUM_A, "A",
MY_ENUM_B, "B",
0, (void*)0);
- if (e.GetValue () != MY_ENUM_C)
- {
- ok = false;
- }
- Bind ("test-e", "B");
- if (e.GetValue () != MY_ENUM_B)
- {
- ok = false;
- }
- if (BindSafe ("test-e", "D") != INVALID_VALUE)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_C);
+ DefaultValue::Bind ("test-e", "B");
+ NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_B);
+ NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("test-e", "D"), DefaultValue::INVALID_VALUE);
class MyEnumSubclass : public EnumDefaultValue<enum MyEnum>
{
@@ -456,15 +406,9 @@
AddPossibleValue (MY_ENUM_D, "D");
}
} e1 ;
- if (e1.GetValue () != MY_ENUM_B)
- {
- ok = false;
- }
- Bind ("test-e1", "D");
- if (e1.GetValue () != MY_ENUM_D)
- {
- ok = false;
- }
+ NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_B);
+ DefaultValue::Bind ("test-e1", "D");
+ NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_D);
DefaultValueList::Remove ("test-e1");
DefaultValueList::Remove ("test-e");
@@ -474,7 +418,7 @@
DefaultValueList::Remove ("test-c");
DefaultValueList::Remove ("test-ui32");
- return ok;
+ return result;
}
static DefaultValueTest g_default_value_tests;
--- a/src/core/default-value.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/default-value.h Wed Sep 05 18:35:39 2007 +0100
@@ -31,6 +31,25 @@
namespace ns3 {
+namespace DefaultValue
+{
+
+/**
+ * \ingroup config
+ * \param name name of variable to bind
+ * \param value value to bind to the specified variable
+ *
+ * If the variable name does not match any existing
+ * variable or if the value is not compatible with
+ * the variable type, this function will abort
+ * at runtime and print an error message detailing
+ * which variable or value triggered the problem.
+ */
+void Bind (std::string name, std::string value);
+
+}
+
+
class DefaultValueBase
{
public:
@@ -84,19 +103,6 @@
};
/**
- * \ingroup config
- * \param name name of variable to bind
- * \param value value to bind to the specified variable
- *
- * If the variable name does not match any existing
- * variable or if the value is not compatible with
- * the variable type, this function will abort
- * at runtime and print an error message detailing
- * which variable or value triggered the problem.
- */
-void Bind (std::string name, std::string value);
-
-/**
* \brief A Boolean variable for ns3::Bind
* \ingroup config
*
--- a/src/core/fatal-error.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/fatal-error.h Wed Sep 05 18:35:39 2007 +0100
@@ -21,7 +21,7 @@
#ifndef FATAL_ERROR_H
#define FATAL_ERROR_H
-#include "assert.h"
+#include "breakpoint.h"
#include <iostream>
/**
@@ -32,15 +32,15 @@
*
* When this macro is hit at runtime, the user-specified
* error message is output and the program is halted by calling
- * the ns3::AssertBreakpoint function. This macro is enabled
+ * the NS_DEBUG_BREAKPOINT macro. This macro is enabled
* unconditionally in all builds, including debug and optimized
* builds.
*/
#define NS_FATAL_ERROR(msg) \
do \
{ \
- std::cout << msg << std::endl; \
- ns3::AssertBreakpoint (); \
+ std::cerr << msg << std::endl; \
+ NS_BREAKPOINT (); \
} \
while (false)
--- a/src/core/ptr.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/ptr.cc Wed Sep 05 18:35:39 2007 +0100
@@ -28,9 +28,14 @@
namespace ns3 {
+template <typename T>
+void Foo (void) {}
+
+
class NoCount : public Object
{
public:
+ NoCount (void (*fn) (void));
NoCount (Callback<void> cb);
~NoCount ();
void Nothing (void) const;
@@ -292,12 +297,22 @@
callback ();
}
+
#if 0
// as expected, fails compilation.
{
Ptr<const Object> p = Create<NoCount> (cb);
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
}
+ // local types are not allowed as arguments to a template.
+ {
+ class B
+ {
+ public:
+ B () {}
+ };
+ Foo<B> ();
+ }
#endif
--- a/src/core/ptr.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/ptr.h Wed Sep 05 18:35:39 2007 +0100
@@ -65,7 +65,7 @@
template <typename U>
friend U *PeekPointer (const Ptr<U> &p);
- void Acquire (void) const;
+ inline void Acquire (void) const;
public:
/**
* Create an empty smart pointer
@@ -81,7 +81,16 @@
* same, so that object is deleted if no more references to it
* remain.
*/
- Ptr (T *ptr);
+ Ptr (T *ptr);
+ /**
+ * \param ptr raw pointer to manage
+ * \param ref if set to true, this method calls Ref, otherwise,
+ * it does not call Ref.
+ *
+ * Create a smart pointer which points to the object pointed to by
+ * the input raw pointer ptr.
+ */
+ Ptr (T *ptr, bool ref);
Ptr (Ptr const&o);
// allow conversions from T to T const.
template <typename U>
@@ -379,6 +388,16 @@
}
template <typename T>
+Ptr<T>::Ptr (T *ptr, bool ref)
+ : m_ptr (ptr)
+{
+ if (ref)
+ {
+ Acquire ();
+ }
+}
+
+template <typename T>
Ptr<T>::Ptr (Ptr const&o)
: m_ptr (PeekPointer (o))
{
--- a/src/core/random-variable.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/random-variable.cc Wed Sep 05 18:35:39 2007 +0100
@@ -108,8 +108,8 @@
{
if (RandomVariable::globalSeedSet)
{
- cout << "Random number generator already initialized!" << endl;
- cout << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
+ cerr << "Random number generator already initialized!" << endl;
+ cerr << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
return;
}
RandomVariable::globalSeed[0] = s0;
@@ -537,7 +537,7 @@
ValueCDF& current = emp[i];
if (current.value < prior.value || current.cdf < prior.cdf)
{ // Error
- cout << "Empirical Dist error,"
+ cerr << "Empirical Dist error,"
<< " current value " << current.value
<< " prior value " << prior.value
<< " current cdf " << current.cdf
--- a/src/core/random-variable.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/random-variable.h Wed Sep 05 18:35:39 2007 +0100
@@ -772,6 +772,7 @@
/**
* \param s Low end of the range
* \param l High end of the range
+ * \param mean mean of the distribution
* \return A triangularly distributed random number between s and l
*/
static double GetSingleValue(double s, double l, double mean);
--- a/src/core/rng-stream.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/rng-stream.cc Wed Sep 05 18:35:39 2007 +0100
@@ -269,11 +269,11 @@
}
for (i = 3; i < 6; ++i) {
if (seed[i] >= m2) {
- cout << "Seed[" << i << "] = " << seed[i] << endl;
- cerr << "*****************************************\n\n"
- << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
- << "\n\n*****************************************\n\n";
- return (false);
+ cerr << "Seed[" << i << "] = " << seed[i] << endl;
+ cerr << "*****************************************\n\n"
+ << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
+ << "\n\n*****************************************\n\n";
+ return (false);
}
}
if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) {
--- a/src/core/uid-manager.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/uid-manager.cc Wed Sep 05 18:35:39 2007 +0100
@@ -20,6 +20,7 @@
*/
#include "uid-manager.h"
#include "ns3/fatal-error.h"
+#include "ns3/assert.h"
namespace ns3 {
--- a/src/core/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -15,18 +15,22 @@
e.define = 'HAVE_GETENV'
e.run()
+ e = conf.create_header_configurator()
+ e.mandatory = False
+ e.name = 'signal.h'
+ e.define = 'HAVE_SIGNAL_H'
+ e.run()
+
conf.write_config_header('ns3/core-config.h')
def build(bld):
- core = bld.create_obj('cpp', 'shlib')
- core.name = 'ns3-core'
- core.target = core.name
+ core = bld.create_ns3_module('core')
core.source = [
'callback-test.cc',
'debug.cc',
- 'assert.cc',
+ 'breakpoint.cc',
'ptr.cc',
'object.cc',
'test.cc',
@@ -58,6 +62,7 @@
'object.h',
'debug.h',
'assert.h',
+ 'breakpoint.h',
'fatal-error.h',
'test.h',
'random-variable.h',
--- a/src/devices/csma-cd/backoff.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007, Emmanuelle Laprise
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
- */
-
-#include "backoff.h"
-
-namespace ns3 {
-
-Backoff::Backoff()
-{
- m_slotTime = MicroSeconds(1);
- m_minSlots = 1;
- m_maxSlots = 1000;
- m_ceiling = 10;
- m_maxRetries = 1000;
-
- ResetBackoffTime();
-}
-
-Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
- uint32_t ceiling, uint32_t maxRetries)
-{
- m_slotTime = slotTime;
- m_minSlots = minSlots;
- m_maxSlots = maxSlots;
- m_ceiling = ceiling;
- m_maxRetries = maxRetries;
-}
-
-Time
-Backoff::GetBackoffTime (void)
-{
- Time backoff;
- uint32_t ceiling;
-
- if ((m_ceiling > 0) &&(m_numBackoffRetries > m_ceiling))
- ceiling = m_ceiling;
- else
- ceiling = m_numBackoffRetries;
-
- uint32_t minSlot = m_minSlots;
- uint32_t maxSlot = (uint32_t)pow(2, ceiling) - 1;
- if (maxSlot > m_maxSlots)
- maxSlot = m_maxSlots;
-
- uint32_t backoffSlots =
- (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot);
-
- backoff = Scalar(backoffSlots) * m_slotTime;
- return (backoff);
-}
-
-void Backoff::ResetBackoffTime (void)
-{
- m_numBackoffRetries = 0;
-}
-
-bool Backoff::MaxRetriesReached(void) {
- return (m_numBackoffRetries >= m_maxRetries);
-}
-
-void Backoff::IncrNumRetries(void) {
- m_numBackoffRetries++;
-}
-
-} // namespace ns3
--- a/src/devices/csma-cd/backoff.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- *
- * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
- * Derived from the p2p net device file
-Transmi */
-
-#ifndef BACKOFF_H
-#define BACKOFF_H
-
-#include <stdint.h>
-#include "ns3/nstime.h"
-#include "ns3/random-variable.h"
-
-namespace ns3 {
-
- /**
- * \brief The backoff class is used for calculating backoff times
- * when many net devices can write to the same channel
- *
- */
-
-class Backoff {
-public:
- uint32_t m_minSlots; // Minimum number of backoff slots (when
- // multiplied by m_slotTime, determines minimum
- // backoff time)
- uint32_t m_maxSlots; // Maximim number of backoff slots (when
- // multiplied by m_slotTime, determines
- // maximum backoff time)
- uint32_t m_ceiling; // Caps the exponential function when the
- // number of retries reaches m_ceiling
- uint32_t m_maxRetries; // Maximum number of transmission retries
- // before the packet is dropped.
- Time m_slotTime; // Length of one slot. A slot time, it usually
- // the packet transmission time, if the packet
- // size is fixed.
-
- Backoff();
- Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
- uint32_t ceiling, uint32_t maxRetries);
-
- /**
- * \return The amount of time that the net device should wait before
- * trying to retransmit the packet
- */
- Time GetBackoffTime();
- /**
- * Indicates to the backoff object that the last packet was
- * successfully transmitted and that the number of retries should be
- * reset to 0.
- */
- void ResetBackoffTime();
- /**
- * \return True if the maximum number of retries has been reached
- */
- bool MaxRetriesReached();
- /**
- * Increments the number of retries by 1.
- */
- void IncrNumRetries();
-
-private:
- uint32_t m_numBackoffRetries; // Number of times that the
- // transmitter has tried to
- // unsuccessfully transmit the current
- // packet
-};
-
-}; // namespace ns3
-
-#endif // BACKOFF_H
-
--- a/src/devices/csma-cd/csma-cd-channel.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,371 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
- */
-
-#include "csma-cd-channel.h"
-#include "csma-cd-net-device.h"
-#include "ns3/packet.h"
-#include "ns3/simulator.h"
-#include "ns3/debug.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("CsmaCdChannel");
-
-namespace ns3 {
-
-CsmaCdDeviceRec::CsmaCdDeviceRec()
-{
- active = false;
-}
-
-CsmaCdDeviceRec::CsmaCdDeviceRec(Ptr<CsmaCdNetDevice> device)
-{
- devicePtr = device;
- active = true;
-}
-
-bool
-CsmaCdDeviceRec::IsActive() {
- return active;
-}
-
-
-//
-// By default, you get a channel with the name "CsmaCd Channel" that
-// has an "infitely" fast transmission speed and zero delay.
-CsmaCdChannel::CsmaCdChannel()
-:
- Channel ("CsmaCd Channel"),
- m_bps (DataRate(0xffffffff)),
- m_delay (Seconds(0))
-{
- NS_DEBUG("CsmaCdChannel::CsmaCdChannel ()");
- Init();
-}
-
-CsmaCdChannel::CsmaCdChannel(
- const DataRate& bps,
- const Time& delay)
-:
- Channel ("CsmaCd Channel"),
- m_bps (bps),
- m_delay (delay)
-{
- NS_DEBUG("CsmaCdChannel::CsmaCdChannel (" << Channel::GetName()
- << ", " << bps.GetBitRate() << ", " << delay << ")");
- Init();
-}
-
-CsmaCdChannel::CsmaCdChannel(
- const std::string& name,
- const DataRate& bps,
- const Time& delay)
-:
- Channel (name),
- m_bps (bps),
- m_delay (delay)
-{
- NS_DEBUG("CsmaCdChannel::CsmaCdChannel (" << name << ", " <<
- bps.GetBitRate() << ", " << delay << ")");
- Init();
-}
-
-void CsmaCdChannel::Init() {
- m_state = IDLE;
- m_deviceList.clear();
-}
-
-int32_t
-CsmaCdChannel::Attach(Ptr<CsmaCdNetDevice> device)
-{
- NS_DEBUG("CsmaCdChannel::Attach (" << device << ")");
- NS_ASSERT(device != 0);
-
- CsmaCdDeviceRec rec(device);
-
- m_deviceList.push_back(rec);
- return (m_deviceList.size() - 1);
-}
-
-bool
-CsmaCdChannel::Reattach(Ptr<CsmaCdNetDevice> device)
-{
- NS_DEBUG("CsmaCdChannel::Reattach (" << device << ")");
- NS_ASSERT(device != 0);
-
- std::vector<CsmaCdDeviceRec>::iterator it;
- for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
- {
- if (it->devicePtr == device)
- {
- if (!it->active)
- {
- it->active = true;
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- return false;
-}
-
-bool
-CsmaCdChannel::Reattach(uint32_t deviceId)
-{
- NS_DEBUG("CsmaCdChannel::Reattach (" << deviceId << ")");
- if (deviceId < m_deviceList.size())
- {
- return false;
- }
-
- if (m_deviceList[deviceId].active)
- {
- return false;
- }
- else
- {
- m_deviceList[deviceId].active = true;
- return true;
- }
-}
-
-bool
-CsmaCdChannel::Detach(uint32_t deviceId)
-{
- NS_DEBUG("CsmaCdChannel::Detach (" << deviceId << ")");
-
- if (deviceId < m_deviceList.size())
- {
- if (!m_deviceList[deviceId].active)
- {
- NS_DEBUG("CsmaCdChannel::Detach Device is already detached ("
- << deviceId << ")");
- return false;
- }
-
- m_deviceList[deviceId].active = false;
- if ((m_state == TRANSMITTING) && (m_currentSrc == deviceId))
- {
- NS_DEBUG("CsmaCdChannel::Detach Device is currently"
- << "transmitting (" << deviceId << ")");
- // Here we will need to place a warning in the packet
- }
-
- return true;
- }
- else
- {
- return false;
- }
-}
-
-bool
-CsmaCdChannel::Detach(Ptr<CsmaCdNetDevice> device)
-{
- NS_DEBUG("CsmaCdChannel::Detach (" << device << ")");
- NS_ASSERT(device != 0);
-
- std::vector<CsmaCdDeviceRec>::iterator it;
- for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
- {
- if ((it->devicePtr == device) && (it->active))
- {
- it->active = false;
- return true;
- }
- }
- return false;
-}
-
-bool
-CsmaCdChannel::TransmitStart(Packet& p, uint32_t srcId)
-{
- NS_DEBUG ("CsmaCdChannel::TransmitStart (" << &p << ", " << srcId
- << ")");
- NS_DEBUG ("CsmaCdChannel::TransmitStart (): UID is " <<
- p.GetUid () << ")");
-
- if (m_state != IDLE)
- {
- NS_DEBUG("CsmaCdChannel::TransmitStart (): state is not IDLE");
- return false;
- }
-
- if (!IsActive(srcId))
- {
- NS_DEBUG("CsmaCdChannel::TransmitStart (): ERROR: Seclected "
- << "source is not currently attached to network");
- return false;
- }
-
- NS_DEBUG("CsmaCdChannel::TransmitStart (): switch to TRANSMITTING");
- m_currentPkt = p;
- m_currentSrc = srcId;
- m_state = TRANSMITTING;
- return true;
-}
-
-bool
-CsmaCdChannel::IsActive(uint32_t deviceId)
-{
- return (m_deviceList[deviceId].active);
-}
-
-bool
-CsmaCdChannel::TransmitEnd()
-{
- NS_DEBUG("CsmaCdChannel::TransmitEnd (" << &m_currentPkt << ", "
- << m_currentSrc << ")");
- NS_DEBUG("CsmaCdChannel::TransmitEnd (): UID is " <<
- m_currentPkt.GetUid () << ")");
-
- NS_ASSERT(m_state == TRANSMITTING);
- m_state = PROPAGATING;
-
- bool retVal = true;
-
- if (!IsActive(m_currentSrc)) {
- NS_DEBUG("CsmaCdChannel::TransmitEnd (): ERROR: Seclected source "
- << "was detached before the end of the transmission");
- retVal = false;
- }
-
- NS_DEBUG ("CsmaCdChannel::TransmitEnd (): Schedule event in " <<
- m_delay.GetSeconds () << "sec");
-
- Simulator::Schedule (m_delay,
- &CsmaCdChannel::PropagationCompleteEvent,
- this);
- return retVal;
-}
-
-void
-CsmaCdChannel::PropagationCompleteEvent()
-{
- NS_DEBUG("CsmaCdChannel::PropagationCompleteEvent ("
- << &m_currentPkt << ")");
- NS_DEBUG ("CsmaCdChannel::PropagationCompleteEvent (): UID is " <<
- m_currentPkt.GetUid () << ")");
-
- NS_ASSERT(m_state == PROPAGATING);
- m_state = IDLE;
-
- NS_DEBUG ("CsmaCdChannel::PropagationCompleteEvent (): Receive");
-
- std::vector<CsmaCdDeviceRec>::iterator it;
- for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
- {
- if (it->IsActive())
- {
- it->devicePtr->Receive (m_currentPkt);
- }
- }
-}
-
-
-uint32_t
-CsmaCdChannel::GetNumActDevices (void)
-{
- int numActDevices = 0;
- std::vector<CsmaCdDeviceRec>::iterator it;
- for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
- {
- if (it->active)
- {
- numActDevices++;
- }
- }
- return numActDevices;
-}
-
-// This is not the number of active devices. This is the total number
-// of devices even if some were detached after.
-uint32_t
-CsmaCdChannel::GetNDevices (void) const
-{
- return (m_deviceList.size());
-}
-
-Ptr<NetDevice>
-CsmaCdChannel::GetDevice (uint32_t i) const
-{
- Ptr< CsmaCdNetDevice > netDevice;
-
- netDevice = m_deviceList[i].devicePtr;
- return netDevice;
-}
-
-int32_t
-CsmaCdChannel::GetDeviceNum (Ptr<CsmaCdNetDevice> device)
-{
- std::vector<CsmaCdDeviceRec>::iterator it;
- int i = 0;
- for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
- {
- if (it->devicePtr == device)
- {
- if (it->active)
- {
- return i;
- }
- else
- {
- return -2;
- }
- }
- i++;
- }
- return -1;
-}
-
-bool
-CsmaCdChannel::IsBusy (void)
-{
- if (m_state == IDLE)
- {
- return false;
- }
- else
- {
- return true;
- }
-}
-
-DataRate
-CsmaCdChannel::GetDataRate (void)
-{
- return m_bps;
-}
-
-Time
-CsmaCdChannel::GetDelay (void)
-{
- return m_delay;
-}
-
-WireState
-CsmaCdChannel::GetState(void)
-{
- return m_state;
-}
-
-} // namespace ns3
--- a/src/devices/csma-cd/csma-cd-channel.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,307 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- *
- * 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: Emmanuelle Laprise<emmanuelle.laprise@bluekazoo.ca>
- */
-
-#ifndef CSMA_CD_CHANNEL_H
-#define CSMA_CD_CHANNEL_H
-
-#include "ns3/channel.h"
-#include "ns3/ptr.h"
-#include "ns3/packet.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-
-namespace ns3 {
-
-class CsmaCdNetDevice;
-
- /**
- * \brief CsmaCdNetDevice Record
- *
- * Stores the information related to each net device that is
- * connected to the channel.
- */
- class CsmaCdDeviceRec {
- public:
- Ptr< CsmaCdNetDevice > devicePtr; /// Pointer to the net device
- bool active; /// Is net device enabled to TX/RX
-
- CsmaCdDeviceRec();
- CsmaCdDeviceRec(Ptr< CsmaCdNetDevice > device);
- /*
- * \return If the net device pointed to by the devicePtr is active
- * and ready to RX/TX.
- */
- bool IsActive();
- };
-
- /**
- * Current state of the channel
- */
- enum WireState
- {
- IDLE, /**< Channel is IDLE, no packet is being
- transmitted */
- TRANSMITTING, /**< Channel is BUSY, a packet is being written
- by a net device */
- PROPAGATING /**< Channel is BUSY, packet is propagating to
- all attached net devices */
- };
-
-/**
- * \brief CsmaCd Channel.
- *
- * This class represents a simple Csma/Cd channel that can be used
- * when many nodes are connected to one wire. It uses a single busy
- * flag to indicate if the channel is currently in use. It does not
- * take into account the distances between stations or the speed of
- * light to determine collisions.
- *
- * Each net device must query the state of the channel and make sure
- * that it is IDLE before writing a packet to the channel.
- *
- * When the channel is instaniated, the constructor takes parameters
- * for a single speed, in bits per second, and a speed-of-light delay
- * time as a Time object. When a net device is attached to a channel,
- * it is assigned a device ID, this is in order to facilitate the
- * check that makes sure that a net device that is trying to send a
- * packet to the channel is really connected to this channel
- *
- */
-class CsmaCdChannel : public Channel {
-public:
- /**
- * \brief Create a CsmaCdChannel
- *
- * By default, you get a channel with the name "CsmaCd Channel" that
- * has an "infitely" fast transmission speed and zero delay.
- */
- CsmaCdChannel ();
-
- /**
- * \brief Create a CsmaCdChannel
- *
- * \param bps The bitrate of the channel
- * \param delay Transmission delay through the channel
- */
- CsmaCdChannel (const DataRate& bps, const Time& delay);
-
- /**
- * \brief Create a CsmaCdChannel
- *
- * \param name the name of the channel for identification purposes
- * \param bps The bitrate of the channel
- * \param delay Transmission delay through the channel
- */
- CsmaCdChannel (const std::string& name,
- const DataRate& bps, const Time& delay);
-
- /**
- * \brief Attach a given netdevice to this channel
- *
- * \param device Device pointer to the netdevice to attach to the channel
- * \return The assigned device number
- */
- int32_t Attach (Ptr<CsmaCdNetDevice> device);
- /**
- * \brief Detach a given netdevice from this channel
- *
- * The net device is marked as inactive and it is not allowed to
- * receive or transmit packets
- *
- * \param device Device pointer to the netdevice to detach from the channel
- * \return True if the device is found and attached to the channel,
- * false if the device is not currently connected to the channel or
- * can't be found.
- */
- bool Detach (Ptr<CsmaCdNetDevice> device);
- /**
- * \brief Detach a given netdevice from this channel
- *
- * The net device is marked as inactive and it is not allowed to
- * receive or transmit packets
- *
- * \param deviceId The deviceID assigned to the net device when it
- * was connected to the channel
- * \return True if the device is found and attached to the channel,
- * false if the device is not currently connected to the channel or
- * can't be found.
- */
- bool Detach (uint32_t deviceId);
- /**
- * \brief Reattach a previously detached net device to the channel
- *
- * The net device is marked as active. It is now allowed to receive
- * or transmit packets. The net device must have been previously
- * attached to the channel using the attach function.
- *
- * \param deviceId The device ID assigned to the net device when it
- * was connected to the channel
- * \return True if the device is found and is not attached to the
- * channel, false if the device is currently connected to the
- * channel or can't be found.
- */
- bool Reattach(uint32_t deviceId);
- /**
- * \brief Reattach a previously detached net device to the channel
- *
- * The net device is marked as active. It is now allowed to receive
- * or transmit packets. The net device must have been previously
- * attached to the channel using the attach function.
- *
- * \param device Device pointer to the netdevice to detach from the channel
- * \return True if the device is found and is not attached to the
- * channel, false if the device is currently connected to the
- * channel or can't be found.
- */
- bool Reattach(Ptr<CsmaCdNetDevice> device);
- /**
- * \brief Start transmitting a packet over the channel
- *
- * If the srcId belongs to a net device that is connected to the
- * channel, packet transmission begins, and the channel becomes busy
- * until the packet has completely reached all destinations.
- *
- * \param p A reference to the packet that will be transmitted over
- * the channel
- * \param srcId The device Id of the net device that wants to
- * transmit on the channel.
- * \return True if the channel is not busy and the transmitting net
- * device is currently active.
- */
- bool TransmitStart (Packet& p, uint32_t srcId);
- /**
- * \brief Indicates that the net device has finished transmitting
- * the packet over the channel
- *
- * The channel will stay busy until the packet has completely
- * propagated to all net devices attached to the channel. The
- * TransmitEnd function schedules the PropagationCompleteEvent which
- * will free the channel for further transmissions. Stores the
- * packet p as the m_currentPkt, the packet being currently
- * transmitting.
- *
- * \return Returns true unless the source was detached before it
- * completed its transmission.
- */
- bool TransmitEnd ();
- /**
- * \brief Indicates that the channel has finished propagating the
- * current packet. The channel is released and becomes free.
- *
- * Calls the receive function of every active net device that is
- * attached to the channel.
- */
- void PropagationCompleteEvent();
- /**
- * \return Returns the device number assigned to a net device by the
- * channel
- *
- * \param device Device pointer to the netdevice for which the device
- * number is needed
- */
- int32_t GetDeviceNum (Ptr<CsmaCdNetDevice> device);
- /**
- * \return Returns the state of the channel (IDLE -- free,
- * TRANSMITTING -- busy, PROPAGATING - busy )
- */
- WireState GetState();
-
- /**
- * \brief Indicates if the channel is busy. The channel will only
- * accept new packets for transmission if it is not busy.
- *
- * \return Returns true if the channel is busy and false if it is
- * free.
- */
- bool IsBusy();
-
- /**
- * \brief Indicates if a net device is currently attached or
- * detached from the channel.
- *
- * \param deviceId The ID that was assigned to the net device when
- * it was attached to the channel.
- * \return Returns true if the net device is attached to the
- * channel, false otherwise.
- */
- bool IsActive(uint32_t deviceId);
- /**
- * \return Returns the number of net devices that are currently
- * attached to the channel.
- */
- uint32_t GetNumActDevices (void);
- /**
- * \return Returns the total number of devices including devices
- * that have been detached from the channel.
- */
- virtual uint32_t GetNDevices (void) const;
- /**
- * \param i The deviceId of the net device for which we want the
- * pointer.
- * \return Returns the pointer to the net device that is associated
- * with deviceId i.
- */
- virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
-
- virtual DataRate GetDataRate (void);
- virtual Time GetDelay (void);
-
-private:
- DataRate m_bps; /// Data rate of the channel
- Time m_delay; /// Delay of the channel.
-
- /**
- * List of the net devices that have been or are currently connected
- * to the channel.
- *
- * Devices are nor removed from this list, they are marked as
- * inactive. Otherwise the assigned device IDs will not refer to the
- * correct NetDevice. The DeviceIds are used so that it is possible
- * to have a number to refer to an entry in the list so that the
- * whole list does not have to be searched when making sure that a
- * source is attached to a channel when it is transmitting data.
- */
- std::vector< CsmaCdDeviceRec > m_deviceList;
- /**
- * Packet that is currently being transmitted on the channel (or last
- * packet to have been transmitted on the channel if the channel is
- * free.)
- */
- Packet m_currentPkt;
- /**
- * Device Id of the source that is currently transmitting on the
- * channel. Or last source to have transmitted a packet on the
- * channel, if the channel is currently not busy.
- */
- uint32_t m_currentSrc;
- /**
- * Current state of the channel
- */
- WireState m_state;
- /**
- * Initializes the channel when it is constructed. Resets the
- * deviceList and sets the channel state to IDLE.
- */
- void Init (void);
-};
-
-} // namespace ns3
-
-#endif /* CSMA_CD_CHANNEL_H */
--- a/src/devices/csma-cd/csma-cd-ipv4-topology.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-
-#include <algorithm>
-#include "ns3/assert.h"
-#include "ns3/debug.h"
-#include "ns3/fatal-error.h"
-#include "ns3/nstime.h"
-#include "ns3/internet-node.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/queue.h"
-
-#include "csma-cd-channel.h"
-#include "csma-cd-net-device.h"
-#include "csma-cd-ipv4-topology.h"
-
-namespace ns3 {
-
-
-uint32_t
-CsmaCdIpv4Topology::AddIpv4CsmaCdNode(Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr)
-{
- Ptr<Queue> q = Queue::CreateDefault ();
-
- // assume full-duplex
- Ptr<CsmaCdNetDevice> nd0 = Create<CsmaCdNetDevice> (n1, addr,
- ns3::CsmaCdNetDevice::IP_ARP,
- true, true);
- nd0->AddQueue(q);
- nd0->Attach (ch);
- return nd0->GetIfIndex ();
-}
-
-
-void
-CsmaCdIpv4Topology::AddIpv4LlcCsmaCdNode(Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr)
-{
- Ptr<Queue> q = Queue::CreateDefault ();
-
- Ptr<CsmaCdNetDevice> nd0 = Create<CsmaCdNetDevice> (n1, addr,
- ns3::CsmaCdNetDevice::LLC,
- true, false);
- nd0->AddQueue(q);
- nd0->Attach (ch);
-
- Ptr<CsmaCdNetDevice> nd1 = Create<CsmaCdNetDevice> (n1, addr,
- ns3::CsmaCdNetDevice::LLC,
- false, true);
- nd1->AddQueue(q);
- nd1->Attach (ch);
-}
-
-void
-CsmaCdIpv4Topology::AddIpv4RawCsmaCdNode(Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr)
-{
- Ptr<Queue> q = Queue::CreateDefault ();
-
- Ptr<CsmaCdNetDevice> nd0 = Create<CsmaCdNetDevice> (n1, addr,
- ns3::CsmaCdNetDevice::RAW,
- true, false);
- nd0->AddQueue(q);
- nd0->Attach (ch);
-
- Ptr<CsmaCdNetDevice> nd1 = Create<CsmaCdNetDevice> (n1, addr,
- ns3::CsmaCdNetDevice::RAW,
- false, true);
- nd1->AddQueue(q);
- nd1->Attach (ch);
-}
-
-void
-CsmaCdIpv4Topology::AddIpv4Address(Ptr<Node> n1,
- int ndNum,
- const Ipv4Address& addr1,
- const Ipv4Mask& netmask1)
-{
-
- // Duplex link is assumed to be subnetted as a /30
- // May run this unnumbered in the future?
- Ipv4Mask netmask(netmask1);
-
- Ptr<NetDevice> nd1 = n1->GetDevice(ndNum);
-
- Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
- uint32_t index1 = ip1->AddInterface (nd1);
-
- ip1->SetAddress (index1, addr1);
- ip1->SetNetworkMask (index1, netmask);
- ip1->SetUp (index1);
-
-}
-
-void
-CsmaCdIpv4Topology::AddIpv4Routes (
- Ptr<NetDevice> nd1, Ptr<NetDevice> nd2)
-{
- // Assert that both are Ipv4 nodes
- Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
- Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
- NS_ASSERT(ip1 != 0 && ip2 != 0);
-
- // Get interface indexes for both nodes corresponding to the right channel
- uint32_t index1 = 0;
- bool found = false;
- for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
- {
- if (ip1 ->GetNetDevice (i) == nd1)
- {
- index1 = i;
- found = true;
- }
- }
- NS_ASSERT(found);
-
- uint32_t index2 = 0;
- found = false;
- for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
- {
- if (ip2 ->GetNetDevice (i) == nd2)
- {
- index2 = i;
- found = true;
- }
- }
- NS_ASSERT(found);
-
- ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
- ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2);
-}
-
-} // namespace ns3
-
--- a/src/devices/csma-cd/csma-cd-ipv4-topology.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-
-#ifndef __CSMA_CD_IPV4_TOPOLOGY_H__
-#define __CSMA_CD_IPV4_TOPOLOGY_H__
-
-#include "ns3/ptr.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/ipv4-route.h"
-#include "ns3/internet-node.h"
-#include "ns3/csma-cd-net-device.h"
-
-// The topology class consists of only static methods thar are used to
-// create the topology and data flows for an ns3 simulation
-
-namespace ns3 {
-
-class CsmaCdIpv4Channel;
-class Node;
-class IPAddr;
-class DataRate;
-class Queue;
-
-/**
- * \brief A helper class to create Topologies based on the
- * InternetNodes and CsmaCdChannels. Either the
- * SimpleCsmaCdNetDevice or the LLCCsmaCdNetDevice can be used
- * when constructing these topologies.
- */
-class CsmaCdIpv4Topology {
-public:
-
- /**
- * \param n1 Node to be attached to the Csma/Cd channel
- * \param ch CsmaCdChannel to which node n1 should be attached
- * \param addr Mac address of the node
- *
- * Add a Csma/Cd node to a Csma/Cd channel. This function adds
- * a EthernetCsmaCdNetDevice to the nodes so that they can
- * connect to a CsmaCdChannel. This means that Ethernet headers
- * and trailers will be added to the packet before sending out on
- * the net device.
- *
- * \return ifIndex of the device
- */
- static uint32_t AddIpv4CsmaCdNode( Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr);
-
- /**
- * \param n1 Node to be attached to the Csma/Cd channel
- * \param ch CsmaCdChannel to which node n1 should be attached
- * \param addr Mac address of the node
- *
- * Add a Csma/Cd node to a Csma/Cd channel. This function adds
- * a RawCsmaCdNetDevice to the nodes so that they can connect
- * to a CsmaCdChannel.
- */
- static void AddIpv4RawCsmaCdNode( Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr);
-
- /**
- * \param n1 Node to be attached to the Csma/Cd channel
- * \param ch CsmaCdChannel to which node n1 should be attached
- * \param addr Mac address of the node
- *
- * Add a Csma/Cd node to a Csma/Cd channel. This function adds
- * a LlcCsmaCdNetDevice to the nodes so that they can connect
- * to a CsmaCdChannel.
- */
- static void AddIpv4LlcCsmaCdNode( Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr);
-
-
-
- /**
- * \param n1 Node
- * \param ndNum NetDevice number with which to associate address
- * \param addr1 Ipv4 Address for ndNum of n1
- * \param network network mask for ndNum of node n1
- *
- * Add an Ipv4Address to the Ipv4 interface associated with the
- * ndNum CsmaCdIpv4NetDevices on the provided
- * CsmaCdIpv4Channel
- */
- static void AddIpv4Address(Ptr<Node> n1, int ndNum,
- const Ipv4Address& addr1,
- const Ipv4Mask& netmask1);
-
- /**
- * \param nd1 Node
- * \param nd2 Node
- *
- * Add an IPV4 host route between the two specified net devices
- */
- static void AddIpv4Routes (Ptr<NetDevice> nd1, Ptr<NetDevice> nd2);
-};
-
-} // namespace ns3
-
-#endif
-
--- a/src/devices/csma-cd/csma-cd-net-device.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,488 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
- */
-
-#include <iostream>
-#include <cassert>
-#include "ns3/debug.h"
-#include "ns3/queue.h"
-#include "ns3/simulator.h"
-#include "ns3/composite-trace-resolver.h"
-#include "csma-cd-net-device.h"
-#include "csma-cd-channel.h"
-#include "ns3/ethernet-header.h"
-#include "ns3/ethernet-trailer.h"
-#include "ns3/llc-snap-header.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("CsmaCdNetDevice");
-
-namespace ns3 {
-
-CsmaCdNetDevice::CsmaCdNetDevice (Ptr<Node> node, MacAddress addr,
- CsmaCdEncapsulationMode encapMode)
- : NetDevice(node, addr), m_bps (DataRate (0xffffffff))
-{
- NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")");
- m_encapMode = encapMode;
-
- Init(true, true);
-}
-
-CsmaCdNetDevice::CsmaCdNetDevice (Ptr<Node> node, MacAddress addr,
- CsmaCdEncapsulationMode encapMode,
- bool sendEnable, bool receiveEnable)
- : NetDevice(node, addr), m_bps (DataRate (0xffffffff))
-{
- NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")");
- m_encapMode = encapMode;
-
- Init(sendEnable, receiveEnable);
-}
-
-CsmaCdNetDevice::~CsmaCdNetDevice()
-{
- NS_DEBUG ("CsmaCdNetDevice::~CsmaCdNetDevice ()");
- m_queue = 0;
-}
-
-void
-CsmaCdNetDevice::DoDispose ()
-{
- m_channel = 0;
- NetDevice::DoDispose ();
-}
-
-//
-// Assignment operator for CsmaCdNetDevice.
-//
-// This uses the non-obvious trick of taking the source net device passed by
-// value instead of by reference. This causes the copy constructor to be
-// invoked (where the real work is done -- see above). All we have to do
-// here is to return the newly constructed net device.
-//
-/*
-CsmaCdNetDevice&
-CsmaCdNetDevice::operator= (const CsmaCdNetDevice nd)
-{
- NS_DEBUG ("CsmaCdNetDevice::operator= (" << &nd << ")");
- return *this;
-}
-*/
-
-void
-CsmaCdNetDevice::Init(bool sendEnable, bool receiveEnable)
-{
- m_txMachineState = READY;
- m_tInterframeGap = Seconds(0);
- m_channel = 0;
- m_queue = 0;
-
- EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff"));
- EnableMulticast();
- EnablePointToPoint();
-
- SetSendEnable (sendEnable);
- SetReceiveEnable (receiveEnable);
-}
-
-void
-CsmaCdNetDevice::SetSendEnable (bool sendEnable)
-{
- m_sendEnable = sendEnable;
-}
-
-void
-CsmaCdNetDevice::SetReceiveEnable (bool receiveEnable)
-{
- m_receiveEnable = receiveEnable;
-}
-bool
-CsmaCdNetDevice::IsSendEnabled (void)
-{
- return (m_sendEnable);
-}
-
-bool
-CsmaCdNetDevice::IsReceiveEnabled (void)
-{
- return (m_receiveEnable);
-}
-
-void
-CsmaCdNetDevice::SetDataRate (DataRate bps)
-{
- m_bps = bps;
-}
-
-void
-CsmaCdNetDevice::SetInterframeGap (Time t)
-{
- m_tInterframeGap = t;
-}
-
-void
-CsmaCdNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots,
- uint32_t maxSlots, uint32_t ceiling,
- uint32_t maxRetries)
-{
- m_backoff.m_slotTime = slotTime;
- m_backoff.m_minSlots = minSlots;
- m_backoff.m_maxSlots = maxSlots;
- m_backoff.m_ceiling = ceiling;
- m_backoff.m_maxRetries = maxRetries;
-}
-void
-CsmaCdNetDevice::AddHeader (Packet& p, const MacAddress& dest,
- uint16_t protocolNumber)
-{
- if (m_encapMode == RAW)
- {
- return;
- }
- EthernetHeader header (false);
- EthernetTrailer trailer;
- header.SetSource(this->GetAddress());
- header.SetDestination(dest);
-
- uint16_t lengthType = 0;
- switch (m_encapMode)
- {
- case ETHERNET_V1:
- lengthType = p.GetSize() + header.GetSize() + trailer.GetSize();
- break;
- case IP_ARP:
- lengthType = protocolNumber;
- break;
- case LLC: {
- LlcSnapHeader llc;
- llc.SetType (protocolNumber);
- p.AddHeader (llc);
- } break;
- case RAW:
- NS_ASSERT (false);
- break;
- }
- header.SetLengthType (lengthType);
- p.AddHeader(header);
- trailer.CalcFcs(p);
- p.AddTrailer(trailer);
-}
-bool
-CsmaCdNetDevice::ProcessHeader (Packet& p, uint16_t & param)
-{
- if (m_encapMode == RAW)
- {
- return true;
- }
- EthernetHeader header (false);
- EthernetTrailer trailer;
-
- p.RemoveTrailer(trailer);
- trailer.CheckFcs(p);
- p.RemoveHeader(header);
-
- if ((header.GetDestination() != this->GetBroadcast()) &&
- (header.GetDestination() != this->GetAddress()))
- {
- return false;
- }
-
- switch (m_encapMode)
- {
- case ETHERNET_V1:
- case IP_ARP:
- param = header.GetLengthType();
- break;
- case LLC: {
- LlcSnapHeader llc;
- p.RemoveHeader (llc);
- param = llc.GetType ();
- } break;
- case RAW:
- NS_ASSERT (false);
- break;
- }
- return true;
-}
-
-bool
-CsmaCdNetDevice::DoNeedsArp (void) const
-{
- if ((m_encapMode == IP_ARP) || (m_encapMode == LLC))
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-bool
-CsmaCdNetDevice::SendTo (Packet& p, const MacAddress& dest, uint16_t protocolNumber)
-{
- NS_DEBUG ("CsmaCdNetDevice::SendTo (" << &p << ")");
- NS_DEBUG ("CsmaCdNetDevice::SendTo (): UID is " << p.GetUid () << ")");
-
- NS_ASSERT (IsLinkUp ());
-
- // Only transmit if send side of net device is enabled
- if (!IsSendEnabled())
- return false;
-
- AddHeader(p, dest, protocolNumber);
-
- // Place the packet to be sent on the send queue
- if (m_queue->Enqueue(p) == false )
- {
- return false;
- }
- // If the device is idle, we need to start a transmission. Otherwise,
- // the transmission will be started when the current packet finished
- // transmission (see TransmitCompleteEvent)
- if (m_txMachineState == READY)
- {
- // Store the next packet to be transmitted
- if (m_queue->Dequeue (m_currentPkt))
- {
- TransmitStart();
- }
- }
- return true;
-}
-
-void
-CsmaCdNetDevice::TransmitStart ()
-{
- NS_DEBUG ("CsmaCdNetDevice::TransmitStart (" << &m_currentPkt << ")");
- NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): UID is "
- << m_currentPkt.GetUid () << ")");
-//
-// This function is called to start the process of transmitting a packet.
-// We need to tell the channel that we've started wiggling the wire and
-// schedule an event that will be executed when it's time to tell the
-// channel that we're done wiggling the wire.
-//
- NS_ASSERT_MSG((m_txMachineState == READY) || (m_txMachineState == BACKOFF),
- "Must be READY to transmit. Tx state is: "
- << m_txMachineState);
-
- // Only transmit if send side of net device is enabled
- if (!IsSendEnabled())
- return;
-
- if (m_channel->GetState() != IDLE)
- { // Channel busy, backoff and rechedule TransmitStart()
- m_txMachineState = BACKOFF;
- if (m_backoff.MaxRetriesReached())
- { // Too many retries reached, abort transmission of packet
- TransmitAbort();
- }
- else
- {
- m_backoff.IncrNumRetries();
- Time backoffTime = m_backoff.GetBackoffTime();
-
- NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): "
- << "Channel busy, backing off for "
- << backoffTime.GetSeconds () << "sec");
-
- Simulator::Schedule (backoffTime,
- &CsmaCdNetDevice::TransmitStart,
- this);
- }
- }
- else
- {
- // Channel is free, transmit packet
- m_txMachineState = BUSY;
- Time tEvent = Seconds (m_bps.CalculateTxTime(m_currentPkt.GetSize()));
-
- NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " <<
- "Schedule TransmitCompleteEvent in " <<
- tEvent.GetSeconds () << "sec");
-
- Simulator::Schedule (tEvent,
- &CsmaCdNetDevice::TransmitCompleteEvent,
- this);
- if (!m_channel->TransmitStart (m_currentPkt, m_deviceId))
- {
- NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " <<
- "Channel transmit start did not work at " <<
- tEvent.GetSeconds () << "sec");
- m_txMachineState = READY;
- }
- else
- {
- // Transmission success, reset backoff time parameters.
- m_backoff.ResetBackoffTime();
- }
- }
-}
-
-
-void
-CsmaCdNetDevice::TransmitAbort (void)
-{
- NS_DEBUG ("CsmaCdNetDevice::TransmitAbort ()");
-
- NS_DEBUG ("CsmaCdNetDevice::TransmitAbort (): Pkt UID is " <<
- m_currentPkt.GetUid () << ")");
-
- // Try to transmit a new packet
- bool found;
- found = m_queue->Dequeue (m_currentPkt);
- NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
- m_backoff.ResetBackoffTime();
- m_txMachineState = READY;
- TransmitStart ();
-}
-
-void
-CsmaCdNetDevice::TransmitCompleteEvent (void)
-{
- NS_DEBUG ("CsmaCdNetDevice::TransmitCompleteEvent ()");
-//
-// This function is called to finish the process of transmitting a packet.
-// We need to tell the channel that we've stopped wiggling the wire and
-// schedule an event that will be executed when it's time to re-enable
-// the transmitter after the interframe gap.
-//
- NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
- // Channel should be transmitting
- NS_ASSERT(m_channel->GetState() == TRANSMITTING);
- m_txMachineState = GAP;
-
- NS_DEBUG ("CsmaCdNetDevice::TransmitCompleteEvent (): Pkt UID is " <<
- m_currentPkt.GetUid () << ")");
- m_channel->TransmitEnd ();
-
- NS_DEBUG (
- "CsmaCdNetDevice::TransmitCompleteEvent (): " <<
- "Schedule TransmitReadyEvent in "
- << m_tInterframeGap.GetSeconds () << "sec");
-
- Simulator::Schedule (m_tInterframeGap,
- &CsmaCdNetDevice::TransmitReadyEvent,
- this);
-}
-
-void
-CsmaCdNetDevice::TransmitReadyEvent (void)
-{
- NS_DEBUG ("CsmaCdNetDevice::TransmitReadyEvent ()");
-//
-// This function is called to enable the transmitter after the interframe
-// gap has passed. If there are pending transmissions, we use this opportunity
-// to start the next transmit.
-//
- NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
- m_txMachineState = READY;
-
- // Get the next packet from the queue for transmitting
- if (m_queue->IsEmpty())
- {
- return;
- }
- else
- {
- bool found;
- found = m_queue->Dequeue (m_currentPkt);
- NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
- TransmitStart ();
- }
-}
-
-TraceResolver *
-CsmaCdNetDevice::DoCreateTraceResolver (TraceContext const &context)
-{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- resolver->Add ("queue",
- MakeCallback (&Queue::CreateTraceResolver,
- PeekPointer (m_queue)),
- CsmaCdNetDevice::QUEUE);
- resolver->Add ("rx",
- m_rxTrace,
- CsmaCdNetDevice::RX);
- return resolver;
-}
-
-bool
-CsmaCdNetDevice::Attach (Ptr<CsmaCdChannel> ch)
-{
- NS_DEBUG ("CsmaCdNetDevice::Attach (" << &ch << ")");
-
- m_channel = ch;
-
- m_deviceId = m_channel->Attach(this);
- m_bps = m_channel->GetDataRate ();
- m_tInterframeGap = m_channel->GetDelay ();
-
- /*
- * For now, this device is up whenever a channel is attached to it.
- */
- NotifyLinkUp ();
- return true;
-}
-
-void
-CsmaCdNetDevice::AddQueue (Ptr<Queue> q)
-{
- NS_DEBUG ("CsmaCdNetDevice::AddQueue (" << q << ")");
-
- m_queue = q;
-}
-
-void
-CsmaCdNetDevice::Receive (Packet& p)
-{
- NS_DEBUG ("CsmaCdNetDevice::Receive UID is (" << p.GetUid() << ")");
-
- // Only receive if send side of net device is enabled
- if (!IsReceiveEnabled())
- return;
-
- uint16_t param = 0;
- Packet packet = p;
-
- if (ProcessHeader(packet, param))
- {
- m_rxTrace (packet);
- ForwardUp (packet, param);
- }
- else
- {
- m_dropTrace (packet);
- }
-}
-
-Ptr<Queue>
-CsmaCdNetDevice::GetQueue(void) const
-{
- return m_queue;
-}
-
-Ptr<Channel>
-CsmaCdNetDevice::DoGetChannel(void) const
-{
- return m_channel;
-}
-
-} // namespace ns3
--- a/src/devices/csma-cd/csma-cd-net-device.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,409 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- *
- * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
- * Derived from the p2p net device file
- */
-
-#ifndef CSMA_CD_NET_DEVICE_H
-#define CSMA_CD_NET_DEVICE_H
-
-#include <string.h>
-#include "ns3/node.h"
-#include "ns3/backoff.h"
-#include "ns3/mac-address.h"
-#include "ns3/net-device.h"
-#include "ns3/callback.h"
-#include "ns3/packet.h"
-#include "ns3/callback-trace-source.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-#include "ns3/ptr.h"
-#include "ns3/random-variable.h"
-
-namespace ns3 {
-
-class Queue;
-class CsmaCdChannel;
-
-/**
- * \class CsmaCdNetDevice
- * \brief A Device for a CsmaCd Network Link.
- *
- * The Csma/Cd net device class is analogous to layer 1 and 2 of the
- * TCP stack. The NetDevice takes a raw packet of bytes and creates a
- * protocol specific packet from them. The Csma/Cd net device class
- * takes this packet and adds and processes the headers/trailers that
- * are associated with EthernetV1, EthernetV2, RAW or LLC
- * protocols. The EthernetV1 packet type adds and removes Ethernet
- * destination and source addresses. The LLC packet type adds and
- * removes LLC snap headers. The raw packet type does not add or
- * remove any headers. Each Csma/Cd net device will receive all
- * packets written to the Csma/Cd link. The ProcessHeader function can
- * be used to filter out the packets such that higher level layers
- * only receive packets that are addressed to their associated net
- * devices
- *
- */
-class CsmaCdNetDevice : public NetDevice {
-public:
- /**
- * Enumeration of the types of traces supported in the class.
- *
- */
- enum TraceType {
- QUEUE, /**< Trace queue events on the attached queue */
- RX, /**< Trace packet reception events (from the channel) */
- DROP /**< Trace packet drop events (from the channel) */
- };
-
- /**
- * Enumeration of the types of packets supported in the class.
- *
- */
-enum CsmaCdEncapsulationMode {
- ETHERNET_V1, /**< Version one ethernet packet, length field */
- IP_ARP, /**< Ethernet packet encapsulates IP/ARP packet */
- RAW, /**< Packet that contains no headers */
- LLC, /**< LLC packet encapsulation */
-};
-
- /**
- * Construct a CsmaCdNetDevice
- *
- * This is the constructor for the CsmaCdNetDevice. It takes as a
- * parameter the Node to which this device is connected. Ownership of the
- * Node pointer is not implied and the node must not be deleted.
- *
- * \param node the Node to which this device is connected.
- * \param addr The source MAC address of the net device.
- */
- CsmaCdNetDevice (Ptr<Node> node, MacAddress addr, CsmaCdEncapsulationMode pktType);
- CsmaCdNetDevice (Ptr<Node> node, MacAddress addr,
- CsmaCdEncapsulationMode pktType,
- bool sendEnable, bool receiveEnable);
- /**
- * Destroy a CsmaCdNetDevice
- *
- * This is the destructor for the CsmaCdNetDevice.
- */
- virtual ~CsmaCdNetDevice();
- /**
- * Set the Data Rate used for transmission of packets. The data rate is
- * set in the Attach () method from the corresponding field in the channel
- * to which the device is attached. It can be overridden using this method.
- *
- * @see Attach ()
- * \param bps the data rate at which this object operates
- */
- void SetDataRate (DataRate bps);
- /**
- * Set the inteframe gap used to separate packets. The interframe gap
- * defines the minimum space required between packets sent by this device.
- * It is usually set in the Attach () method based on the speed of light
- * delay of the channel to which the device is attached. It can be
- * overridden using this method if desired.
- *
- * @see Attach ()
- * \param t the interframe gap time
- */
- void SetInterframeGap (Time t);
- /**
- * Set the backoff parameters used to determine the wait to retry
- * transmitting a packet when the channel is busy.
- *
- * @see Attach ()
- * \param slotTime Length of a packet slot (or average packet time)
- * \param minSlots Minimum number of slots to wait
- * \param maxSlots Maximum number of slots to wait
- * \param maxRetries Maximum number of retries before packet is discard
- * \param ceiling Cap on the exponential function when calculating max slots
- */
- void SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots,
- uint32_t maxRetries, uint32_t ceiling);
- /**
- * Attach the device to a channel.
- *
- * The function Attach is used to add a CsmaCdNetDevice to a
- * CsmaCdChannel.
- *
- * @see SetDataRate ()
- * @see SetInterframeGap ()
- * \param ch a pointer to the channel to which this object is being attached.
- */
- bool Attach (Ptr<CsmaCdChannel> ch);
- /**
- * Attach a queue to the CsmaCdNetDevice.
- *
- * The CsmaCdNetDevice "owns" a queue. This queue is created by the
- * CsmaCdTopology object and implements a queueing method such as
- * DropTail or RED. The CsmaCdNetDevice assumes ownership of this
- * queue and must delete it when the device is destroyed.
- *
- * @see CsmaCdTopology::AddCsmaCdLink ()
- * @see Queue
- * @see DropTailQueue
- * \param queue a pointer to the queue for which object is assuming
- * ownership.
- */
- void AddQueue (Ptr<Queue> queue);
- /**
- * Receive a packet from a connected CsmaCdChannel.
- *
- * The CsmaCdNetDevice receives packets from its connected channel
- * and forwards them up the protocol stack. This is the public method
- * used by the channel to indicate that the last bit of a packet has
- * arrived at the device.
- *
- * @see CsmaCdChannel
- * \param p a reference to the received packet
- */
- void Receive (Packet& p);
-
- bool IsSendEnabled (void);
- bool IsReceiveEnabled (void);
-
- void SetSendEnable (bool);
- void SetReceiveEnable (bool);
-
-protected:
- virtual bool DoNeedsArp (void) const;
- virtual void DoDispose (void);
- /**
- * Get a copy of the attached Queue.
- *
- * This method is provided for any derived class that may need to get
- * direct access to the underlying queue.
- *
- * \return a pointer to the queue.
- */
- Ptr<Queue> GetQueue (void) const;
- /**
- * Get a copy of the attached Channel
- *
- * This method is provided for any derived class that may need to get
- * direct access to the connected channel
- *
- * \return a pointer to the channel
- */
- virtual Ptr<Channel> DoGetChannel (void) const;
- /**
- * Adds the necessary headers and trailers to a packet of data in order to
- * respect the packet type
- *
- * \param p Packet to which header should be added
- * \param dest MAC destination address to which packet should be sent
- * \param protocolNumber In some protocols, identifies the type of
- * payload contained in this packet.
- */
- void AddHeader (Packet& p, const MacAddress& dest,
- uint16_t protocolNumber);
- /**
- * Removes, from a packet of data, all headers and trailers that
- * relate to the packet type
- *
- * \param p Packet whose headers need to be processed
- * \param param An integer parameter that can be set by the function
- * to return information gathered in the header
- * \return Returns true if the packet should be forwarded up the
- * protocol stack.
- */
- bool ProcessHeader (Packet& p, uint16_t & param);
-
-private:
- // disable copy constructor and operator =
- CsmaCdNetDevice &operator = (const CsmaCdNetDevice &o);
- CsmaCdNetDevice (const CsmaCdNetDevice &o);
- /**
- * Initializes variablea when construction object.
- */
- void Init (bool sendEnable, bool receiveEnable);
- /**
- * Send a Packet on the Csma/Cd network
- *
- * This method does not use a destination address since all packets
- * are broadcast to all NetDevices attached to the channel. Packet
- * should contain all needed headers at this time.
- *
- * If the device is ready to transmit, the next packet is read off
- * of the queue and stored locally until it has been transmitted.
- *
- * \param p a reference to the packet to send
- * \param dest destination address
- * \param protocolNumber -- this parameter is not used here
- * \return true if success, false on failure
- */
- virtual bool SendTo (Packet& p, const MacAddress& dest, uint16_t protocolNumber);
-
- /**
- * Start Sending a Packet Down the Wire.
- *
- * The TransmitStart method is the method that is used internally in
- * the CsmaCdNetDevice to begin the process of sending a packet
- * out on the channel. The corresponding method is called on the
- * channel to let it know that the physical device this class
- * represents has virually started sending signals, this causes the
- * channel to become busy. An event is scheduled for the time at
- * which the bits have been completely transmitted. If the channel
- * is busy, the method reschedules itself for a later time (within
- * the backoff period)
- *
- * @see CsmaCdChannel::TransmitStart ()
- * @see TransmitCompleteEvent ()
- */
- void TransmitStart ();
- /**
- * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
- *
- * The TransmitCompleteEvent method is used internally to finish the process
- * of sending a packet out on the channel. During execution of this method
- * the TransmitEnd method is called on the channel to let it know that the
- * physical device this class represents has virually finished sending
- * signals. The channel uses this event to begin its speed of light delay
- * timer after which it notifies the Net Device at the other end of the
- * link that the bits have arrived. During this method, the net device
- * also schedules the TransmitReadyEvent at which time the transmitter
- * becomes ready to send the next packet.
- *
- * @see CsmaCdChannel::TransmitEnd ()
- * @see TransmitReadyEvent ()
- */
- void TransmitCompleteEvent (void);
- /**
- * Cause the Transmitter to Become Ready to Send Another Packet.
- *
- * The TransmitReadyEvent method is used internally to re-enable the
- * transmit machine of the net device. It is scheduled after a suitable
- * interframe gap after the completion of the previous transmission.
- * The queue is checked at this time, and if there is a packet waiting on
- * the queue, the transmission process is begun.
- *
- * If a packet is in the queue, it is extracted for the queue as the
- * next packet to be transmitted by the net device.
- *
- * @see TransmitStart ()
- */
- void TransmitReadyEvent (void);
- /**
- * Create a Trace Resolver for events in the net device.
- * (NOT TESTED)
- * @see class TraceResolver
- */
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
-
- /**
- * Aborts the transmission of the current packet
- *
- * If the net device has tried to transmit a packet for more times
- * than the maximum allowed number of retries (channel always busy)
- * then the packet is dropped.
- *
- */
- void TransmitAbort (void);
-
- /**
- * Device ID returned by the attached functions. It is used by the
- * mp-channel to identify each net device to make sure that only
- * active net devices are writing to the channel
- */
- uint32_t m_deviceId;
-
- /**
- * Enable net device to send packets. True by default
- */
- bool m_sendEnable;
- /**
- * Enable net device to receive packets. True by default
- */
- bool m_receiveEnable;
- /**
- * Enumeration of the states of the transmit machine of the net device.
- */
- enum TxMachineState
- {
- READY, /**< The transmitter is ready to begin transmission of a packet */
- BUSY, /**< The transmitter is busy transmitting a packet */
- GAP, /**< The transmitter is in the interframe gap time */
- BACKOFF /**< The transmitter is waiting for the channel to be free */
- };
- /**
- * The state of the Net Device transmit state machine.
- * @see TxMachineState
- */
- TxMachineState m_txMachineState;
-
- /**
- * The type of packet that should be created by the AddHeader
- * function and that should be processed by the ProcessHeader
- * function.
- */
- CsmaCdEncapsulationMode m_encapMode;
- /**
- * The data rate that the Net Device uses to simulate packet transmission
- * timing.
- * @see class DataRate
- */
- DataRate m_bps;
- /**
- * The interframe gap that the Net Device uses to throttle packet
- * transmission
- * @see class Time
- */
- Time m_tInterframeGap;
- /**
- * Holds the backoff parameters and is used to calculate the next
- * backoff time to use when the channel is busy and the net device
- * is ready to transmit
- */
- Backoff m_backoff;
- /**
- * Next packet that will be transmitted (if transmitter is not
- * currently transmitting) or packet that is currently being
- * transmitted.
- */
- Packet m_currentPkt;
- /**
- * The CsmaCdChannel to which this CsmaCdNetDevice has been
- * attached.
- * @see class CsmaCdChannel
- */
- Ptr<CsmaCdChannel> m_channel;
- /**
- * The Queue which this CsmaCdNetDevice uses as a packet source.
- * Management of this Queue has been delegated to the CsmaCdNetDevice
- * and it has the responsibility for deletion.
- * @see class Queue
- * @see class DropTailQueue
- */
- Ptr<Queue> m_queue;
- /**
- * NOT TESTED
- * The trace source for the packet reception events that the device can
- * fire.
- *
- * @see class CallBackTraceSource
- * @see class TraceResolver
- */
- CallbackTraceSource<Packet &> m_rxTrace;
- CallbackTraceSource<Packet &> m_dropTrace;
-
-};
-
-}; // namespace ns3
-
-#endif // CSMA_CD_NET_DEVICE_H
-
--- a/src/devices/csma-cd/csma-cd-topology.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-
-//
-// Topology helper for CsmaCd channels in ns3.
-
-#include "ns3/assert.h"
-#include "ns3/debug.h"
-#include "ns3/queue.h"
-
-#include "csma-cd-channel.h"
-#include "csma-cd-net-device.h"
-#include "csma-cd-topology.h"
-#include "ns3/socket-factory.h"
-
-namespace ns3 {
-
-Ptr<CsmaCdChannel>
-CsmaCdTopology::CreateCsmaCdChannel(
- const DataRate& bps,
- const Time& delay)
-{
- Ptr<CsmaCdChannel> channel = Create<CsmaCdChannel> (bps, delay);
-
- return channel;
-}
-
-#if 0
-Ptr<CsmaCdNetDevice>
-CsmaCdTopology::AddCsmaCdEthernetNode(
- Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr)
-{
- Ptr<CsmaCdNetDevice> nd1 = Create<CsmaCdNetDevice> (n1, addr,
- ns3::CsmaCdNetDevice::ETHERNET_V1);
-
- Ptr<Queue> q = Queue::CreateDefault ();
- nd1->AddQueue(q);
- nd1->Attach (ch);
-
- return nd1;
-}
-
-Ptr<PacketSocket>
-CsmaCdTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
- Ptr<CsmaCdNetDevice> ndSrc,
- Ptr<CsmaCdNetDevice> ndDest)
-{
- Ptr<PacketSocket> socket = Create<PacketSocket> ();
- socket->Bind(ndSrc);
- socket->Connect(ndDest->GetAddress());
- app->Connect(socket);
-
- return socket;
-}
-
-Ptr<PacketSocket>
-CsmaCdTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
- Ptr<CsmaCdNetDevice> ndSrc,
- MacAddress macAddr)
-{
- Ptr<PacketSocket> socket = Create<PacketSocket> ();
- socket->Bind(ndSrc);
- socket->Connect(macAddr);
- app->Connect(socket);
-
- return socket;
-}
-
-Ptr<Socket>
-CsmaCdTopology::CreatePacketSocket(Ptr<Node> n1, std::string iid_name)
-{
- InterfaceId iid = InterfaceId::LookupByName (iid_name);
-
- Ptr<SocketFactory> socketFactory =
- n1->QueryInterface<SocketFactory> (iid);
-
- Ptr<Socket> socket = socketFactory->CreateSocket ();
-
- return socket;
-}
-#endif
-
-} // namespace ns3
-
--- a/src/devices/csma-cd/csma-cd-topology.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-// Topology helper for multipoint channels in ns3.
-//
-#ifndef CSMA_CD_TOPOLOGY_H
-#define CSMA_CD_TOPOLOGY_H
-
-#include "ns3/ptr.h"
-#include "ns3/csma-cd-net-device.h"
-#if 0
-#include "ns3/packet-socket.h"
-#include "ns3/packet-socket-app.h"
-#endif
-#include "ns3/node.h"
-#include "ns3/mac-address.h"
-
-// The topology class consists of only static methods thar are used to
-// create the topology and data flows for an ns3 simulation
-
-namespace ns3 {
-
-class CsmaCdChannel;
-class Node;
-class DataRate;
-class Queue;
-
-/**
- * \brief A helper class to create CsmaCd Topologies
- *
- * CsmaCd topologies are created based on the
- * ns3::CsmaCdNetDevice subclasses and ns3::CsmaCdChannel
- * objects. This class uses the EthernetNetDevice and
- * PacketSocket classes in order to create logical connections between
- * net devices. The PacketSocket class generates the data and the
- * EthernetNetDevice class creates ethernet packets from the
- * data, filling in source and destination addresses. The
- * EthernetNetDevice class filters received data packets
- * according to its destination Mac addresses.
- */
-class CsmaCdTopology {
-public:
- /**
- * \param dataRate Maximum transmission link rate
- * \param delay propagation delay between any two nodes
- * \return Pointer to the created CsmaCdChannel
- *
- * Create a CsmaCdChannel. All nodes connected to a multipoint
- * channels will receive all packets written to that channel
- */
- static Ptr<CsmaCdChannel> CreateCsmaCdChannel(
- const DataRate& dataRate, const Time& delay);
-
-#if 0
- /**
- * \param n1 Node to be attached to the multipoint channel
- * \param ch CsmaCdChannel to which node n1 should be attached
- * \param addr MacAddress that should be assigned to the
- * EthernetNetDevice that will be added to the node.
- *
- * Add a multipoint node to a multipoint channel
- */
- static Ptr<CsmaCdNetDevice> AddCsmaCdEthernetNode(Ptr<Node> n1,
- Ptr<CsmaCdChannel> ch,
- MacAddress addr);
-
- /**
- * \param app Application that will be sending data to the agent
- * \param ndSrc Net Device that will be sending the packets onto the
- * network
- * \param ndDest Net Device to which ndSrc will be sending the packets
- * \return A pointer to the PacketSocket
- *
- * Creates an PacketSocket and configure it to send packets between
- * two net devices
- */
-static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
- Ptr<CsmaCdNetDevice> ndSrc,
- Ptr<CsmaCdNetDevice> ndDest);
-
- /**
- * \param app Application that will be sending data to the agent
- * \param ndSrc Net Device that will be sending the packets onto the
- * network
- * \param macAddr Mac destination address for the packets send by
- * the ndSrc net device \return a Pointer to the created
- * PacketSocket
- *
- * Creates an PacketSocket and configure it to send packets from a
- * net device to a destination MacAddress
- */
-static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
- Ptr<CsmaCdNetDevice> ndSrc,
- MacAddress macAddr);
-
- /**
- * \param n1 Node from which socketfactory should be tested.
- * \param iid_name Interface identifier ("Packet", in this case)
- *
- * This is a test function to make sure that a socket can be created
- * by using the socketfactory interface provided in the
- * netdevicenode.
- */
-static Ptr<Socket> CreatePacketSocket(Ptr<Node> n1,
- std::string iid_name);
-#endif
-
-};
-} // namespace ns3
-
-#endif
-
--- a/src/devices/csma-cd/wscript Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-
-def build(bld):
- obj = bld.create_obj('cpp', 'shlib')
- obj.name = 'ns3-csma-cd'
- obj.target = obj.name
- obj.uselib_local = ['ns3-node']
- obj.source = [
- 'backoff.cc',
- 'csma-cd-net-device.cc',
- 'csma-cd-channel.cc',
- 'csma-cd-topology.cc',
- 'csma-cd-ipv4-topology.cc',
- ]
- headers = bld.create_obj('ns3header')
- headers.source = [
- 'backoff.h',
- 'csma-cd-net-device.h',
- 'csma-cd-channel.h',
- 'csma-cd-topology.h',
- 'csma-cd-ipv4-topology.h',
- ]
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007, Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "backoff.h"
+
+namespace ns3 {
+
+Backoff::Backoff()
+{
+ m_slotTime = MicroSeconds(1);
+ m_minSlots = 1;
+ m_maxSlots = 1000;
+ m_ceiling = 10;
+ m_maxRetries = 1000;
+
+ ResetBackoffTime();
+}
+
+Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+ uint32_t ceiling, uint32_t maxRetries)
+{
+ m_slotTime = slotTime;
+ m_minSlots = minSlots;
+ m_maxSlots = maxSlots;
+ m_ceiling = ceiling;
+ m_maxRetries = maxRetries;
+}
+
+Time
+Backoff::GetBackoffTime (void)
+{
+ Time backoff;
+ uint32_t ceiling;
+
+ if ((m_ceiling > 0) &&(m_numBackoffRetries > m_ceiling))
+ ceiling = m_ceiling;
+ else
+ ceiling = m_numBackoffRetries;
+
+ uint32_t minSlot = m_minSlots;
+ uint32_t maxSlot = (uint32_t)pow(2, ceiling) - 1;
+ if (maxSlot > m_maxSlots)
+ maxSlot = m_maxSlots;
+
+ uint32_t backoffSlots =
+ (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot);
+
+ backoff = Scalar(backoffSlots) * m_slotTime;
+ return (backoff);
+}
+
+void Backoff::ResetBackoffTime (void)
+{
+ m_numBackoffRetries = 0;
+}
+
+bool Backoff::MaxRetriesReached(void) {
+ return (m_numBackoffRetries >= m_maxRetries);
+}
+
+void Backoff::IncrNumRetries(void) {
+ m_numBackoffRetries++;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+Transmi */
+
+#ifndef BACKOFF_H
+#define BACKOFF_H
+
+#include <stdint.h>
+#include "ns3/nstime.h"
+#include "ns3/random-variable.h"
+
+namespace ns3 {
+
+ /**
+ * \brief The backoff class is used for calculating backoff times
+ * when many net devices can write to the same channel
+ *
+ */
+
+class Backoff {
+public:
+ uint32_t m_minSlots; // Minimum number of backoff slots (when
+ // multiplied by m_slotTime, determines minimum
+ // backoff time)
+ uint32_t m_maxSlots; // Maximim number of backoff slots (when
+ // multiplied by m_slotTime, determines
+ // maximum backoff time)
+ uint32_t m_ceiling; // Caps the exponential function when the
+ // number of retries reaches m_ceiling
+ uint32_t m_maxRetries; // Maximum number of transmission retries
+ // before the packet is dropped.
+ Time m_slotTime; // Length of one slot. A slot time, it usually
+ // the packet transmission time, if the packet
+ // size is fixed.
+
+ Backoff();
+ Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+ uint32_t ceiling, uint32_t maxRetries);
+
+ /**
+ * \return The amount of time that the net device should wait before
+ * trying to retransmit the packet
+ */
+ Time GetBackoffTime();
+ /**
+ * Indicates to the backoff object that the last packet was
+ * successfully transmitted and that the number of retries should be
+ * reset to 0.
+ */
+ void ResetBackoffTime();
+ /**
+ * \return True if the maximum number of retries has been reached
+ */
+ bool MaxRetriesReached();
+ /**
+ * Increments the number of retries by 1.
+ */
+ void IncrNumRetries();
+
+private:
+ uint32_t m_numBackoffRetries; // Number of times that the
+ // transmitter has tried to
+ // unsuccessfully transmit the current
+ // packet
+};
+
+}; // namespace ns3
+
+#endif // BACKOFF_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,371 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/debug.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("CsmaChannel");
+
+namespace ns3 {
+
+CsmaDeviceRec::CsmaDeviceRec()
+{
+ active = false;
+}
+
+CsmaDeviceRec::CsmaDeviceRec(Ptr<CsmaNetDevice> device)
+{
+ devicePtr = device;
+ active = true;
+}
+
+bool
+CsmaDeviceRec::IsActive() {
+ return active;
+}
+
+
+//
+// By default, you get a channel with the name "Csma Channel" that
+// has an "infitely" fast transmission speed and zero delay.
+CsmaChannel::CsmaChannel()
+:
+ Channel ("Csma Channel"),
+ m_bps (DataRate(0xffffffff)),
+ m_delay (Seconds(0))
+{
+ NS_DEBUG("CsmaChannel::CsmaChannel ()");
+ Init();
+}
+
+CsmaChannel::CsmaChannel(
+ const DataRate& bps,
+ const Time& delay)
+:
+ Channel ("Csma Channel"),
+ m_bps (bps),
+ m_delay (delay)
+{
+ NS_DEBUG("CsmaChannel::CsmaChannel (" << Channel::GetName()
+ << ", " << bps.GetBitRate() << ", " << delay << ")");
+ Init();
+}
+
+CsmaChannel::CsmaChannel(
+ const std::string& name,
+ const DataRate& bps,
+ const Time& delay)
+:
+ Channel (name),
+ m_bps (bps),
+ m_delay (delay)
+{
+ NS_DEBUG("CsmaChannel::CsmaChannel (" << name << ", " <<
+ bps.GetBitRate() << ", " << delay << ")");
+ Init();
+}
+
+void CsmaChannel::Init() {
+ m_state = IDLE;
+ m_deviceList.clear();
+}
+
+int32_t
+CsmaChannel::Attach(Ptr<CsmaNetDevice> device)
+{
+ NS_DEBUG("CsmaChannel::Attach (" << device << ")");
+ NS_ASSERT(device != 0);
+
+ CsmaDeviceRec rec(device);
+
+ m_deviceList.push_back(rec);
+ return (m_deviceList.size() - 1);
+}
+
+bool
+CsmaChannel::Reattach(Ptr<CsmaNetDevice> device)
+{
+ NS_DEBUG("CsmaChannel::Reattach (" << device << ")");
+ NS_ASSERT(device != 0);
+
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->devicePtr == device)
+ {
+ if (!it->active)
+ {
+ it->active = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+CsmaChannel::Reattach(uint32_t deviceId)
+{
+ NS_DEBUG("CsmaChannel::Reattach (" << deviceId << ")");
+ if (deviceId < m_deviceList.size())
+ {
+ return false;
+ }
+
+ if (m_deviceList[deviceId].active)
+ {
+ return false;
+ }
+ else
+ {
+ m_deviceList[deviceId].active = true;
+ return true;
+ }
+}
+
+bool
+CsmaChannel::Detach(uint32_t deviceId)
+{
+ NS_DEBUG("CsmaChannel::Detach (" << deviceId << ")");
+
+ if (deviceId < m_deviceList.size())
+ {
+ if (!m_deviceList[deviceId].active)
+ {
+ NS_DEBUG("CsmaChannel::Detach Device is already detached ("
+ << deviceId << ")");
+ return false;
+ }
+
+ m_deviceList[deviceId].active = false;
+ if ((m_state == TRANSMITTING) && (m_currentSrc == deviceId))
+ {
+ NS_DEBUG("CsmaChannel::Detach Device is currently"
+ << "transmitting (" << deviceId << ")");
+ // Here we will need to place a warning in the packet
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+CsmaChannel::Detach(Ptr<CsmaNetDevice> device)
+{
+ NS_DEBUG("CsmaChannel::Detach (" << device << ")");
+ NS_ASSERT(device != 0);
+
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if ((it->devicePtr == device) && (it->active))
+ {
+ it->active = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CsmaChannel::TransmitStart(Packet& p, uint32_t srcId)
+{
+ NS_DEBUG ("CsmaChannel::TransmitStart (" << &p << ", " << srcId
+ << ")");
+ NS_DEBUG ("CsmaChannel::TransmitStart (): UID is " <<
+ p.GetUid () << ")");
+
+ if (m_state != IDLE)
+ {
+ NS_DEBUG("CsmaChannel::TransmitStart (): state is not IDLE");
+ return false;
+ }
+
+ if (!IsActive(srcId))
+ {
+ NS_DEBUG("CsmaChannel::TransmitStart (): ERROR: Seclected "
+ << "source is not currently attached to network");
+ return false;
+ }
+
+ NS_DEBUG("CsmaChannel::TransmitStart (): switch to TRANSMITTING");
+ m_currentPkt = p;
+ m_currentSrc = srcId;
+ m_state = TRANSMITTING;
+ return true;
+}
+
+bool
+CsmaChannel::IsActive(uint32_t deviceId)
+{
+ return (m_deviceList[deviceId].active);
+}
+
+bool
+CsmaChannel::TransmitEnd()
+{
+ NS_DEBUG("CsmaChannel::TransmitEnd (" << &m_currentPkt << ", "
+ << m_currentSrc << ")");
+ NS_DEBUG("CsmaChannel::TransmitEnd (): UID is " <<
+ m_currentPkt.GetUid () << ")");
+
+ NS_ASSERT(m_state == TRANSMITTING);
+ m_state = PROPAGATING;
+
+ bool retVal = true;
+
+ if (!IsActive(m_currentSrc)) {
+ NS_DEBUG("CsmaChannel::TransmitEnd (): ERROR: Seclected source "
+ << "was detached before the end of the transmission");
+ retVal = false;
+ }
+
+ NS_DEBUG ("CsmaChannel::TransmitEnd (): Schedule event in " <<
+ m_delay.GetSeconds () << "sec");
+
+ Simulator::Schedule (m_delay,
+ &CsmaChannel::PropagationCompleteEvent,
+ this);
+ return retVal;
+}
+
+void
+CsmaChannel::PropagationCompleteEvent()
+{
+ NS_DEBUG("CsmaChannel::PropagationCompleteEvent ("
+ << &m_currentPkt << ")");
+ NS_DEBUG ("CsmaChannel::PropagationCompleteEvent (): UID is " <<
+ m_currentPkt.GetUid () << ")");
+
+ NS_ASSERT(m_state == PROPAGATING);
+
+ NS_DEBUG ("CsmaChannel::PropagationCompleteEvent (): Receive");
+
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->IsActive())
+ {
+ it->devicePtr->Receive (m_currentPkt);
+ }
+ }
+ m_state = IDLE;
+}
+
+
+uint32_t
+CsmaChannel::GetNumActDevices (void)
+{
+ int numActDevices = 0;
+ std::vector<CsmaDeviceRec>::iterator it;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->active)
+ {
+ numActDevices++;
+ }
+ }
+ return numActDevices;
+}
+
+// This is not the number of active devices. This is the total number
+// of devices even if some were detached after.
+uint32_t
+CsmaChannel::GetNDevices (void) const
+{
+ return (m_deviceList.size());
+}
+
+Ptr<NetDevice>
+CsmaChannel::GetDevice (uint32_t i) const
+{
+ Ptr< CsmaNetDevice > netDevice;
+
+ netDevice = m_deviceList[i].devicePtr;
+ return netDevice;
+}
+
+int32_t
+CsmaChannel::GetDeviceNum (Ptr<CsmaNetDevice> device)
+{
+ std::vector<CsmaDeviceRec>::iterator it;
+ int i = 0;
+ for (it = m_deviceList.begin(); it < m_deviceList.end(); it++)
+ {
+ if (it->devicePtr == device)
+ {
+ if (it->active)
+ {
+ return i;
+ }
+ else
+ {
+ return -2;
+ }
+ }
+ i++;
+ }
+ return -1;
+}
+
+bool
+CsmaChannel::IsBusy (void)
+{
+ if (m_state == IDLE)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+DataRate
+CsmaChannel::GetDataRate (void)
+{
+ return m_bps;
+}
+
+Time
+CsmaChannel::GetDelay (void)
+{
+ return m_delay;
+}
+
+WireState
+CsmaChannel::GetState(void)
+{
+ return m_state;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,307 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise<emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef CSMA_CHANNEL_H
+#define CSMA_CHANNEL_H
+
+#include "ns3/channel.h"
+#include "ns3/ptr.h"
+#include "ns3/packet.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class CsmaNetDevice;
+
+ /**
+ * \brief CsmaNetDevice Record
+ *
+ * Stores the information related to each net device that is
+ * connected to the channel.
+ */
+ class CsmaDeviceRec {
+ public:
+ Ptr< CsmaNetDevice > devicePtr; /// Pointer to the net device
+ bool active; /// Is net device enabled to TX/RX
+
+ CsmaDeviceRec();
+ CsmaDeviceRec(Ptr< CsmaNetDevice > device);
+ /*
+ * \return If the net device pointed to by the devicePtr is active
+ * and ready to RX/TX.
+ */
+ bool IsActive();
+ };
+
+ /**
+ * Current state of the channel
+ */
+ enum WireState
+ {
+ IDLE, /**< Channel is IDLE, no packet is being
+ transmitted */
+ TRANSMITTING, /**< Channel is BUSY, a packet is being written
+ by a net device */
+ PROPAGATING /**< Channel is BUSY, packet is propagating to
+ all attached net devices */
+ };
+
+/**
+ * \brief Csma Channel.
+ *
+ * This class represents a simple Csma channel that can be used
+ * when many nodes are connected to one wire. It uses a single busy
+ * flag to indicate if the channel is currently in use. It does not
+ * take into account the distances between stations or the speed of
+ * light to determine collisions.
+ *
+ * Each net device must query the state of the channel and make sure
+ * that it is IDLE before writing a packet to the channel.
+ *
+ * When the channel is instaniated, the constructor takes parameters
+ * for a single speed, in bits per second, and a speed-of-light delay
+ * time as a Time object. When a net device is attached to a channel,
+ * it is assigned a device ID, this is in order to facilitate the
+ * check that makes sure that a net device that is trying to send a
+ * packet to the channel is really connected to this channel
+ *
+ */
+class CsmaChannel : public Channel {
+public:
+ /**
+ * \brief Create a CsmaChannel
+ *
+ * By default, you get a channel with the name "Csma Channel" that
+ * has an "infitely" fast transmission speed and zero delay.
+ */
+ CsmaChannel ();
+
+ /**
+ * \brief Create a CsmaChannel
+ *
+ * \param bps The bitrate of the channel
+ * \param delay Transmission delay through the channel
+ */
+ CsmaChannel (const DataRate& bps, const Time& delay);
+
+ /**
+ * \brief Create a CsmaChannel
+ *
+ * \param name the name of the channel for identification purposes
+ * \param bps The bitrate of the channel
+ * \param delay Transmission delay through the channel
+ */
+ CsmaChannel (const std::string& name,
+ const DataRate& bps, const Time& delay);
+
+ /**
+ * \brief Attach a given netdevice to this channel
+ *
+ * \param device Device pointer to the netdevice to attach to the channel
+ * \return The assigned device number
+ */
+ int32_t Attach (Ptr<CsmaNetDevice> device);
+ /**
+ * \brief Detach a given netdevice from this channel
+ *
+ * The net device is marked as inactive and it is not allowed to
+ * receive or transmit packets
+ *
+ * \param device Device pointer to the netdevice to detach from the channel
+ * \return True if the device is found and attached to the channel,
+ * false if the device is not currently connected to the channel or
+ * can't be found.
+ */
+ bool Detach (Ptr<CsmaNetDevice> device);
+ /**
+ * \brief Detach a given netdevice from this channel
+ *
+ * The net device is marked as inactive and it is not allowed to
+ * receive or transmit packets
+ *
+ * \param deviceId The deviceID assigned to the net device when it
+ * was connected to the channel
+ * \return True if the device is found and attached to the channel,
+ * false if the device is not currently connected to the channel or
+ * can't be found.
+ */
+ bool Detach (uint32_t deviceId);
+ /**
+ * \brief Reattach a previously detached net device to the channel
+ *
+ * The net device is marked as active. It is now allowed to receive
+ * or transmit packets. The net device must have been previously
+ * attached to the channel using the attach function.
+ *
+ * \param deviceId The device ID assigned to the net device when it
+ * was connected to the channel
+ * \return True if the device is found and is not attached to the
+ * channel, false if the device is currently connected to the
+ * channel or can't be found.
+ */
+ bool Reattach(uint32_t deviceId);
+ /**
+ * \brief Reattach a previously detached net device to the channel
+ *
+ * The net device is marked as active. It is now allowed to receive
+ * or transmit packets. The net device must have been previously
+ * attached to the channel using the attach function.
+ *
+ * \param device Device pointer to the netdevice to detach from the channel
+ * \return True if the device is found and is not attached to the
+ * channel, false if the device is currently connected to the
+ * channel or can't be found.
+ */
+ bool Reattach(Ptr<CsmaNetDevice> device);
+ /**
+ * \brief Start transmitting a packet over the channel
+ *
+ * If the srcId belongs to a net device that is connected to the
+ * channel, packet transmission begins, and the channel becomes busy
+ * until the packet has completely reached all destinations.
+ *
+ * \param p A reference to the packet that will be transmitted over
+ * the channel
+ * \param srcId The device Id of the net device that wants to
+ * transmit on the channel.
+ * \return True if the channel is not busy and the transmitting net
+ * device is currently active.
+ */
+ bool TransmitStart (Packet& p, uint32_t srcId);
+ /**
+ * \brief Indicates that the net device has finished transmitting
+ * the packet over the channel
+ *
+ * The channel will stay busy until the packet has completely
+ * propagated to all net devices attached to the channel. The
+ * TransmitEnd function schedules the PropagationCompleteEvent which
+ * will free the channel for further transmissions. Stores the
+ * packet p as the m_currentPkt, the packet being currently
+ * transmitting.
+ *
+ * \return Returns true unless the source was detached before it
+ * completed its transmission.
+ */
+ bool TransmitEnd ();
+ /**
+ * \brief Indicates that the channel has finished propagating the
+ * current packet. The channel is released and becomes free.
+ *
+ * Calls the receive function of every active net device that is
+ * attached to the channel.
+ */
+ void PropagationCompleteEvent();
+ /**
+ * \return Returns the device number assigned to a net device by the
+ * channel
+ *
+ * \param device Device pointer to the netdevice for which the device
+ * number is needed
+ */
+ int32_t GetDeviceNum (Ptr<CsmaNetDevice> device);
+ /**
+ * \return Returns the state of the channel (IDLE -- free,
+ * TRANSMITTING -- busy, PROPAGATING - busy )
+ */
+ WireState GetState();
+
+ /**
+ * \brief Indicates if the channel is busy. The channel will only
+ * accept new packets for transmission if it is not busy.
+ *
+ * \return Returns true if the channel is busy and false if it is
+ * free.
+ */
+ bool IsBusy();
+
+ /**
+ * \brief Indicates if a net device is currently attached or
+ * detached from the channel.
+ *
+ * \param deviceId The ID that was assigned to the net device when
+ * it was attached to the channel.
+ * \return Returns true if the net device is attached to the
+ * channel, false otherwise.
+ */
+ bool IsActive(uint32_t deviceId);
+ /**
+ * \return Returns the number of net devices that are currently
+ * attached to the channel.
+ */
+ uint32_t GetNumActDevices (void);
+ /**
+ * \return Returns the total number of devices including devices
+ * that have been detached from the channel.
+ */
+ virtual uint32_t GetNDevices (void) const;
+ /**
+ * \param i The deviceId of the net device for which we want the
+ * pointer.
+ * \return Returns the pointer to the net device that is associated
+ * with deviceId i.
+ */
+ virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
+ virtual DataRate GetDataRate (void);
+ virtual Time GetDelay (void);
+
+private:
+ DataRate m_bps; /// Data rate of the channel
+ Time m_delay; /// Delay of the channel.
+
+ /**
+ * List of the net devices that have been or are currently connected
+ * to the channel.
+ *
+ * Devices are nor removed from this list, they are marked as
+ * inactive. Otherwise the assigned device IDs will not refer to the
+ * correct NetDevice. The DeviceIds are used so that it is possible
+ * to have a number to refer to an entry in the list so that the
+ * whole list does not have to be searched when making sure that a
+ * source is attached to a channel when it is transmitting data.
+ */
+ std::vector< CsmaDeviceRec > m_deviceList;
+ /**
+ * Packet that is currently being transmitted on the channel (or last
+ * packet to have been transmitted on the channel if the channel is
+ * free.)
+ */
+ Packet m_currentPkt;
+ /**
+ * Device Id of the source that is currently transmitting on the
+ * channel. Or last source to have transmitted a packet on the
+ * channel, if the channel is currently not busy.
+ */
+ uint32_t m_currentSrc;
+ /**
+ * Current state of the channel
+ */
+ WireState m_state;
+ /**
+ * Initializes the channel when it is constructed. Resets the
+ * deviceList and sets the channel state to IDLE.
+ */
+ void Init (void);
+};
+
+} // namespace ns3
+
+#endif /* CSMA_CHANNEL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,155 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#include <algorithm>
+#include "ns3/assert.h"
+#include "ns3/debug.h"
+#include "ns3/fatal-error.h"
+#include "ns3/nstime.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-ipv4-topology.h"
+
+namespace ns3 {
+
+uint32_t
+CsmaIpv4Topology::AddIpv4CsmaNode(Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr)
+{
+ Ptr<Queue> q = Queue::CreateDefault ();
+
+ // assume full-duplex
+ Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::IP_ARP,
+ true, true);
+ nd0->AddQueue(q);
+ nd0->Attach (ch);
+ return nd0->GetIfIndex ();
+}
+
+
+void
+CsmaIpv4Topology::AddIpv4LlcCsmaNode(Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr)
+{
+ Ptr<Queue> q = Queue::CreateDefault ();
+
+ Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::LLC,
+ true, false);
+ nd0->AddQueue(q);
+ nd0->Attach (ch);
+
+ Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::LLC,
+ false, true);
+ nd1->AddQueue(q);
+ nd1->Attach (ch);
+}
+
+void
+CsmaIpv4Topology::AddIpv4RawCsmaNode(Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr)
+{
+ Ptr<Queue> q = Queue::CreateDefault ();
+
+ Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::RAW,
+ true, false);
+ nd0->AddQueue(q);
+ nd0->Attach (ch);
+
+ Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::RAW,
+ false, true);
+ nd1->AddQueue(q);
+ nd1->Attach (ch);
+}
+
+void
+CsmaIpv4Topology::AddIpv4Address(Ptr<Node> n1,
+ int ndNum,
+ const Ipv4Address& addr1,
+ const Ipv4Mask& netmask1)
+{
+
+ // Duplex link is assumed to be subnetted as a /30
+ // May run this unnumbered in the future?
+ Ipv4Mask netmask(netmask1);
+
+ Ptr<NetDevice> nd1 = n1->GetDevice(ndNum);
+
+ Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t index1 = ip1->AddInterface (nd1);
+
+ ip1->SetAddress (index1, addr1);
+ ip1->SetNetworkMask (index1, netmask);
+ ip1->SetUp (index1);
+
+}
+
+void
+CsmaIpv4Topology::AddIpv4Routes (
+ Ptr<NetDevice> nd1, Ptr<NetDevice> nd2)
+{
+ // Assert that both are Ipv4 nodes
+ Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+ Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT(ip1 != 0 && ip2 != 0);
+
+ // Get interface indexes for both nodes corresponding to the right channel
+ uint32_t index1 = 0;
+ bool found = false;
+ for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
+ {
+ if (ip1 ->GetNetDevice (i) == nd1)
+ {
+ index1 = i;
+ found = true;
+ }
+ }
+ NS_ASSERT(found);
+
+ uint32_t index2 = 0;
+ found = false;
+ for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
+ {
+ if (ip2 ->GetNetDevice (i) == nd2)
+ {
+ index2 = i;
+ found = true;
+ }
+ }
+ NS_ASSERT(found);
+
+ ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
+ ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2);
+}
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,122 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#ifndef __CSMA_IPV4_TOPOLOGY_H__
+#define __CSMA_IPV4_TOPOLOGY_H__
+
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-net-device.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaIpv4Channel;
+class Node;
+class IPAddr;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Topologies based on the
+ * InternetNodes and CsmaChannels. Either the
+ * SimpleCsmaNetDevice or the LLCCsmaNetDevice can be used
+ * when constructing these topologies.
+ */
+class CsmaIpv4Topology {
+public:
+
+ /**
+ * \param n1 Node to be attached to the Csma channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr Mac address of the node
+ *
+ * Add a Csma node to a Csma channel. This function adds
+ * a EthernetCsmaNetDevice to the nodes so that they can
+ * connect to a CsmaChannel. This means that Ethernet headers
+ * and trailers will be added to the packet before sending out on
+ * the net device.
+ *
+ * \return ifIndex of the device
+ */
+ static uint32_t AddIpv4CsmaNode( Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr);
+
+ /**
+ * \param n1 Node to be attached to the Csma channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr Mac address of the node
+ *
+ * Add a Csma node to a Csma channel. This function adds
+ * a RawCsmaNetDevice to the nodes so that they can connect
+ * to a CsmaChannel.
+ */
+ static void AddIpv4RawCsmaNode( Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr);
+
+ /**
+ * \param n1 Node to be attached to the Csma channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr Mac address of the node
+ *
+ * Add a Csma node to a Csma channel. This function adds
+ * a LlcCsmaNetDevice to the nodes so that they can connect
+ * to a CsmaChannel.
+ */
+ static void AddIpv4LlcCsmaNode( Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr);
+
+
+
+ /**
+ * \param n1 Node
+ * \param ndNum NetDevice number with which to associate address
+ * \param addr1 Ipv4 Address for ndNum of n1
+ * \param netmask1 network mask for ndNum of node n1
+ *
+ * Add an Ipv4Address to the Ipv4 interface associated with the
+ * ndNum CsmaIpv4NetDevices on the provided
+ * CsmaIpv4Channel
+ */
+ static void AddIpv4Address(Ptr<Node> n1, int ndNum,
+ const Ipv4Address& addr1,
+ const Ipv4Mask& netmask1);
+
+ /**
+ * \param nd1 Node
+ * \param nd2 Node
+ *
+ * Add an IPV4 host route between the two specified net devices
+ */
+ static void AddIpv4Routes (Ptr<NetDevice> nd1, Ptr<NetDevice> nd2);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,574 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include <iostream>
+#include <cassert>
+#include "ns3/debug.h"
+#include "ns3/queue.h"
+#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "csma-net-device.h"
+#include "csma-channel.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/ethernet-trailer.h"
+#include "ns3/llc-snap-header.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("CsmaNetDevice");
+
+namespace ns3 {
+
+CsmaTraceType::CsmaTraceType (enum Type type)
+ : m_type (type)
+{}
+CsmaTraceType::CsmaTraceType ()
+ : m_type (RX)
+{}
+void
+CsmaTraceType::Print (std::ostream &os) const
+{
+ switch (m_type) {
+ case RX:
+ os << "dev-rx";
+ break;
+ case DROP:
+ os << "dev-drop";
+ break;
+ }
+}
+uint16_t
+CsmaTraceType::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<CsmaTraceType> ("CsmaTraceType");
+ return uid;
+}
+
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node)
+ : NetDevice (node, Eui48Address::Allocate ()),
+ m_bps (DataRate (0xffffffff))
+{
+ NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")");
+ m_encapMode = IP_ARP;
+ Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr,
+ CsmaEncapsulationMode encapMode)
+ : NetDevice(node, addr),
+ m_bps (DataRate (0xffffffff))
+{
+ NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")");
+ m_encapMode = encapMode;
+
+ Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr,
+ CsmaEncapsulationMode encapMode,
+ bool sendEnable, bool receiveEnable)
+ : NetDevice(node, addr),
+ m_bps (DataRate (0xffffffff))
+{
+ NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")");
+ m_encapMode = encapMode;
+
+ Init(sendEnable, receiveEnable);
+}
+
+CsmaNetDevice::~CsmaNetDevice()
+{
+ NS_DEBUG ("CsmaNetDevice::~CsmaNetDevice ()");
+ m_queue = 0;
+}
+
+void
+CsmaNetDevice::DoDispose ()
+{
+ m_channel = 0;
+ NetDevice::DoDispose ();
+}
+
+//
+// Assignment operator for CsmaNetDevice.
+//
+// This uses the non-obvious trick of taking the source net device passed by
+// value instead of by reference. This causes the copy constructor to be
+// invoked (where the real work is done -- see above). All we have to do
+// here is to return the newly constructed net device.
+//
+/*
+CsmaNetDevice&
+CsmaNetDevice::operator= (const CsmaNetDevice nd)
+{
+ NS_DEBUG ("CsmaNetDevice::operator= (" << &nd << ")");
+ return *this;
+}
+*/
+
+void
+CsmaNetDevice::Init(bool sendEnable, bool receiveEnable)
+{
+ m_txMachineState = READY;
+ m_tInterframeGap = Seconds(0);
+ m_channel = 0;
+ m_queue = 0;
+
+ EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
+ EnableMulticast();
+
+ SetSendEnable (sendEnable);
+ SetReceiveEnable (receiveEnable);
+}
+
+void
+CsmaNetDevice::SetSendEnable (bool sendEnable)
+{
+ m_sendEnable = sendEnable;
+}
+
+void
+CsmaNetDevice::SetReceiveEnable (bool receiveEnable)
+{
+ m_receiveEnable = receiveEnable;
+}
+bool
+CsmaNetDevice::IsSendEnabled (void)
+{
+ return (m_sendEnable);
+}
+
+bool
+CsmaNetDevice::IsReceiveEnabled (void)
+{
+ return (m_receiveEnable);
+}
+
+void
+CsmaNetDevice::SetDataRate (DataRate bps)
+{
+ m_bps = bps;
+}
+
+void
+CsmaNetDevice::SetInterframeGap (Time t)
+{
+ m_tInterframeGap = t;
+}
+
+void
+CsmaNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots,
+ uint32_t maxSlots, uint32_t ceiling,
+ uint32_t maxRetries)
+{
+ m_backoff.m_slotTime = slotTime;
+ m_backoff.m_minSlots = minSlots;
+ m_backoff.m_maxSlots = maxSlots;
+ m_backoff.m_ceiling = ceiling;
+ m_backoff.m_maxRetries = maxRetries;
+}
+void
+CsmaNetDevice::AddHeader (Packet& p, Eui48Address dest,
+ uint16_t protocolNumber)
+{
+ if (m_encapMode == RAW)
+ {
+ return;
+ }
+ EthernetHeader header (false);
+ EthernetTrailer trailer;
+ Eui48Address source = Eui48Address::ConvertFrom (GetAddress ());
+ header.SetSource(source);
+ header.SetDestination(dest);
+
+ uint16_t lengthType = 0;
+ switch (m_encapMode)
+ {
+ case ETHERNET_V1:
+ lengthType = p.GetSize() + header.GetSerializedSize() + trailer.GetSerializedSize();
+ break;
+ case IP_ARP:
+ lengthType = protocolNumber;
+ break;
+ case LLC: {
+ LlcSnapHeader llc;
+ llc.SetType (protocolNumber);
+ p.AddHeader (llc);
+ } break;
+ case RAW:
+ NS_ASSERT (false);
+ break;
+ }
+ header.SetLengthType (lengthType);
+ p.AddHeader(header);
+ trailer.CalcFcs(p);
+ p.AddTrailer(trailer);
+}
+bool
+CsmaNetDevice::ProcessHeader (Packet& p, uint16_t & param)
+{
+ if (m_encapMode == RAW)
+ {
+ return true;
+ }
+ EthernetHeader header (false);
+ EthernetTrailer trailer;
+
+ p.RemoveTrailer(trailer);
+ trailer.CheckFcs(p);
+ p.RemoveHeader(header);
+
+ if ((header.GetDestination() != GetBroadcast ()) &&
+ (header.GetDestination() != GetAddress ()))
+ {
+ return false;
+ }
+
+ switch (m_encapMode)
+ {
+ case ETHERNET_V1:
+ case IP_ARP:
+ param = header.GetLengthType();
+ break;
+ case LLC: {
+ LlcSnapHeader llc;
+ p.RemoveHeader (llc);
+ param = llc.GetType ();
+ } break;
+ case RAW:
+ NS_ASSERT (false);
+ break;
+ }
+ return true;
+}
+
+bool
+CsmaNetDevice::DoNeedsArp (void) const
+{
+ if ((m_encapMode == IP_ARP) || (m_encapMode == LLC))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+CsmaNetDevice::SendTo (
+ const Packet& packet,
+ const Address& dest,
+ uint16_t protocolNumber)
+{
+ Packet p = packet;
+ NS_DEBUG ("CsmaNetDevice::SendTo (" << &p << ")");
+ NS_DEBUG ("CsmaNetDevice::SendTo (): UID is " << p.GetUid () << ")");
+
+ NS_ASSERT (IsLinkUp ());
+
+ // Only transmit if send side of net device is enabled
+ if (!IsSendEnabled())
+ return false;
+
+ Eui48Address destination = Eui48Address::ConvertFrom (dest);
+ AddHeader(p, destination, protocolNumber);
+
+ // Place the packet to be sent on the send queue
+ if (m_queue->Enqueue(p) == false )
+ {
+ return false;
+ }
+ // If the device is idle, we need to start a transmission. Otherwise,
+ // the transmission will be started when the current packet finished
+ // transmission (see TransmitCompleteEvent)
+ if (m_txMachineState == READY)
+ {
+ // Store the next packet to be transmitted
+ if (m_queue->Dequeue (m_currentPkt))
+ {
+ TransmitStart();
+ }
+ }
+ return true;
+}
+
+void
+CsmaNetDevice::TransmitStart ()
+{
+ NS_DEBUG ("CsmaNetDevice::TransmitStart (" << &m_currentPkt << ")");
+ NS_DEBUG ("CsmaNetDevice::TransmitStart (): UID is "
+ << m_currentPkt.GetUid () << ")");
+//
+// This function is called to start the process of transmitting a packet.
+// We need to tell the channel that we've started wiggling the wire and
+// schedule an event that will be executed when it's time to tell the
+// channel that we're done wiggling the wire.
+//
+ NS_ASSERT_MSG((m_txMachineState == READY) || (m_txMachineState == BACKOFF),
+ "Must be READY to transmit. Tx state is: "
+ << m_txMachineState);
+
+ // Only transmit if send side of net device is enabled
+ if (!IsSendEnabled())
+ return;
+
+ if (m_channel->GetState() != IDLE)
+ { // Channel busy, backoff and rechedule TransmitStart()
+ m_txMachineState = BACKOFF;
+ if (m_backoff.MaxRetriesReached())
+ { // Too many retries reached, abort transmission of packet
+ TransmitAbort();
+ }
+ else
+ {
+ m_backoff.IncrNumRetries();
+ Time backoffTime = m_backoff.GetBackoffTime();
+
+ NS_DEBUG ("CsmaNetDevice::TransmitStart (): "
+ << "Channel busy, backing off for "
+ << backoffTime.GetSeconds () << "sec");
+
+ Simulator::Schedule (backoffTime,
+ &CsmaNetDevice::TransmitStart,
+ this);
+ }
+ }
+ else
+ {
+ // Channel is free, transmit packet
+ m_txMachineState = BUSY;
+ Time tEvent = Seconds (m_bps.CalculateTxTime(m_currentPkt.GetSize()));
+
+ NS_DEBUG ("CsmaNetDevice::TransmitStart (): " <<
+ "Schedule TransmitCompleteEvent in " <<
+ tEvent.GetSeconds () << "sec");
+
+ Simulator::Schedule (tEvent,
+ &CsmaNetDevice::TransmitCompleteEvent,
+ this);
+ if (!m_channel->TransmitStart (m_currentPkt, m_deviceId))
+ {
+ NS_DEBUG ("CsmaNetDevice::TransmitStart (): " <<
+ "Channel transmit start did not work at " <<
+ tEvent.GetSeconds () << "sec");
+ m_txMachineState = READY;
+ }
+ else
+ {
+ // Transmission success, reset backoff time parameters.
+ m_backoff.ResetBackoffTime();
+ }
+ }
+}
+
+
+void
+CsmaNetDevice::TransmitAbort (void)
+{
+ NS_DEBUG ("CsmaNetDevice::TransmitAbort ()");
+
+ NS_DEBUG ("CsmaNetDevice::TransmitAbort (): Pkt UID is " <<
+ m_currentPkt.GetUid () << ")");
+
+ // Try to transmit a new packet
+ bool found;
+ found = m_queue->Dequeue (m_currentPkt);
+ NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+ m_backoff.ResetBackoffTime();
+ m_txMachineState = READY;
+ TransmitStart ();
+}
+
+void
+CsmaNetDevice::TransmitCompleteEvent (void)
+{
+ NS_DEBUG ("CsmaNetDevice::TransmitCompleteEvent ()");
+//
+// This function is called to finish the process of transmitting a packet.
+// We need to tell the channel that we've stopped wiggling the wire and
+// schedule an event that will be executed when it's time to re-enable
+// the transmitter after the interframe gap.
+//
+ NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
+ // Channel should be transmitting
+ NS_ASSERT(m_channel->GetState() == TRANSMITTING);
+ m_txMachineState = GAP;
+
+ NS_DEBUG ("CsmaNetDevice::TransmitCompleteEvent (): Pkt UID is " <<
+ m_currentPkt.GetUid () << ")");
+ m_channel->TransmitEnd ();
+
+ NS_DEBUG (
+ "CsmaNetDevice::TransmitCompleteEvent (): " <<
+ "Schedule TransmitReadyEvent in "
+ << m_tInterframeGap.GetSeconds () << "sec");
+
+ Simulator::Schedule (m_tInterframeGap,
+ &CsmaNetDevice::TransmitReadyEvent,
+ this);
+}
+
+void
+CsmaNetDevice::TransmitReadyEvent (void)
+{
+ NS_DEBUG ("CsmaNetDevice::TransmitReadyEvent ()");
+//
+// This function is called to enable the transmitter after the interframe
+// gap has passed. If there are pending transmissions, we use this opportunity
+// to start the next transmit.
+//
+ NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
+ m_txMachineState = READY;
+
+ // Get the next packet from the queue for transmitting
+ if (m_queue->IsEmpty())
+ {
+ return;
+ }
+ else
+ {
+ bool found;
+ found = m_queue->Dequeue (m_currentPkt);
+ NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+ TransmitStart ();
+ }
+}
+
+TraceResolver *
+CsmaNetDevice::DoCreateTraceResolver (TraceContext const &context)
+{
+ CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+ resolver->Add ("queue",
+ MakeCallback (&Queue::CreateTraceResolver,
+ PeekPointer (m_queue)));
+ resolver->Add ("rx",
+ m_rxTrace,
+ CsmaTraceType (CsmaTraceType::RX));
+ resolver->Add ("drop",
+ m_dropTrace,
+ CsmaTraceType (CsmaTraceType::DROP));
+ return resolver;
+}
+
+bool
+CsmaNetDevice::Attach (Ptr<CsmaChannel> ch)
+{
+ NS_DEBUG ("CsmaNetDevice::Attach (" << &ch << ")");
+
+ m_channel = ch;
+
+ m_deviceId = m_channel->Attach(this);
+ m_bps = m_channel->GetDataRate ();
+ m_tInterframeGap = m_channel->GetDelay ();
+
+ /*
+ * For now, this device is up whenever a channel is attached to it.
+ */
+ NotifyLinkUp ();
+ return true;
+}
+
+void
+CsmaNetDevice::AddQueue (Ptr<Queue> q)
+{
+ NS_DEBUG ("CsmaNetDevice::AddQueue (" << q << ")");
+
+ m_queue = q;
+}
+
+void
+CsmaNetDevice::Receive (const Packet& packet)
+{
+ EthernetHeader header (false);
+ EthernetTrailer trailer;
+ Eui48Address broadcast;
+ Eui48Address destination;
+ Packet p = packet;
+
+ NS_DEBUG ("CsmaNetDevice::Receive UID is (" << p.GetUid() << ")");
+
+ // Only receive if send side of net device is enabled
+ if (!IsReceiveEnabled())
+ {
+ m_dropTrace (p);
+ return;
+ }
+
+ if (m_encapMode == RAW)
+ {
+ ForwardUp (packet, 0, GetBroadcast ());
+ m_dropTrace (p);
+ return;
+ }
+ p.RemoveTrailer(trailer);
+ trailer.CheckFcs(p);
+ p.RemoveHeader(header);
+
+ broadcast = Eui48Address::ConvertFrom (GetBroadcast ());
+ destination = Eui48Address::ConvertFrom (GetAddress ());
+ if ((header.GetDestination() != broadcast) &&
+ (header.GetDestination() != destination))
+ {
+ // not for us.
+ m_dropTrace (p);
+ return;
+ }
+
+ m_rxTrace (p);
+//
+// protocol must be initialized to avoid a compiler warning in the RAW
+// case that breaks the optimized build.
+//
+ uint16_t protocol = 0;
+
+ switch (m_encapMode)
+ {
+ case ETHERNET_V1:
+ case IP_ARP:
+ protocol = header.GetLengthType();
+ break;
+ case LLC: {
+ LlcSnapHeader llc;
+ p.RemoveHeader (llc);
+ protocol = llc.GetType ();
+ } break;
+ case RAW:
+ NS_ASSERT (false);
+ break;
+ }
+
+ ForwardUp (p, protocol, header.GetSource ());
+ return;
+}
+
+Ptr<Queue>
+CsmaNetDevice::GetQueue(void) const
+{
+ return m_queue;
+}
+
+Ptr<Channel>
+CsmaNetDevice::DoGetChannel(void) const
+{
+ return m_channel;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,432 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+ */
+
+#ifndef CSMA_NET_DEVICE_H
+#define CSMA_NET_DEVICE_H
+
+#include <string.h>
+#include "ns3/node.h"
+#include "ns3/backoff.h"
+#include "ns3/address.h"
+#include "ns3/net-device.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/callback-trace-source.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/eui48-address.h"
+
+namespace ns3 {
+
+class Queue;
+class CsmaChannel;
+
+class CsmaTraceType : public TraceContextElement
+{
+public:
+ enum Type {
+ RX,
+ DROP
+ };
+ CsmaTraceType (enum Type type);
+ CsmaTraceType ();
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+private:
+ enum Type m_type;
+};
+
+/**
+ * \class CsmaNetDevice
+ * \brief A Device for a Csma Network Link.
+ *
+ * The Csma net device class is analogous to layer 1 and 2 of the
+ * TCP stack. The NetDevice takes a raw packet of bytes and creates a
+ * protocol specific packet from them. The Csma net device class
+ * takes this packet and adds and processes the headers/trailers that
+ * are associated with EthernetV1, EthernetV2, RAW or LLC
+ * protocols. The EthernetV1 packet type adds and removes Ethernet
+ * destination and source addresses. The LLC packet type adds and
+ * removes LLC snap headers. The raw packet type does not add or
+ * remove any headers. Each Csma net device will receive all
+ * packets written to the Csma link. The ProcessHeader function can
+ * be used to filter out the packets such that higher level layers
+ * only receive packets that are addressed to their associated net
+ * devices
+ *
+ */
+class CsmaNetDevice : public NetDevice {
+public:
+
+ /**
+ * Enumeration of the types of packets supported in the class.
+ *
+ */
+enum CsmaEncapsulationMode {
+ ETHERNET_V1, /**< Version one ethernet packet, length field */
+ IP_ARP, /**< Ethernet packet encapsulates IP/ARP packet */
+ RAW, /**< Packet that contains no headers */
+ LLC, /**< LLC packet encapsulation */
+};
+
+ CsmaNetDevice (Ptr<Node> node);
+ /**
+ * Construct a CsmaNetDevice
+ *
+ * This is the constructor for the CsmaNetDevice. It takes as a
+ * parameter the Node to which this device is connected. Ownership of the
+ * Node pointer is not implied and the node must not be deleted.
+ *
+ * \param node the Node to which this device is connected.
+ * \param addr The source MAC address of the net device.
+ * \param pktType the type of encapsulation
+ */
+ CsmaNetDevice (Ptr<Node> node, Eui48Address addr, CsmaEncapsulationMode pktType);
+
+ /**
+ * Construct a CsmaNetDevice
+ *
+ * This is the constructor for the CsmaNetDevice. It takes as a
+ * parameter the Node to which this device is connected. Ownership of the
+ * Node pointer is not implied and the node must not be deleted.
+ *
+ * \param node the Node to which this device is connected.
+ * \param addr The source MAC address of the net device.
+ * \param pktType the type of encapsulation
+ * \param sendEnable whether this device is able to send
+ * \param receiveEnable whether this device is able to receive
+ */
+ CsmaNetDevice (Ptr<Node> node, Eui48Address addr,
+ CsmaEncapsulationMode pktType,
+ bool sendEnable, bool receiveEnable);
+ /**
+ * Destroy a CsmaNetDevice
+ *
+ * This is the destructor for the CsmaNetDevice.
+ */
+ virtual ~CsmaNetDevice();
+ /**
+ * Set the Data Rate used for transmission of packets. The data rate is
+ * set in the Attach () method from the corresponding field in the channel
+ * to which the device is attached. It can be overridden using this method.
+ *
+ * @see Attach ()
+ * \param bps the data rate at which this object operates
+ */
+ void SetDataRate (DataRate bps);
+ /**
+ * Set the inteframe gap used to separate packets. The interframe gap
+ * defines the minimum space required between packets sent by this device.
+ * It is usually set in the Attach () method based on the speed of light
+ * delay of the channel to which the device is attached. It can be
+ * overridden using this method if desired.
+ *
+ * @see Attach ()
+ * \param t the interframe gap time
+ */
+ void SetInterframeGap (Time t);
+ /**
+ * Set the backoff parameters used to determine the wait to retry
+ * transmitting a packet when the channel is busy.
+ *
+ * @see Attach ()
+ * \param slotTime Length of a packet slot (or average packet time)
+ * \param minSlots Minimum number of slots to wait
+ * \param maxSlots Maximum number of slots to wait
+ * \param maxRetries Maximum number of retries before packet is discard
+ * \param ceiling Cap on the exponential function when calculating max slots
+ */
+ void SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+ uint32_t maxRetries, uint32_t ceiling);
+ /**
+ * Attach the device to a channel.
+ *
+ * The function Attach is used to add a CsmaNetDevice to a
+ * CsmaChannel.
+ *
+ * @see SetDataRate ()
+ * @see SetInterframeGap ()
+ * \param ch a pointer to the channel to which this object is being attached.
+ */
+ bool Attach (Ptr<CsmaChannel> ch);
+ /**
+ * Attach a queue to the CsmaNetDevice.
+ *
+ * The CsmaNetDevice "owns" a queue. This queue is created by the
+ * CsmaTopology object and implements a queueing method such as
+ * DropTail or RED. The CsmaNetDevice assumes ownership of this
+ * queue and must delete it when the device is destroyed.
+ *
+ * @see CsmaTopology::AddCsmaLink ()
+ * @see Queue
+ * @see DropTailQueue
+ * \param queue a pointer to the queue for which object is assuming
+ * ownership.
+ */
+ void AddQueue (Ptr<Queue> queue);
+ /**
+ * Receive a packet from a connected CsmaChannel.
+ *
+ * The CsmaNetDevice receives packets from its connected channel
+ * and forwards them up the protocol stack. This is the public method
+ * used by the channel to indicate that the last bit of a packet has
+ * arrived at the device.
+ *
+ * @see CsmaChannel
+ * \param p a reference to the received packet
+ */
+ void Receive (const Packet& p);
+
+ bool IsSendEnabled (void);
+ bool IsReceiveEnabled (void);
+
+ void SetSendEnable (bool);
+ void SetReceiveEnable (bool);
+
+protected:
+ virtual bool DoNeedsArp (void) const;
+ virtual void DoDispose (void);
+ /**
+ * Get a copy of the attached Queue.
+ *
+ * This method is provided for any derived class that may need to get
+ * direct access to the underlying queue.
+ *
+ * \return a pointer to the queue.
+ */
+ Ptr<Queue> GetQueue (void) const;
+ /**
+ * Get a copy of the attached Channel
+ *
+ * This method is provided for any derived class that may need to get
+ * direct access to the connected channel
+ *
+ * \return a pointer to the channel
+ */
+ virtual Ptr<Channel> DoGetChannel (void) const;
+ /**
+ * Adds the necessary headers and trailers to a packet of data in order to
+ * respect the packet type
+ *
+ * \param p Packet to which header should be added
+ * \param dest MAC destination address to which packet should be sent
+ * \param protocolNumber In some protocols, identifies the type of
+ * payload contained in this packet.
+ */
+ void AddHeader (Packet& p, Eui48Address dest,
+ uint16_t protocolNumber);
+ /**
+ * Removes, from a packet of data, all headers and trailers that
+ * relate to the packet type
+ *
+ * \param p Packet whose headers need to be processed
+ * \param param An integer parameter that can be set by the function
+ * to return information gathered in the header
+ * \return Returns true if the packet should be forwarded up the
+ * protocol stack.
+ */
+ bool ProcessHeader (Packet& p, uint16_t & param);
+
+private:
+ // disable copy constructor and operator =
+ CsmaNetDevice &operator = (const CsmaNetDevice &o);
+ CsmaNetDevice (const CsmaNetDevice &o);
+ /**
+ * Initializes variablea when construction object.
+ */
+ void Init (bool sendEnable, bool receiveEnable);
+ /**
+ * Send a Packet on the Csma network
+ *
+ * This method does not use a destination address since all packets
+ * are broadcast to all NetDevices attached to the channel. Packet
+ * should contain all needed headers at this time.
+ *
+ * If the device is ready to transmit, the next packet is read off
+ * of the queue and stored locally until it has been transmitted.
+ *
+ * \param p a reference to the packet to send
+ * \param dest destination address
+ * \param protocolNumber -- this parameter is not used here
+ * \return true if success, false on failure
+ */
+ virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber);
+
+ /**
+ * Start Sending a Packet Down the Wire.
+ *
+ * The TransmitStart method is the method that is used internally in
+ * the CsmaNetDevice to begin the process of sending a packet
+ * out on the channel. The corresponding method is called on the
+ * channel to let it know that the physical device this class
+ * represents has virually started sending signals, this causes the
+ * channel to become busy. An event is scheduled for the time at
+ * which the bits have been completely transmitted. If the channel
+ * is busy, the method reschedules itself for a later time (within
+ * the backoff period)
+ *
+ * @see CsmaChannel::TransmitStart ()
+ * @see TransmitCompleteEvent ()
+ */
+ void TransmitStart ();
+ /**
+ * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
+ *
+ * The TransmitCompleteEvent method is used internally to finish the process
+ * of sending a packet out on the channel. During execution of this method
+ * the TransmitEnd method is called on the channel to let it know that the
+ * physical device this class represents has virually finished sending
+ * signals. The channel uses this event to begin its speed of light delay
+ * timer after which it notifies the Net Device at the other end of the
+ * link that the bits have arrived. During this method, the net device
+ * also schedules the TransmitReadyEvent at which time the transmitter
+ * becomes ready to send the next packet.
+ *
+ * @see CsmaChannel::TransmitEnd ()
+ * @see TransmitReadyEvent ()
+ */
+ void TransmitCompleteEvent (void);
+ /**
+ * Cause the Transmitter to Become Ready to Send Another Packet.
+ *
+ * The TransmitReadyEvent method is used internally to re-enable the
+ * transmit machine of the net device. It is scheduled after a suitable
+ * interframe gap after the completion of the previous transmission.
+ * The queue is checked at this time, and if there is a packet waiting on
+ * the queue, the transmission process is begun.
+ *
+ * If a packet is in the queue, it is extracted for the queue as the
+ * next packet to be transmitted by the net device.
+ *
+ * @see TransmitStart ()
+ */
+ void TransmitReadyEvent (void);
+ /**
+ * Create a Trace Resolver for events in the net device.
+ * (NOT TESTED)
+ * @see class TraceResolver
+ */
+ virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
+
+ /**
+ * Aborts the transmission of the current packet
+ *
+ * If the net device has tried to transmit a packet for more times
+ * than the maximum allowed number of retries (channel always busy)
+ * then the packet is dropped.
+ *
+ */
+ void TransmitAbort (void);
+
+ /**
+ * Device ID returned by the attached functions. It is used by the
+ * mp-channel to identify each net device to make sure that only
+ * active net devices are writing to the channel
+ */
+ uint32_t m_deviceId;
+
+ /**
+ * Enable net device to send packets. True by default
+ */
+ bool m_sendEnable;
+ /**
+ * Enable net device to receive packets. True by default
+ */
+ bool m_receiveEnable;
+ /**
+ * Enumeration of the states of the transmit machine of the net device.
+ */
+ enum TxMachineState
+ {
+ READY, /**< The transmitter is ready to begin transmission of a packet */
+ BUSY, /**< The transmitter is busy transmitting a packet */
+ GAP, /**< The transmitter is in the interframe gap time */
+ BACKOFF /**< The transmitter is waiting for the channel to be free */
+ };
+ /**
+ * The state of the Net Device transmit state machine.
+ * @see TxMachineState
+ */
+ TxMachineState m_txMachineState;
+
+ /**
+ * The type of packet that should be created by the AddHeader
+ * function and that should be processed by the ProcessHeader
+ * function.
+ */
+ CsmaEncapsulationMode m_encapMode;
+ /**
+ * The data rate that the Net Device uses to simulate packet transmission
+ * timing.
+ * @see class DataRate
+ */
+ DataRate m_bps;
+ /**
+ * The interframe gap that the Net Device uses to throttle packet
+ * transmission
+ * @see class Time
+ */
+ Time m_tInterframeGap;
+ /**
+ * Holds the backoff parameters and is used to calculate the next
+ * backoff time to use when the channel is busy and the net device
+ * is ready to transmit
+ */
+ Backoff m_backoff;
+ /**
+ * Next packet that will be transmitted (if transmitter is not
+ * currently transmitting) or packet that is currently being
+ * transmitted.
+ */
+ Packet m_currentPkt;
+ /**
+ * The CsmaChannel to which this CsmaNetDevice has been
+ * attached.
+ * @see class CsmaChannel
+ */
+ Ptr<CsmaChannel> m_channel;
+ /**
+ * The Queue which this CsmaNetDevice uses as a packet source.
+ * Management of this Queue has been delegated to the CsmaNetDevice
+ * and it has the responsibility for deletion.
+ * @see class Queue
+ * @see class DropTailQueue
+ */
+ Ptr<Queue> m_queue;
+ /**
+ * NOT TESTED
+ * The trace source for the packet reception events that the device can
+ * fire.
+ *
+ * @see class CallBackTraceSource
+ * @see class TraceResolver
+ */
+ CallbackTraceSource<const Packet &> m_rxTrace;
+ CallbackTraceSource<const Packet &> m_dropTrace;
+
+};
+
+}; // namespace ns3
+
+#endif // CSMA_NET_DEVICE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+//
+// Topology helper for Csma channels in ns3.
+
+#include "ns3/assert.h"
+#include "ns3/debug.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-topology.h"
+#include "ns3/socket-factory.h"
+
+namespace ns3 {
+
+Ptr<CsmaChannel>
+CsmaTopology::CreateCsmaChannel(
+ const DataRate& bps,
+ const Time& delay)
+{
+ Ptr<CsmaChannel> channel = Create<CsmaChannel> (bps, delay);
+
+ return channel;
+}
+
+#if 0
+Ptr<CsmaNetDevice>
+CsmaTopology::AddCsmaEthernetNode(
+ Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ MacAddress addr)
+{
+ Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+ ns3::CsmaNetDevice::ETHERNET_V1);
+
+ Ptr<Queue> q = Queue::CreateDefault ();
+ nd1->AddQueue(q);
+ nd1->Attach (ch);
+
+ return nd1;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ Ptr<CsmaNetDevice> ndDest)
+{
+ Ptr<PacketSocket> socket = Create<PacketSocket> ();
+ socket->Bind(ndSrc);
+ socket->Connect(ndDest->GetAddress());
+ app->Connect(socket);
+
+ return socket;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ MacAddress macAddr)
+{
+ Ptr<PacketSocket> socket = Create<PacketSocket> ();
+ socket->Bind(ndSrc);
+ socket->Connect(macAddr);
+ app->Connect(socket);
+
+ return socket;
+}
+
+Ptr<Socket>
+CsmaTopology::CreatePacketSocket(Ptr<Node> n1, std::string iid_name)
+{
+ InterfaceId iid = InterfaceId::LookupByName (iid_name);
+
+ Ptr<SocketFactory> socketFactory =
+ n1->QueryInterface<SocketFactory> (iid);
+
+ Ptr<Socket> socket = socketFactory->CreateSocket ();
+
+ return socket;
+}
+#endif
+
+} // namespace ns3
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,123 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+// Topology helper for multipoint channels in ns3.
+//
+#ifndef CSMA_TOPOLOGY_H
+#define CSMA_TOPOLOGY_H
+
+#include "ns3/ptr.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/node.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaChannel;
+class Node;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Csma Topologies
+ *
+ * Csma topologies are created based on the
+ * ns3::CsmaNetDevice subclasses and ns3::CsmaChannel
+ * objects. This class uses the EthernetNetDevice and
+ * PacketSocket classes in order to create logical connections between
+ * net devices. The PacketSocket class generates the data and the
+ * EthernetNetDevice class creates ethernet packets from the
+ * data, filling in source and destination addresses. The
+ * EthernetNetDevice class filters received data packets
+ * according to its destination Mac addresses.
+ */
+class CsmaTopology {
+public:
+ /**
+ * \param dataRate Maximum transmission link rate
+ * \param delay propagation delay between any two nodes
+ * \return Pointer to the created CsmaChannel
+ *
+ * Create a CsmaChannel. All nodes connected to a multipoint
+ * channels will receive all packets written to that channel
+ */
+ static Ptr<CsmaChannel> CreateCsmaChannel(
+ const DataRate& dataRate, const Time& delay);
+
+#if 0
+ /**
+ * \param n1 Node to be attached to the multipoint channel
+ * \param ch CsmaChannel to which node n1 should be attached
+ * \param addr MacAddress that should be assigned to the
+ * EthernetNetDevice that will be added to the node.
+ *
+ * Add a multipoint node to a multipoint channel
+ */
+ static Ptr<CsmaNetDevice> AddCsmaEthernetNode(Ptr<Node> n1,
+ Ptr<CsmaChannel> ch,
+ MacAddress addr);
+
+ /**
+ * \param app Application that will be sending data to the agent
+ * \param ndSrc Net Device that will be sending the packets onto the
+ * network
+ * \param ndDest Net Device to which ndSrc will be sending the packets
+ * \return A pointer to the PacketSocket
+ *
+ * Creates an PacketSocket and configure it to send packets between
+ * two net devices
+ */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ Ptr<CsmaNetDevice> ndDest);
+
+ /**
+ * \param app Application that will be sending data to the agent
+ * \param ndSrc Net Device that will be sending the packets onto the
+ * network
+ * \param macAddr Mac destination address for the packets send by
+ * the ndSrc net device \return a Pointer to the created
+ * PacketSocket
+ *
+ * Creates an PacketSocket and configure it to send packets from a
+ * net device to a destination MacAddress
+ */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+ Ptr<CsmaNetDevice> ndSrc,
+ MacAddress macAddr);
+
+ /**
+ * \param n1 Node from which socketfactory should be tested.
+ * \param iid_name Interface identifier ("Packet", in this case)
+ *
+ * This is a test function to make sure that a socket can be created
+ * by using the socketfactory interface provided in the
+ * netdevicenode.
+ */
+static Ptr<Socket> CreatePacketSocket(Ptr<Node> n1,
+ std::string iid_name);
+#endif
+
+};
+} // namespace ns3
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,19 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ obj = bld.create_ns3_module('csma', ['node'])
+ obj.source = [
+ 'backoff.cc',
+ 'csma-net-device.cc',
+ 'csma-channel.cc',
+ 'csma-topology.cc',
+ 'csma-ipv4-topology.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'backoff.h',
+ 'csma-net-device.h',
+ 'csma-channel.h',
+ 'csma-topology.h',
+ 'csma-ipv4-topology.h',
+ ]
--- a/src/devices/point-to-point/point-to-point-net-device.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.cc Wed Sep 05 18:35:39 2007 +0100
@@ -26,9 +26,10 @@
#include "ns3/queue.h"
#include "ns3/simulator.h"
#include "ns3/composite-trace-resolver.h"
+#include "ns3/eui48-address.h"
+#include "ns3/llc-snap-header.h"
#include "point-to-point-net-device.h"
#include "point-to-point-channel.h"
-#include "ns3/llc-snap-header.h"
NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice");
@@ -39,10 +40,25 @@
"The default data rate for point to point links",
DataRate ("10Mb/s"));
- PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
- const DataRate& rate)
+PointToPointTraceType::PointToPointTraceType ()
+{}
+void
+PointToPointTraceType::Print (std::ostream &os) const
+{
+ os << "dev-rx";
+}
+uint16_t
+PointToPointTraceType::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<PointToPointTraceType> ("PointToPointTraceType");
+ return uid;
+}
+
+
+PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
+ const DataRate& rate)
:
- NetDevice(node, MacAddress (6)),
+ NetDevice(node, Eui48Address::Allocate ()),
m_txMachineState (READY),
m_bps (rate),
m_tInterframeGap (Seconds(0)),
@@ -55,7 +71,7 @@
// BUGBUG FIXME
//
// You _must_ support broadcast to get any sort of packet from the ARP layer.
- EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff"));
+ EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
EnableMulticast();
EnablePointToPoint();
}
@@ -66,15 +82,16 @@
m_queue = 0;
}
-void PointToPointNetDevice::AddHeader(Packet& p, const MacAddress& dest,
- uint16_t protocolNumber)
+void
+PointToPointNetDevice::AddHeader(Packet& p, uint16_t protocolNumber)
{
LlcSnapHeader llc;
llc.SetType (protocolNumber);
p.AddHeader (llc);
}
-bool PointToPointNetDevice::ProcessHeader(Packet& p, uint16_t& param)
+bool
+PointToPointNetDevice::ProcessHeader(Packet& p, uint16_t& param)
{
LlcSnapHeader llc;
p.RemoveHeader (llc);
@@ -100,9 +117,10 @@
m_tInterframeGap = t;
}
-bool PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest,
+bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest,
uint16_t protocolNumber)
{
+ Packet p = packet;
NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")");
NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")");
@@ -110,7 +128,7 @@
// "go down" during the simulation? Shouldn't we just wait for it
// to come back up?
NS_ASSERT (IsLinkUp ());
- AddHeader(p, dest, protocolNumber);
+ AddHeader(p, protocolNumber);
//
// This class simulates a point to point device. In the case of a serial
@@ -119,14 +137,14 @@
//
// If there's a transmission in progress, we enque the packet for later
// trnsmission; otherwise we send it now.
- if (m_txMachineState == READY)
- {
- return TransmitStart (p);
- }
- else
- {
- return m_queue->Enqueue(p);
- }
+ if (m_txMachineState == READY)
+ {
+ return TransmitStart (p);
+ }
+ else
+ {
+ return m_queue->Enqueue(p);
+ }
}
bool
@@ -176,11 +194,10 @@
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
resolver->Add ("queue",
- MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)),
- PointToPointNetDevice::QUEUE);
+ MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)));
resolver->Add ("rx",
m_rxTrace,
- PointToPointNetDevice::RX);
+ PointToPointTraceType ());
return resolver;
}
@@ -218,12 +235,12 @@
void PointToPointNetDevice::Receive (Packet& p)
{
NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")");
- uint16_t param = 0;
+ uint16_t protocol = 0;
Packet packet = p;
- ProcessHeader(packet, param);
m_rxTrace (packet);
- ForwardUp (packet, param);
+ ProcessHeader(packet, protocol);
+ ForwardUp (packet, protocol, GetBroadcast ());
}
Ptr<Queue> PointToPointNetDevice::GetQueue(void) const
--- a/src/devices/point-to-point/point-to-point-net-device.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.h Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,7 @@
#define POINT_TO_POINT_NET_DEVICE_H
#include <string.h>
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
#include "ns3/node.h"
#include "ns3/net-device.h"
#include "ns3/callback.h"
@@ -38,6 +38,14 @@
class Queue;
class PointToPointChannel;
+class PointToPointTraceType : public TraceContextElement
+{
+public:
+ PointToPointTraceType ();
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+};
+
/**
* \class PointToPointNetDevice
* \brief A Device for a Point to Point Network Link.
@@ -64,14 +72,6 @@
class PointToPointNetDevice : public NetDevice {
public:
/**
- * Enumeration of the types of traces supported in the class.
- *
- */
- enum TraceType {
- QUEUE, /**< Trace queue events on the attached queue */
- RX, /**< Trace packet reception events (from the channel) */
- };
- /**
* Construct a PointToPointNetDevice
*
* This is the constructor for the PointToPointNetDevice. It takes as a
@@ -175,7 +175,6 @@
virtual Ptr<Channel> DoGetChannel(void) const;
/**
* Set a new default data rate
- * @param Data rate to set for new default
*/
static void SetDefaultRate(const DataRate&);
@@ -191,7 +190,7 @@
* Adds the necessary headers and trailers to a packet of data in order to
* respect the protocol implemented by the agent.
*/
- void AddHeader(Packet& p, const MacAddress& dest, uint16_t protocolNumber);
+ void AddHeader(Packet& p, uint16_t protocolNumber);
/**
* Removes, from a packet of data, all headers and trailers that
* relate to the protocol implemented by the agent
@@ -208,11 +207,11 @@
*
* @see NetDevice
* @param p a reference to the packet to send
- * @param dest a reference to the MacAddress of the destination device
+ * @param dest a reference to the Address of the destination device
* @param protocolNumber Protocol Number used to find protocol touse
* @returns true if success, false on failure
*/
- virtual bool SendTo (Packet& p, const MacAddress& dest,
+ virtual bool SendTo (const Packet& p, const Address& dest,
uint16_t protocolNumber);
/**
* Start Sending a Packet Down the Wire.
@@ -291,7 +290,7 @@
* @see class CallBackTraceSource
* @see class TraceResolver
*/
- CallbackTraceSource<Packet &> m_rxTrace;
+ CallbackTraceSource<const Packet &> m_rxTrace;
/**
* Default data rate. Used for all newly created p2p net devices
*/
--- a/src/devices/point-to-point/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/devices/point-to-point/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -2,10 +2,7 @@
def build(bld):
- module = bld.create_obj('cpp', 'shlib')
- module.name = 'ns3-point-to-point'
- module.target = module.name
- module.uselib_local = ['ns3-node']
+ module = bld.create_ns3_module('point-to-point', ['node'])
module.source = [
'point-to-point-net-device.cc',
'point-to-point-channel.cc',
--- a/src/internet-node/arp-cache.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-cache.cc Wed Sep 05 18:35:39 2007 +0100
@@ -148,7 +148,7 @@
UpdateSeen ();
}
Packet
-ArpCache::Entry::MarkAlive (MacAddress macAddress)
+ArpCache::Entry::MarkAlive (Address macAddress)
{
NS_ASSERT (m_state == WAIT_REPLY);
//NS_ASSERT (m_waiting != 0);
@@ -182,7 +182,7 @@
UpdateSeen ();
}
-MacAddress
+Address
ArpCache::Entry::GetMacAddress (void)
{
NS_ASSERT (m_state == ALIVE);
--- a/src/internet-node/arp-cache.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-cache.h Wed Sep 05 18:35:39 2007 +0100
@@ -26,7 +26,7 @@
#include "ns3/nstime.h"
#include "ns3/net-device.h"
#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
#include "ns3/ptr.h"
#include "sgi-hashmap.h"
@@ -101,7 +101,7 @@
* \param macAddress
* \return
*/
- Packet MarkAlive (MacAddress macAddress);
+ Packet MarkAlive (Address macAddress);
/**
* \param waiting
*/
@@ -127,7 +127,7 @@
/**
* \return The MacAddress of this entry
*/
- MacAddress GetMacAddress (void);
+ Address GetMacAddress (void);
/**
* \return True if this entry has timedout; false otherwise.
*/
@@ -143,7 +143,7 @@
ArpCache *m_arp;
ArpCacheEntryState_e m_state;
Time m_lastSeen;
- MacAddress m_macAddress;
+ Address m_macAddress;
Packet m_waiting;
};
--- a/src/internet-node/arp-header.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-header.cc Wed Sep 05 18:35:39 2007 +0100
@@ -25,13 +25,19 @@
namespace ns3 {
-ArpHeader::~ArpHeader ()
-{}
+NS_HEADER_ENSURE_REGISTERED (ArpHeader);
+
+uint32_t
+ArpHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<ArpHeader> ("ArpHeader.ns3");
+ return uid;
+}
void
-ArpHeader::SetRequest (MacAddress sourceHardwareAddress,
+ArpHeader::SetRequest (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress)
{
m_type = ARP_TYPE_REQUEST;
@@ -41,9 +47,9 @@
m_ipv4Dest = destinationProtocolAddress;
}
void
-ArpHeader::SetReply (MacAddress sourceHardwareAddress,
+ArpHeader::SetReply (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress)
{
m_type = ARP_TYPE_REPLY;
@@ -62,12 +68,12 @@
{
return (m_type == ARP_TYPE_REPLY)?true:false;
}
-MacAddress
+Address
ArpHeader::GetSourceHardwareAddress (void)
{
return m_macSource;
}
-MacAddress
+Address
ArpHeader::GetDestinationHardwareAddress (void)
{
return m_macDest;
@@ -84,13 +90,13 @@
}
std::string
-ArpHeader::DoGetName (void) const
+ArpHeader::GetName (void) const
{
return "ARP";
}
void
-ArpHeader::PrintTo (std::ostream &os) const
+ArpHeader::Print (std::ostream &os) const
{
if (IsRequest ())
{
@@ -123,7 +129,7 @@
}
void
-ArpHeader::SerializeTo (Buffer::Iterator start) const
+ArpHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
NS_ASSERT (m_macSource.GetLength () == m_macDest.GetLength ());
@@ -141,7 +147,7 @@
WriteTo (i, m_ipv4Dest);
}
uint32_t
-ArpHeader::DeserializeFrom (Buffer::Iterator start)
+ArpHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
i.Next (2+2);
--- a/src/internet-node/arp-header.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-header.h Wed Sep 05 18:35:39 2007 +0100
@@ -23,59 +23,47 @@
#define ARP_HEADER_H
#include "ns3/header.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
#include "ns3/ipv4-address.h"
+#include <string>
namespace ns3 {
/**
* \brief The packet header for an ARP packet
*/
-class ArpHeader : public Header {
- public:
- virtual ~ArpHeader ();
+class ArpHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
- void SetRequest (MacAddress sourceHardwareAddress,
+ void SetRequest (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress);
- void SetReply (MacAddress sourceHardwareAddress,
+ void SetReply (Address sourceHardwareAddress,
Ipv4Address sourceProtocolAddress,
- MacAddress destinationHardwareAddress,
+ Address destinationHardwareAddress,
Ipv4Address destinationProtocolAddress);
bool IsRequest (void) const;
bool IsReply (void) const;
- MacAddress GetSourceHardwareAddress (void);
- MacAddress GetDestinationHardwareAddress (void);
+ Address GetSourceHardwareAddress (void);
+ Address GetDestinationHardwareAddress (void);
Ipv4Address GetSourceIpv4Address (void);
Ipv4Address GetDestinationIpv4Address (void);
-private:
- virtual std::string DoGetName (void) const;
- /**
- * \param os
- */
- virtual void PrintTo (std::ostream &os) const;
- /**
- * \return
- */
- virtual uint32_t GetSerializedSize (void) const;
- /**
- * \param start
- */
- virtual void SerializeTo (Buffer::Iterator start) const;
- /**
- * \param start
- * \return
- */
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+ std::string GetName (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);
enum ArpType_e {
ARP_TYPE_REQUEST = 1,
ARP_TYPE_REPLY = 2
};
uint16_t m_type;
- MacAddress m_macSource;
- MacAddress m_macDest;
+ Address m_macSource;
+ Address m_macDest;
Ipv4Address m_ipv4Source;
Ipv4Address m_ipv4Dest;
};
--- a/src/internet-node/arp-ipv4-interface.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.cc Wed Sep 05 18:35:39 2007 +0100
@@ -25,10 +25,11 @@
#include "ns3/composite-trace-resolver.h"
#include "ns3/node.h"
#include "ns3/net-device.h"
+#include "ns3/address.h"
#include "arp-ipv4-interface.h"
-#include "arp-private.h"
#include "ipv4-l3-protocol.h"
+#include "arp-l3-protocol.h"
namespace ns3 {
@@ -46,8 +47,7 @@
if (GetDevice () != 0)
{
resolver->Add ("netdevice",
- MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())),
- ArpIpv4Interface::NETDEVICE);
+ MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())));
}
return resolver;
@@ -59,18 +59,17 @@
NS_ASSERT (GetDevice () != 0);
if (GetDevice ()->NeedsArp ())
{
- Ptr<ArpPrivate> arp = m_node->QueryInterface<ArpPrivate> (ArpPrivate::iid);
- MacAddress hardwareDestination;
+ Ptr<ArpL3Protocol> arp = m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
+ Address hardwareDestination;
bool found;
if (dest.IsBroadcast ())
{
- hardwareDestination = GetDevice ()->GetBroadcast ();
- found = true;
+ hardwareDestination = GetDevice ()->GetBroadcast ();
+ found = true;
}
else
{
- Ptr<ArpPrivate> arp = m_node->QueryInterface<ArpPrivate> (ArpPrivate::iid);
found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
}
--- a/src/internet-node/arp-ipv4-interface.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.h Wed Sep 05 18:35:39 2007 +0100
@@ -39,10 +39,6 @@
class ArpIpv4Interface : public Ipv4Interface
{
public:
- enum TraceType {
- NETDEVICE,
- ARP,
- };
ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device);
virtual ~ArpIpv4Interface ();
--- a/src/internet-node/arp-l3-protocol.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-l3-protocol.cc Wed Sep 05 18:35:39 2007 +0100
@@ -24,22 +24,24 @@
#include "ns3/node.h"
#include "ns3/net-device.h"
+#include "ipv4-l3-protocol.h"
#include "arp-l3-protocol.h"
#include "arp-header.h"
#include "arp-cache.h"
#include "ipv4-interface.h"
-#include "ipv4-private.h"
NS_DEBUG_COMPONENT_DEFINE ("ArpL3Protocol");
namespace ns3 {
+const InterfaceId ArpL3Protocol::iid = MakeInterfaceId ("ArpL3Protocol", Object::iid);
const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
ArpL3Protocol::ArpL3Protocol (Ptr<Node> node)
- : L3Protocol (PROT_NUMBER, 0/* XXX: correct version number ? */ ),
- m_node (node)
-{}
+ : m_node (node)
+{
+ SetInterfaceId (ArpL3Protocol::iid);
+}
ArpL3Protocol::~ArpL3Protocol ()
{}
@@ -53,7 +55,7 @@
}
m_cacheList.clear ();
m_node = 0;
- L3Protocol::DoDispose ();
+ Object::DoDispose ();
}
TraceResolver *
@@ -72,7 +74,7 @@
return *i;
}
}
- Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
+ Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
Ipv4Interface *interface = ipv4->FindInterfaceForDevice (device);
ArpCache * cache = new ArpCache (device, interface);
NS_ASSERT (device->IsBroadcast ());
@@ -82,10 +84,11 @@
}
void
-ArpL3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+ArpL3Protocol::Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
{
ArpCache *cache = FindCache (device);
ArpHeader arp;
+ Packet packet = p;
packet.RemoveHeader (arp);
NS_DEBUG ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") <<
@@ -104,7 +107,7 @@
}
else if (arp.IsReply () &&
arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress ()) &&
- arp.GetDestinationHardwareAddress ().IsEqual (device->GetAddress ()))
+ arp.GetDestinationHardwareAddress () == device->GetAddress ())
{
Ipv4Address from = arp.GetSourceIpv4Address ();
ArpCache::Entry *entry = cache->Lookup (from);
@@ -115,7 +118,7 @@
NS_DEBUG ("node="<<m_node->GetId ()<<", got reply from " <<
arp.GetSourceIpv4Address ()
<< " for waiting entry -- flush");
- MacAddress from_mac = arp.GetSourceHardwareAddress ();
+ Address from_mac = arp.GetSourceHardwareAddress ();
Packet waiting = entry->MarkAlive (from_mac);
cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ());
}
@@ -144,8 +147,8 @@
}
bool
ArpL3Protocol::Lookup (Packet &packet, Ipv4Address destination,
- Ptr<NetDevice> device,
- MacAddress *hardwareDestination)
+ Ptr<NetDevice> device,
+ Address *hardwareDestination)
{
ArpCache *cache = FindCache (device);
ArpCache::Entry *entry = cache->Lookup (destination);
@@ -231,7 +234,7 @@
}
void
-ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac)
+ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac)
{
ArpHeader arp;
NS_DEBUG ("ARP: sending reply from node "<<m_node->GetId ()<<
--- a/src/internet-node/arp-l3-protocol.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-l3-protocol.h Wed Sep 05 18:35:39 2007 +0100
@@ -23,9 +23,8 @@
#include <list>
#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
#include "ns3/ptr.h"
-#include "l3-protocol.h"
namespace ns3 {
@@ -38,22 +37,23 @@
/**
* \brief An implementation of the ARP protocol
*/
-class ArpL3Protocol : public L3Protocol
+class ArpL3Protocol : public Object
{
public:
+ static const InterfaceId iid;
static const uint16_t PROT_NUMBER;
/**
* \brief Constructor
* \param node The node which this ARP object is associated with
*/
ArpL3Protocol (Ptr<Node> node);
- ~ArpL3Protocol ();
+ virtual ~ArpL3Protocol ();
virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
/**
* \brief Recieve a packet
*/
- virtual void Receive(Packet& p, Ptr<NetDevice> device);
+ void Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
/**
* \brief Perform an ARP lookup
* \param p
@@ -64,14 +64,14 @@
*/
bool Lookup (Packet &p, Ipv4Address destination,
Ptr<NetDevice> device,
- MacAddress *hardwareDestination);
+ Address *hardwareDestination);
protected:
virtual void DoDispose (void);
private:
typedef std::list<ArpCache *> CacheList;
ArpCache *FindCache (Ptr<NetDevice> device);
void SendArpRequest (ArpCache const *cache, Ipv4Address to);
- void SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac);
+ void SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac);
CacheList m_cacheList;
Ptr<Node> m_node;
};
--- a/src/internet-node/arp-private.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "arp-private.h"
-#include "arp-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId ArpPrivate::iid = MakeInterfaceId ("ArpPrivate", Object::iid);
-
-ArpPrivate::ArpPrivate (Ptr<ArpL3Protocol> arp)
- : m_arp (arp)
-{
- SetInterfaceId (ArpPrivate::iid);
-}
-ArpPrivate::~ArpPrivate ()
-{
- NS_ASSERT (m_arp == 0);
-}
-
-bool
-ArpPrivate::Lookup (Packet &p, Ipv4Address destination,
- Ptr<NetDevice> device,
- MacAddress *hardwareDestination)
-{
- return m_arp->Lookup (p, destination, device, hardwareDestination);
-}
-
-void
-ArpPrivate::DoDispose (void)
-{
- m_arp = 0;
- Object::DoDispose ();
-}
-
-
-} // namespace ns3
--- a/src/internet-node/arp-private.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef ARP_PRIVATE_H
-#define ARP_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-
-namespace ns3 {
-
-class NetDevice;
-class MacAddress;
-class Packet;
-class ArpL3Protocol;
-
-class ArpPrivate : public Object
-{
-public:
- static const InterfaceId iid;
- ArpPrivate (Ptr<ArpL3Protocol> arp);
- virtual ~ArpPrivate ();
- bool Lookup (Packet &p, Ipv4Address destination,
- Ptr<NetDevice> device,
- MacAddress *hardwareDestination);
-protected:
- virtual void DoDispose (void);
-private:
- Ptr<ArpL3Protocol> m_arp;
-};
-
-} // namespace ns3
-
-#endif /* ARP_PRIVATE_H */
--- a/src/internet-node/ascii-trace.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ascii-trace.cc Wed Sep 05 18:35:39 2007 +0100
@@ -24,14 +24,8 @@
#include "ns3/trace-root.h"
#include "ns3/simulator.h"
#include "ns3/node.h"
+#include "ns3/packet.h"
#include "ns3/queue.h"
-#include "ns3/node-list.h"
-#include "ns3/llc-snap-header.h"
-
-#include "ipv4-l3-protocol.h"
-#include "arp-header.h"
-#include "udp-header.h"
-#include "ipv4-header.h"
namespace ns3 {
@@ -47,90 +41,62 @@
AsciiTrace::TraceAllQueues (void)
{
Packet::EnableMetadata ();
- TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*",
- MakeCallback (&AsciiTrace::LogDevQueue, this));
+ TraceRoot::Connect ("/nodes/*/devices/*/queue/enqueue",
+ MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this));
+ TraceRoot::Connect ("/nodes/*/devices/*/queue/dequeue",
+ MakeCallback (&AsciiTrace::LogDevQueueDequeue, this));
+ TraceRoot::Connect ("/nodes/*/devices/*/queue/drop",
+ MakeCallback (&AsciiTrace::LogDevQueueDrop, this));
}
void
AsciiTrace::TraceAllNetDeviceRx (void)
{
Packet::EnableMetadata ();
- TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx",
+ TraceRoot::Connect ("/nodes/*/devices/*/rx",
MakeCallback (&AsciiTrace::LogDevRx, this));
}
-void
-AsciiTrace::PrintType (Packet const &packet)
+void
+AsciiTrace::LogDevQueueEnqueue (TraceContext const &context,
+ Packet const &packet)
{
- Packet p = packet;
- LlcSnapHeader llc;
- p.RemoveHeader (llc);
- switch (llc.GetType ())
- {
- case 0x0800: {
- Ipv4Header ipv4;
- p.RemoveHeader (ipv4);
- if (ipv4.GetProtocol () == 17)
- {
- UdpHeader udp;
- p.RemoveHeader (udp);
- m_os << "udp size=" << p.GetSize ();
- }
- } break;
- case 0x0806: {
- ArpHeader arp;
- p.RemoveHeader (arp);
- m_os << "arp ";
- if (arp.IsRequest ())
- {
- m_os << "request";
- }
- else
- {
- m_os << "reply ";
- }
- } break;
- }
-}
+ m_os << "+ ";
+ m_os << Simulator::Now ().GetSeconds () << " ";
+ context.Print (m_os);
+ m_os << " pkt-uid=" << packet.GetUid () << " ";
+ packet.Print (m_os);
+ m_os << std::endl;
+}
void
-AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet)
+AsciiTrace::LogDevQueueDequeue (TraceContext const &context,
+ Packet const &packet)
{
- enum Queue::TraceType type;
- context.Get (type);
- switch (type)
- {
- case Queue::ENQUEUE:
- m_os << "+ ";
- break;
- case Queue::DEQUEUE:
- m_os << "- ";
- break;
- case Queue::DROP:
- m_os << "d ";
- break;
- }
+ m_os << "- ";
m_os << Simulator::Now ().GetSeconds () << " ";
- NodeList::NodeIndex nodeIndex;
- context.Get (nodeIndex);
- m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
- Ipv4L3Protocol::InterfaceIndex interfaceIndex;
- context.Get (interfaceIndex);
- m_os << "interface=" << interfaceIndex << " ";
- m_os << "pkt-uid=" << packet.GetUid () << " ";
+ context.Print (m_os);
+ m_os << " pkt-uid=" << packet.GetUid () << " ";
+ packet.Print (m_os);
+ m_os << std::endl;
+}
+
+void
+AsciiTrace::LogDevQueueDrop (TraceContext const &context,
+ Packet const &packet)
+{
+ m_os << "d ";
+ m_os << Simulator::Now ().GetSeconds () << " ";
+ context.Print (m_os);
+ m_os << " pkt-uid=" << packet.GetUid () << " ";
packet.Print (m_os);
m_os << std::endl;
}
void
-AsciiTrace::LogDevRx (TraceContext const &context, Packet &p)
+AsciiTrace::LogDevRx (TraceContext const &context, const Packet &p)
{
m_os << "r " << Simulator::Now ().GetSeconds () << " ";
- NodeList::NodeIndex nodeIndex;
- context.Get (nodeIndex);
- m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
- Ipv4L3Protocol::InterfaceIndex interfaceIndex;
- context.Get (interfaceIndex);
- m_os << "interface=" << interfaceIndex << " ";
- m_os << "pkt-uid=" << p.GetUid () << " ";
+ context.Print (m_os);
+ m_os << " pkt-uid=" << p.GetUid () << " ";
p.Print (m_os);
m_os << std::endl;
}
--- a/src/internet-node/ascii-trace.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ascii-trace.h Wed Sep 05 18:35:39 2007 +0100
@@ -37,9 +37,10 @@
void TraceAllQueues (void);
void TraceAllNetDeviceRx (void);
private:
- void PrintType (Packet const &p);
- void LogDevQueue (TraceContext const &context, const Packet &p);
- void LogDevRx (TraceContext const &context, Packet &p);
+ void LogDevQueueEnqueue (TraceContext const &context, const Packet &p);
+ void LogDevQueueDequeue (TraceContext const &context, const Packet &p);
+ void LogDevQueueDrop (TraceContext const &context, const Packet &p);
+ void LogDevRx (TraceContext const &context, const Packet &p);
std::ofstream m_os;
};
--- a/src/internet-node/internet-node.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/internet-node.cc Wed Sep 05 18:35:39 2007 +0100
@@ -23,21 +23,18 @@
#include "ns3/composite-trace-resolver.h"
#include "ns3/net-device.h"
+#include "ns3/callback.h"
-#include "l3-demux.h"
#include "ipv4-l4-demux.h"
#include "internet-node.h"
#include "udp-l4-protocol.h"
#include "ipv4-l3-protocol.h"
#include "arp-l3-protocol.h"
#include "udp-impl.h"
-#include "arp-private.h"
#include "ipv4-impl.h"
-#include "ipv4-private.h"
namespace ns3 {
-
InternetNode::InternetNode()
{
Construct ();
@@ -56,39 +53,34 @@
{
Ptr<Ipv4L3Protocol> ipv4 = Create<Ipv4L3Protocol> (this);
Ptr<ArpL3Protocol> arp = Create<ArpL3Protocol> (this);
- Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
+ // XXX remove the PeekPointer below.
+ RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, PeekPointer (ipv4)),
+ Ipv4L3Protocol::PROT_NUMBER, 0);
+ RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (arp)),
+ ArpL3Protocol::PROT_NUMBER, 0);
- Ptr<L3Demux> l3Demux = Create<L3Demux> (this);
+
Ptr<Ipv4L4Demux> ipv4L4Demux = Create<Ipv4L4Demux> (this);
-
- l3Demux->Insert (ipv4);
- l3Demux->Insert (arp);
+ Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
ipv4L4Demux->Insert (udp);
Ptr<UdpImpl> udpImpl = Create<UdpImpl> (udp);
- Ptr<ArpPrivate> arpPrivate = Create<ArpPrivate> (arp);
Ptr<Ipv4Impl> ipv4Impl = Create<Ipv4Impl> (ipv4);
- Ptr<Ipv4Private> ipv4Private = Create<Ipv4Private> (ipv4);
- Object::AddInterface (ipv4Private);
+ Object::AddInterface (ipv4);
+ Object::AddInterface (arp);
Object::AddInterface (ipv4Impl);
- Object::AddInterface (arpPrivate);
Object::AddInterface (udpImpl);
- Object::AddInterface (l3Demux);
Object::AddInterface (ipv4L4Demux);
}
-
-TraceResolver *
-InternetNode::DoCreateTraceResolver (TraceContext const &context)
+void
+InternetNode::DoFillTraceResolver (CompositeTraceResolver &resolver)
{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- Ptr<Ipv4Private> ipv4 = QueryInterface<Ipv4Private> (Ipv4Private::iid);
- resolver->Add ("ipv4",
- MakeCallback (&Ipv4Private::CreateTraceResolver, PeekPointer (ipv4)),
- InternetNode::IPV4);
-
- return resolver;
+ Node::DoFillTraceResolver (resolver);
+ Ptr<Ipv4L3Protocol> ipv4 = QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+ resolver.Add ("ipv4",
+ MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4)));
}
void
@@ -97,25 +89,4 @@
Node::DoDispose ();
}
-void
-InternetNode::DoAddDevice (Ptr<NetDevice> device)
-{
- device->SetReceiveCallback (MakeCallback (&InternetNode::ReceiveFromDevice, this));
-}
-
-bool
-InternetNode::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const
-{
- Ptr<L3Demux> demux = QueryInterface<L3Demux> (L3Demux::iid);
- Ptr<L3Protocol> target = demux->GetProtocol (protocolNumber);
- if (target != 0)
- {
- Packet packet = p;
- target->Receive(packet, device);
- return true;
- }
- return false;
-}
-
-
}//namespace ns3
--- a/src/internet-node/internet-node.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/internet-node.h Wed Sep 05 18:35:39 2007 +0100
@@ -36,9 +36,6 @@
class InternetNode : public Node
{
public:
- enum TraceType {
- IPV4,
- };
InternetNode();
InternetNode(uint32_t systemId);
virtual ~InternetNode ();
@@ -46,8 +43,7 @@
protected:
virtual void DoDispose(void);
private:
- virtual void DoAddDevice (Ptr<NetDevice> device);
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
+ virtual void DoFillTraceResolver (CompositeTraceResolver &resolver);
bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const;
void Construct (void);
};
--- a/src/internet-node/ipv4-header.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-header.cc Wed Sep 05 18:35:39 2007 +0100
@@ -28,8 +28,17 @@
namespace ns3 {
+NS_HEADER_ENSURE_REGISTERED (Ipv4Header);
+
bool Ipv4Header::m_calcChecksum = false;
+uint32_t
+Ipv4Header::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<Ipv4Header> ("Ipv4Header.ns3");
+ return uid;
+}
+
Ipv4Header::Ipv4Header ()
: m_payloadSize (0),
m_identification (0),
@@ -40,8 +49,6 @@
m_fragmentOffset (0),
m_goodChecksum (true)
{}
-Ipv4Header::~Ipv4Header ()
-{}
void
Ipv4Header::EnableChecksums (void)
@@ -180,13 +187,13 @@
}
std::string
-Ipv4Header::DoGetName (void) const
+Ipv4Header::GetName (void) const
{
return "IPV4";
}
void
-Ipv4Header::PrintTo (std::ostream &os) const
+Ipv4Header::Print (std::ostream &os) const
{
// ipv4, right ?
std::string flags;
@@ -229,7 +236,7 @@
}
void
-Ipv4Header::SerializeTo (Buffer::Iterator start) const
+Ipv4Header::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
@@ -272,7 +279,7 @@
}
}
uint32_t
-Ipv4Header::DeserializeFrom (Buffer::Iterator start)
+Ipv4Header::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
uint8_t verIhl = i.ReadU8 ();
--- a/src/internet-node/ipv4-header.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-header.h Wed Sep 05 18:35:39 2007 +0100
@@ -29,13 +29,14 @@
/**
* \brief Packet header for IPv4
*/
-class Ipv4Header : public Header {
+class Ipv4Header : public Header
+{
public:
+ static uint32_t GetUid (void);
/**
* \brief Construct a null IPv4 header
*/
Ipv4Header ();
- virtual ~Ipv4Header ();
/**
* \brief Enable checksum calculation for IP (XXX currently has no effect)
*/
@@ -139,12 +140,12 @@
*/
bool IsChecksumOk (void) const;
+ std::string GetName (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);
private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
enum FlagsE {
DONT_FRAGMENT = (1<<0),
@@ -165,7 +166,7 @@
bool m_goodChecksum;
};
-}; // namespace ns3
+} // namespace ns3
#endif /* IPV4_HEADER_H */
--- a/src/internet-node/ipv4-l3-protocol.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.cc Wed Sep 05 18:35:39 2007 +0100
@@ -41,15 +41,86 @@
namespace ns3 {
+const InterfaceId Ipv4L3Protocol::iid = MakeInterfaceId ("Ipv4L3Protocol", Object::iid);
const uint16_t Ipv4L3Protocol::PROT_NUMBER = 0x0800;
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement ()
+ : m_type (TX)
+{}
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement (enum Type type)
+ : m_type (type)
+{}
+bool
+Ipv4L3ProtocolTraceContextElement::IsTx (void) const
+{
+ return m_type == TX;
+}
+bool
+Ipv4L3ProtocolTraceContextElement::IsRx (void) const
+{
+ return m_type == RX;
+}
+bool
+Ipv4L3ProtocolTraceContextElement::IsDrop (void) const
+{
+ return m_type == DROP;
+}
+void
+Ipv4L3ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+ os << "ipv4=";
+ switch (m_type)
+ {
+ case TX:
+ os << "tx";
+ break;
+ case RX:
+ os << "rx";
+ break;
+ case DROP:
+ os << "drop";
+ break;
+ }
+}
+uint16_t
+Ipv4L3ProtocolTraceContextElement::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<Ipv4L3ProtocolTraceContextElement> ("Ipv4L3ProtocolTraceContextElement");
+ return uid;
+}
+
+
+Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex ()
+ : m_index (0)
+{}
+Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex (uint32_t index)
+ : m_index (index)
+{}
+uint32_t
+Ipv4l3ProtocolInterfaceIndex::Get (void) const
+{
+ return m_index;
+}
+void
+Ipv4l3ProtocolInterfaceIndex::Print (std::ostream &os) const
+{
+ os << "ipv4-interface=" << m_index;
+}
+uint16_t
+Ipv4l3ProtocolInterfaceIndex::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<Ipv4l3ProtocolInterfaceIndex> ("Ipv4l3ProtocolInterfaceIndex");
+ return uid;
+}
+
+
Ipv4L3Protocol::Ipv4L3Protocol(Ptr<Node> node)
- : L3Protocol (PROT_NUMBER, 4),
- m_nInterfaces (0),
+ : m_nInterfaces (0),
m_defaultTtl (64),
m_identification (0),
m_node (node)
{
+ SetInterfaceId (Ipv4L3Protocol::iid);
m_staticRouting = Create<Ipv4StaticRouting> ();
AddRoutingProtocol (m_staticRouting, 0);
SetupLoopback ();
@@ -66,9 +137,9 @@
}
m_interfaces.clear ();
m_node = 0;
- L3Protocol::DoDispose ();
m_staticRouting->Dispose ();
m_staticRouting = 0;
+ Object::DoDispose ();
}
void
@@ -86,20 +157,19 @@
Ipv4L3Protocol::CreateTraceResolver (TraceContext const &context)
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- resolver->Add ("tx", m_txTrace, Ipv4L3Protocol::TX);
- resolver->Add ("rx", m_rxTrace, Ipv4L3Protocol::RX);
- resolver->Add ("drop", m_dropTrace, Ipv4L3Protocol::DROP);
+ resolver->Add ("tx", m_txTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::TX));
+ resolver->Add ("rx", m_rxTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::RX));
+ resolver->Add ("drop", m_dropTrace, Ipv4L3ProtocolTraceContextElement (Ipv4L3ProtocolTraceContextElement::DROP));
resolver->Add ("interfaces",
- MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this),
- Ipv4L3Protocol::INTERFACES);
+ MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this));
return resolver;
}
TraceResolver *
Ipv4L3Protocol::InterfacesCreateTraceResolver (TraceContext const &context) const
{
- ArrayTraceResolver<Ipv4Interface> *resolver =
- new ArrayTraceResolver<Ipv4Interface>
+ ArrayTraceResolver<Ipv4Interface *, Ipv4l3ProtocolInterfaceIndex> *resolver =
+ new ArrayTraceResolver<Ipv4Interface *,Ipv4l3ProtocolInterfaceIndex>
(context,
MakeCallback (&Ipv4L3Protocol::GetNInterfaces, this),
MakeCallback (&Ipv4L3Protocol::GetInterface, this));
@@ -240,18 +310,19 @@
}
void
-Ipv4L3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+Ipv4L3Protocol::Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
{
uint32_t index = 0;
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
{
if ((*i)->GetDevice () == device)
{
- m_rxTrace (packet, index);
+ m_rxTrace (p, index);
break;
}
index++;
}
+ Packet packet = p;
Ipv4Header ipHeader;
packet.RemoveHeader (ipHeader);
--- a/src/internet-node/ipv4-l3-protocol.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.h Wed Sep 05 18:35:39 2007 +0100
@@ -25,12 +25,11 @@
#include <list>
#include <stdint.h>
#include "ns3/callback-trace-source.h"
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
#include "ns3/ipv4-address.h"
-#include "ipv4-header.h"
#include "ns3/ptr.h"
#include "ns3/ipv4.h"
-#include "l3-protocol.h"
+#include "ipv4-header.h"
#include "ipv4-static-routing.h"
namespace ns3 {
@@ -45,19 +44,43 @@
class TraceResolver;
class TraceContext;
-
-class Ipv4L3Protocol : public L3Protocol
+class Ipv4L3ProtocolTraceContextElement : public TraceContextElement
{
public:
- static const uint16_t PROT_NUMBER;
-
- enum TraceType {
+ enum Type {
TX,
RX,
DROP,
- INTERFACES,
};
- typedef ArrayTraceResolver<Ipv4Interface>::Index InterfaceIndex;
+ Ipv4L3ProtocolTraceContextElement ();
+ Ipv4L3ProtocolTraceContextElement (enum Type type);
+ bool IsTx (void) const;
+ bool IsRx (void) const;
+ bool IsDrop (void) const;
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+private:
+ enum Type m_type;
+};
+
+class Ipv4l3ProtocolInterfaceIndex : public TraceContextElement
+{
+public:
+ Ipv4l3ProtocolInterfaceIndex ();
+ Ipv4l3ProtocolInterfaceIndex (uint32_t index);
+ uint32_t Get (void) const;
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+private:
+ uint32_t m_index;
+};
+
+
+class Ipv4L3Protocol : public Object
+{
+public:
+ static const InterfaceId iid;
+ static const uint16_t PROT_NUMBER;
Ipv4L3Protocol(Ptr<Node> node);
virtual ~Ipv4L3Protocol ();
@@ -95,7 +118,7 @@
* - implement a per-NetDevice ARP cache
* - send back arp replies on the right device
*/
- virtual void Receive(Packet& p, Ptr<NetDevice> device);
+ void Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
/**
* \param packet packet to send
--- a/src/internet-node/ipv4-l4-demux.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l4-demux.cc Wed Sep 05 18:35:39 2007 +0100
@@ -32,6 +32,30 @@
const InterfaceId Ipv4L4Demux::iid = MakeInterfaceId ("Ipv4L4Demux", Object::iid);
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement ()
+ : m_protocolNumber (0)
+{}
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement (int protocolNumber)
+ : m_protocolNumber (protocolNumber)
+{}
+int
+Ipv4L4ProtocolTraceContextElement::Get (void) const
+{
+ return m_protocolNumber;
+}
+void
+Ipv4L4ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+ os << "ipv4-protocol=0x" << std::hex << m_protocolNumber << std::dec;
+}
+uint16_t
+Ipv4L4ProtocolTraceContextElement::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<Ipv4L4ProtocolTraceContextElement> ("Ipv4L4ProtocolTraceContextElement");
+ return uid;
+}
+
+
Ipv4L4Demux::Ipv4L4Demux (Ptr<Node> node)
: m_node (node)
{
@@ -64,7 +88,7 @@
std::string protValue;
std::ostringstream oss (protValue);
oss << (*i)->GetProtocolNumber ();
- Ipv4L4ProtocolTraceType protocolNumber = (*i)->GetProtocolNumber ();
+ Ipv4L4ProtocolTraceContextElement protocolNumber = (*i)->GetProtocolNumber ();
resolver->Add (protValue,
MakeCallback (&Ipv4L4Protocol::CreateTraceResolver, PeekPointer (protocol)),
protocolNumber);
--- a/src/internet-node/ipv4-l4-demux.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l4-demux.h Wed Sep 05 18:35:39 2007 +0100
@@ -28,6 +28,7 @@
#include <list>
#include "ns3/object.h"
#include "ns3/ptr.h"
+#include "ns3/trace-context-element.h"
namespace ns3 {
@@ -36,6 +37,18 @@
class TraceResolver;
class TraceContext;
+class Ipv4L4ProtocolTraceContextElement : public TraceContextElement
+{
+public:
+ Ipv4L4ProtocolTraceContextElement ();
+ Ipv4L4ProtocolTraceContextElement (int protocolNumber);
+ int Get (void) const;
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+private:
+ int m_protocolNumber;
+};
+
/**
* \brief L4 Ipv4 Demux
*/
@@ -43,7 +56,6 @@
{
public:
static const InterfaceId iid;
- typedef int Ipv4L4ProtocolTraceType;
Ipv4L4Demux (Ptr<Node> node);
virtual ~Ipv4L4Demux();
--- a/src/internet-node/ipv4-loopback-interface.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-loopback-interface.cc Wed Sep 05 18:35:39 2007 +0100
@@ -22,8 +22,9 @@
#include "ns3/empty-trace-resolver.h"
#include "ns3/net-device.h"
#include "ns3/node.h"
+#include "ns3/eui48-address.h"
#include "ipv4-loopback-interface.h"
-#include "ipv4-private.h"
+#include "ipv4-l3-protocol.h"
namespace ns3 {
@@ -43,8 +44,8 @@
void
Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest)
{
- Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
- ipv4->Receive (packet, GetDevice ());
+ Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+ ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, Eui48Address ("ff:ff:ff:ff:ff:ff"));
}
}//namespace ns3
--- a/src/internet-node/ipv4-private.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#include "ipv4-private.h"
-#include "ipv4-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId Ipv4Private::iid = MakeInterfaceId ("Ipv4Private", Object::iid);
-
-Ipv4Private::Ipv4Private (Ptr<Ipv4L3Protocol> ipv4)
- : m_ipv4 (ipv4)
-{
- SetInterfaceId (Ipv4Private::iid);
-}
-Ipv4Private::~Ipv4Private ()
-{
- NS_ASSERT (m_ipv4 == 0);
-}
-TraceResolver *
-Ipv4Private::CreateTraceResolver (TraceContext const &context)
-{
- return m_ipv4->CreateTraceResolver (context);
-}
-void
-Ipv4Private::Send (Packet const &packet, Ipv4Address source,
- Ipv4Address destination, uint8_t protocol)
-{
- m_ipv4->Send (packet, source, destination, protocol);
-}
-Ipv4Interface *
-Ipv4Private::FindInterfaceForDevice (Ptr<const NetDevice>device)
-{
- return m_ipv4->FindInterfaceForDevice (device);
-}
-void
-Ipv4Private::Receive(Packet& p, Ptr<NetDevice> device)
-{
- m_ipv4->Receive (p, device);
-}
-void
-Ipv4Private::DoDispose (void)
-{
- m_ipv4 = 0;
- Object::DoDispose ();
-}
-
-} // namespace ns3
--- a/src/internet-node/ipv4-private.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-#ifndef IPV4_PRIVATE_H
-#define IPV4_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ptr.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class Packet;
-class Ipv4L3Protocol;
-class TraceContext;
-class TraceResolver;
-class Ipv4Interface;
-class NetDevice;
-
-class Ipv4Private : public Object
-{
-public:
- static const InterfaceId iid;
- Ipv4Private (Ptr<Ipv4L3Protocol> ipv4);
- virtual ~Ipv4Private ();
-
- TraceResolver *CreateTraceResolver (TraceContext const &context);
- void Send (Packet const &packet, Ipv4Address source,
- Ipv4Address destination, uint8_t protocol);
- Ipv4Interface *FindInterfaceForDevice (Ptr<const NetDevice>device);
- void Receive(Packet& p, Ptr<NetDevice> device);
-protected:
- virtual void DoDispose (void);
-private:
- Ptr<Ipv4L3Protocol> m_ipv4;
-};
-
-} // namespace ns3
-
-#endif /* IPV4_PRIVATE_H */
--- a/src/internet-node/ipv4-static-routing.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-static-routing.h Wed Sep 05 18:35:39 2007 +0100
@@ -31,7 +31,6 @@
#include "ipv4-header.h"
#include "ns3/ptr.h"
#include "ns3/ipv4.h"
-#include "l3-protocol.h"
namespace ns3 {
--- a/src/internet-node/l3-demux.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-// Implement the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-#include <sstream>
-#include <string>
-#include "ns3/composite-trace-resolver.h"
-#include "ns3/node.h"
-#include "l3-demux.h"
-#include "l3-protocol.h"
-
-namespace ns3 {
-
-const InterfaceId L3Demux::iid = MakeInterfaceId ("L3Demux", Object::iid);
-
-L3Demux::L3Demux (Ptr<Node> node)
- : m_node (node)
-{
- SetInterfaceId (L3Demux::iid);
-}
-
-L3Demux::~L3Demux()
-{}
-
-void
-L3Demux::DoDispose (void)
-{
- for (L3Map_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
- {
- i->second->Dispose ();
- i->second = 0;
- }
- m_protocols.clear ();
- m_node = 0;
- Object::DoDispose ();
-}
-
-TraceResolver *
-L3Demux::CreateTraceResolver (TraceContext const &context) const
-{
- CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- for (L3Map_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
- {
- std::string protValue;
- std::ostringstream oss (protValue);
- oss << i->second->GetProtocolNumber ();
- ProtocolTraceType context = i->second->GetProtocolNumber ();
- resolver->Add (protValue,
- MakeCallback (&L3Protocol::CreateTraceResolver, PeekPointer (i->second)),
- context);
- }
- return resolver;
-}
-
-void L3Demux::Insert(Ptr<L3Protocol> p)
-{
- m_protocols.insert(L3Map_t::value_type(p->GetProtocolNumber (), p));
-}
-
-Ptr<L3Protocol>
-L3Demux::GetProtocol (int p)
-{ // Look up a protocol by protocol number
- L3Map_t::iterator i = m_protocols.find(p);
- if (i == m_protocols.end())
- {
- return 0;
- }
- return i->second; // Return the protocol
-}
-
-} //namespace ns3
-
--- a/src/internet-node/l3-demux.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-// Define the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-// This object manages the different layer 3 protocols for any ns3
-// node that has this capability.
-
-#ifndef L3_DEMUX_H
-#define L3_DEMUX_H
-
-#include <map>
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class L3Protocol;
-class Node;
-class TraceResolver;
-class TraceContext;
-
-/**
- * \brief L3 Demux
- */
-class L3Demux : public Object
-{
-public:
- static const InterfaceId iid;
- typedef int ProtocolTraceType;
- L3Demux(Ptr<Node> node);
- virtual ~L3Demux();
-
- /**
- * \param context the trace context to use to construct the
- * TraceResolver to return
- * \returns a TraceResolver which can resolve all traces
- * performed in this object. The caller must
- * delete the returned object.
- */
- TraceResolver *CreateTraceResolver (TraceContext const &context) const;
-
-
- /**
- * \param protocol a template for the protocol to add to this L3 Demux.
- *
- * Invoke Copy on the input template to get a copy of the input
- * protocol which can be used on the Node on which this L3 Demux
- * is running. The new L3Protocol is registered internally as
- * a working L3 Protocol and returned from this method.
- * The caller does not get ownership of the returned pointer.
- */
- void Insert(Ptr<L3Protocol> protocol);
- /**
- * \param protocolNumber number of protocol to lookup
- * in this L4 Demux
- * \returns a matching L3 Protocol
- *
- * This method is typically called by lower layers
- * to forward packets up the stack to the right protocol.
- * It is also called from NodeImpl::GetIpv4 for example.
- */
- Ptr<L3Protocol> GetProtocol (int protocolNumber);
-protected:
- virtual void DoDispose (void);
-private:
- typedef std::map<int, Ptr<ns3::L3Protocol> > L3Map_t;
-
- Ptr<Node> m_node;
- L3Map_t m_protocols;
-};
-
-} //namespace ns3
-#endif
-
--- a/src/internet-node/l3-protocol.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#include "l3-protocol.h"
-
-
-namespace ns3 {
-
-L3Protocol::L3Protocol(int protocolNumber, int version)
- : m_protocolNumber (protocolNumber),
- m_version (version)
-{}
-L3Protocol::~L3Protocol ()
-{}
-
-int
-L3Protocol::GetProtocolNumber (void) const
-{
- return m_protocolNumber;
-}
-int
-L3Protocol::GetVersion() const
-{
- return m_version;
-}
-
-void
-L3Protocol::DoDispose (void)
-{
- Object::DoDispose ();
-}
-
-}//namespace ns3
--- a/src/internet-node/l3-protocol.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#ifndef L3_PROTOCOL_H
-#define L3_PROTOCOL_H
-
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class NetDevice;
-class TraceResolver;
-class TraceContext;
-
-/**
- * ::Send is always defined in subclasses.
- */
-class L3Protocol : public Object {
-public:
- L3Protocol(int protocolNumber, int version);
- virtual ~L3Protocol ();
- /**
- * \return The protocol number of this Layer 3 protocol
- */
- int GetProtocolNumber (void) const;
- /**
- * \return The version number of this protocol
- */
- int GetVersion() const;
-
- virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0;
- /**
- * Lower layer calls this method after calling L3Demux::Lookup
- * The ARP subclass needs to know from which NetDevice this
- * packet is coming to:
- * - implement a per-NetDevice ARP cache
- * - send back arp replies on the right device
- */
- virtual void Receive(Packet& p, Ptr<NetDevice> device) = 0;
-
-protected:
- virtual void DoDispose (void);
-private:
- int m_protocolNumber;
- int m_version;
-};
-
-} // Namespace ns3
-
-#endif
--- a/src/internet-node/pcap-trace.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/pcap-trace.cc Wed Sep 05 18:35:39 2007 +0100
@@ -82,10 +82,9 @@
void
PcapTrace::LogIp (TraceContext const &context, Packet const &p, uint32_t interfaceIndex)
{
- NodeList::NodeIndex nodeIndex;
+ NodeListIndex nodeIndex;
context.Get (nodeIndex);
- uint32_t nodeId = NodeList::GetNode (nodeIndex)->GetId ();
- PcapWriter *writer = GetStream (nodeId, interfaceIndex);
+ PcapWriter *writer = GetStream (nodeIndex.Get (), interfaceIndex);
writer->WritePacket (p);
}
--- a/src/internet-node/udp-header.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-header.cc Wed Sep 05 18:35:39 2007 +0100
@@ -24,8 +24,17 @@
namespace ns3 {
+NS_HEADER_ENSURE_REGISTERED (UdpHeader);
+
bool UdpHeader::m_calcChecksum = false;
+uint32_t
+UdpHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<UdpHeader> ("UdpHeader.ns3");
+ return uid;
+}
+
/* The magic values below are used only for debugging.
* They can be used to easily detect memory corruption
* problems so you can see the patterns in memory.
@@ -84,7 +93,7 @@
destination.Serialize (buf+4);
buf[8] = 0;
buf[9] = protocol;
- uint16_t udpLength = m_payloadSize + GetSize ();
+ uint16_t udpLength = m_payloadSize + GetSerializedSize ();
buf[10] = udpLength >> 8;
buf[11] = udpLength & 0xff;
@@ -92,16 +101,16 @@
}
std::string
-UdpHeader::DoGetName (void) const
+UdpHeader::GetName (void) const
{
return "UDP";
}
void
-UdpHeader::PrintTo (std::ostream &os) const
+UdpHeader::Print (std::ostream &os) const
{
os << "("
- << "length: " << m_payloadSize + GetSize ()
+ << "length: " << m_payloadSize + GetSerializedSize ()
<< ") "
<< m_sourcePort << " > " << m_destinationPort
;
@@ -114,12 +123,12 @@
}
void
-UdpHeader::SerializeTo (Buffer::Iterator start) const
+UdpHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
i.WriteHtonU16 (m_sourcePort);
i.WriteHtonU16 (m_destinationPort);
- i.WriteHtonU16 (m_payloadSize + GetSize ());
+ i.WriteHtonU16 (m_payloadSize + GetSerializedSize ());
i.WriteU16 (0);
if (m_calcChecksum)
@@ -128,7 +137,7 @@
//XXXX
uint16_t checksum = Ipv4ChecksumCalculate (m_initialChecksum,
buffer->PeekData (),
- GetSize () + m_payloadSize);
+ GetSerializedSize () + m_payloadSize);
checksum = Ipv4ChecksumComplete (checksum);
i = buffer->Begin ();
i.Next (6);
@@ -137,12 +146,12 @@
}
}
uint32_t
-UdpHeader::DeserializeFrom (Buffer::Iterator start)
+UdpHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
m_sourcePort = i.ReadNtohU16 ();
m_destinationPort = i.ReadNtohU16 ();
- m_payloadSize = i.ReadNtohU16 () - GetSize ();
+ m_payloadSize = i.ReadNtohU16 () - GetSerializedSize ();
if (m_calcChecksum)
{
// XXX verify checksum.
--- a/src/internet-node/udp-header.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-header.h Wed Sep 05 18:35:39 2007 +0100
@@ -23,6 +23,7 @@
#define UDP_HEADER_H
#include <stdint.h>
+#include <string>
#include "ns3/header.h"
#include "ns3/ipv4-address.h"
@@ -30,15 +31,18 @@
/**
* \brief Packet header for UDP packets
*/
-class UdpHeader : public Header {
+class UdpHeader : public Header
+{
public:
+ static uint32_t GetUid (void);
+
/**
* \brief Constructor
*
* Creates a null header
*/
UdpHeader ();
- virtual ~UdpHeader ();
+ ~UdpHeader ();
/**
* \brief Enable checksum calculation for UDP (XXX currently has no effect)
@@ -80,13 +84,13 @@
Ipv4Address destination,
uint8_t protocol);
+ std::string GetName (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);
+
private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-
uint16_t m_sourcePort;
uint16_t m_destinationPort;
uint16_t m_payloadSize;
@@ -95,6 +99,6 @@
static bool m_calcChecksum;
};
-}; // namespace ns3
+} // namespace ns3
#endif /* UDP_HEADER */
--- a/src/internet-node/udp-l4-protocol.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-l4-protocol.cc Wed Sep 05 18:35:39 2007 +0100
@@ -29,8 +29,6 @@
#include "ipv4-end-point-demux.h"
#include "ipv4-end-point.h"
#include "ipv4-l3-protocol.h"
-#include "ipv4-private.h"
-#include "l3-demux.h"
#include "udp-socket.h"
namespace ns3 {
@@ -138,7 +136,7 @@
packet.AddHeader (udpHeader);
- Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
+ Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
if (ipv4 != 0)
{
ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
--- a/src/internet-node/udp-socket.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-socket.cc Wed Sep 05 18:35:39 2007 +0100
@@ -19,6 +19,7 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "ns3/node.h"
+#include "ns3/inet-socket-address.h"
#include "udp-socket.h"
#include "udp-l4-protocol.h"
#include "ipv4-end-point.h"
@@ -56,6 +57,12 @@
m_udp = 0;
}
+enum Socket::SocketErrno
+UdpSocket::GetErrno (void) const
+{
+ return m_errno;
+}
+
Ptr<Node>
UdpSocket::GetNode (void) const
{
@@ -72,12 +79,12 @@
int
UdpSocket::FinishBind (void)
{
- m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
- m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
if (m_endPoint == 0)
{
return -1;
}
+ m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
+ m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
return 0;
}
@@ -88,29 +95,35 @@
return FinishBind ();
}
int
-UdpSocket::Bind (Ipv4Address address)
-{
- m_endPoint = m_udp->Allocate (address);
- return FinishBind ();
-}
-int
-UdpSocket::Bind (uint16_t port)
+UdpSocket::Bind (const Address &address)
{
- m_endPoint = m_udp->Allocate (port);
- return FinishBind ();
-}
-int
-UdpSocket::Bind (Ipv4Address address, uint16_t port)
-{
- m_endPoint = m_udp->Allocate (address, port);
+ if (!InetSocketAddress::IsMatchingType (address))
+ {
+ return ERROR_INVAL;
+ }
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ if (ipv4 == Ipv4Address::GetAny () && port == 0)
+ {
+ m_endPoint = m_udp->Allocate ();
+ }
+ else if (ipv4 == Ipv4Address::GetAny () && port != 0)
+ {
+ m_endPoint = m_udp->Allocate (port);
+ }
+ else if (ipv4 != Ipv4Address::GetAny () && port == 0)
+ {
+ m_endPoint = m_udp->Allocate (ipv4);
+ }
+ else if (ipv4 != Ipv4Address::GetAny () && port != 0)
+ {
+ m_endPoint = m_udp->Allocate (ipv4, port);
+ }
+
return FinishBind ();
}
-enum Socket::SocketErrno
-UdpSocket::GetErrno (void) const
-{
- return m_errno;
-}
int
UdpSocket::ShutdownSend (void)
{
@@ -124,63 +137,43 @@
return 0;
}
-void
-UdpSocket::DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted)
-{
- // XXX: we should set the close state and check it in all API methods.
- if (!closeCompleted.IsNull ())
- {
- closeCompleted (this);
- }
-}
-void
-UdpSocket::DoConnect(const Ipv4Address & address,
- uint16_t portNumber,
- ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
- ns3::Callback<void, Ptr<Socket> > connectionFailed,
- ns3::Callback<void, Ptr<Socket> > halfClose)
+int
+UdpSocket::Close(void)
{
- m_defaultAddress = address;
- m_defaultPort = portNumber;
- if (!connectionSucceeded.IsNull ())
- {
- connectionSucceeded (this);
- }
- m_connected = true;
+ NotifyCloseCompleted ();
+ return 0;
}
+
int
-UdpSocket::DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- ns3::Callback<void, Ptr<Socket> > closeRequested)
+UdpSocket::Connect(const Address & address)
{
- // calling accept on a udp socket is a programming error.
- m_errno = ERROR_OPNOTSUPP;
- return -1;
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ m_defaultAddress = transport.GetIpv4 ();
+ m_defaultPort = transport.GetPort ();
+ NotifyConnectionSucceeded ();
+ m_connected = true;
+ return 0;
}
int
-UdpSocket::DoSend (const uint8_t* buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::Send (const Packet &p)
{
if (!m_connected)
{
m_errno = ERROR_NOTCONN;
return -1;
}
- Packet p;
- if (buffer == 0)
- {
- p = Packet (size);
- }
- else
- {
- p = Packet (buffer, size);
- }
- return DoSendPacketTo (p, m_defaultAddress, m_defaultPort, dataSent);
+ return DoSendTo (p, m_defaultAddress, m_defaultPort);
}
int
-UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::DoSendTo (const Packet &p, const Address &address)
+{
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ return DoSendTo (p, ipv4, port);
+}
+int
+UdpSocket::DoSendTo (const Packet &p, Ipv4Address ipv4, uint16_t port)
{
if (m_endPoint == 0)
{
@@ -196,64 +189,36 @@
m_errno = ERROR_SHUTDOWN;
return -1;
}
- m_udp->Send (p, m_endPoint->GetLocalAddress (), daddr,
- m_endPoint->GetLocalPort (), dport);
- if (!dataSent.IsNull ())
- {
- dataSent (this, p.GetSize ());
- }
+ m_udp->Send (p, m_endPoint->GetLocalAddress (), ipv4,
+ m_endPoint->GetLocalPort (), port);
+ NotifyDataSent (p.GetSize ());
return 0;
}
int
-UdpSocket::DoSendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::SendTo(const Address &address, const Packet &p)
{
if (m_connected)
{
m_errno = ERROR_ISCONN;
return -1;
}
- Packet p;
- if (buffer == 0)
- {
- p = Packet (size);
- }
- else
- {
- p = Packet (buffer, size);
- }
- return DoSendPacketTo (p, address, port, dataSent);
-}
-void
-UdpSocket::DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
- m_rxCallback = callback;
-}
-void
-UdpSocket::DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
- m_dummyRxCallback = callback;
+ InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+ Ipv4Address ipv4 = transport.GetIpv4 ();
+ uint16_t port = transport.GetPort ();
+ return DoSendTo (p, ipv4, port);
}
void
-UdpSocket::ForwardUp (const Packet &packet, Ipv4Address saddr, uint16_t sport)
+UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port)
{
if (m_shutdownRecv)
{
return;
}
+
+ Address address = InetSocketAddress (ipv4, port);
Packet p = packet;
- if (!m_dummyRxCallback.IsNull ())
- {
- m_dummyRxCallback (this, p.GetSize (), saddr, sport);
- }
- if (!m_rxCallback.IsNull ())
- {
- m_rxCallback (this, p.PeekData (), p.GetSize (), saddr, sport);
- }
+ NotifyDataReceived (p, address);
}
}//namespace ns3
--- a/src/internet-node/udp-socket.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-socket.h Wed Sep 05 18:35:39 2007 +0100
@@ -25,6 +25,7 @@
#include "ns3/callback.h"
#include "ns3/socket.h"
#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
namespace ns3 {
@@ -45,49 +46,32 @@
virtual enum SocketErrno GetErrno (void) const;
virtual Ptr<Node> GetNode (void) const;
virtual int Bind (void);
- virtual int Bind (Ipv4Address address);
- virtual int Bind (uint16_t port);
- virtual int Bind (Ipv4Address address, uint16_t port);
+ 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 Send (const Packet &p);
+ virtual int SendTo(const Address &address,const Packet &p);
private:
- virtual void DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted);
- virtual void DoConnect(const Ipv4Address & address,
- uint16_t portNumber,
- ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
- ns3::Callback<void, Ptr<Socket> > connectionFailed,
- ns3::Callback<void, Ptr<Socket> > halfClose);
- virtual int DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- ns3::Callback<void, Ptr<Socket> > closeRequested);
- virtual int DoSend (const uint8_t* buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
- virtual int DoSendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
- virtual void DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t>);
- virtual void DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>);
private:
friend class Udp;
// invoked by Udp class
int FinishBind (void);
- void ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport);
+ void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port);
void Destroy (void);
- int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
- ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
+ int DoSendTo (const Packet &p, const Address &daddr);
+ int DoSendTo (const Packet &p, Ipv4Address daddr, uint16_t dport);
Ipv4EndPoint *m_endPoint;
Ptr<Node> m_node;
Ptr<UdpL4Protocol> m_udp;
Ipv4Address m_defaultAddress;
uint16_t m_defaultPort;
- Callback<void,Ptr<Socket>,uint32_t,const Ipv4Address &,uint16_t> m_dummyRxCallback;
- Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Ipv4Address &,uint16_t> m_rxCallback;
+ Callback<void,Ptr<Socket>,uint32_t,const Address &> m_dummyRxCallback;
+ Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Address &> m_rxCallback;
enum SocketErrno m_errno;
bool m_shutdownSend;
bool m_shutdownRecv;
--- a/src/internet-node/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -2,14 +2,9 @@
def build(bld):
- obj = bld.create_obj('cpp', 'shlib')
- obj.name = 'ns3-internet-node'
- obj.target = obj.name
- obj.uselib_local = ['ns3-node', 'ns3-applications']
+ obj = bld.create_ns3_module('internet-node', ['node', 'applications'])
obj.source = [
'internet-node.cc',
- 'l3-demux.cc',
- 'l3-protocol.cc',
'ipv4-l4-demux.cc',
'ipv4-l4-protocol.cc',
'ipv4-header.cc',
@@ -27,9 +22,7 @@
'ipv4-loopback-interface.cc',
'udp-socket.cc',
'ipv4-end-point-demux.cc',
- 'arp-private.cc',
'ipv4-impl.cc',
- 'ipv4-private.cc',
'ascii-trace.cc',
'pcap-trace.cc',
'udp-impl.cc',
@@ -41,4 +34,5 @@
'ascii-trace.h',
'pcap-trace.h',
'ipv4-header.h',
+ 'udp-header.h',
]
--- a/src/mobility/mobility-model.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/mobility-model.cc Wed Sep 05 18:35:39 2007 +0100
@@ -52,9 +52,9 @@
}
double
-MobilityModel::GetDistanceFrom (const MobilityModel &other) const
+MobilityModel::GetDistanceFrom (Ptr<const MobilityModel> other) const
{
- Position oPosition = other.DoGet ();
+ Position oPosition = other->DoGet ();
Position position = DoGet ();
return CalculateDistance (position, oPosition);
}
--- a/src/mobility/mobility-model.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/mobility-model.h Wed Sep 05 18:35:39 2007 +0100
@@ -57,7 +57,7 @@
* \param position a reference to another mobility model
* \returns the distance between the two objects. Unit is meters.
*/
- double GetDistanceFrom (const MobilityModel &position) const;
+ double GetDistanceFrom (Ptr<const MobilityModel> position) const;
protected:
/**
* Must be invoked by subclasses when the course of the
--- a/src/mobility/position.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/position.h Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
#ifndef POSITION_H
#define POSITION_H
--- a/src/mobility/random-position.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/random-position.h Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
#ifndef RANDOM_POSITION_H
#define RANDOM_POSITION_H
--- a/src/mobility/speed.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/speed.h Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
#ifndef SPEED_H
#define SPEED_H
--- a/src/mobility/static-speed-helper.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/static-speed-helper.h Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
#ifndef STATIC_SPEED_HELPER_H
#define STATIC_SPEED_HELPER_H
--- a/src/mobility/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -1,10 +1,7 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- mobility = bld.create_obj('cpp', 'shlib')
- mobility.name = 'ns3-mobility'
- mobility.target = mobility.name
- mobility.uselib_local = ['ns3-core', 'ns3-simulator']
+ mobility = bld.create_ns3_module('mobility', ['core', 'simulator'])
mobility.source = [
'grid-topology.cc',
'hierarchical-mobility-model.cc',
--- a/src/node/address-utils.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/address-utils.cc Wed Sep 05 18:35:39 2007 +0100
@@ -26,24 +26,34 @@
{
i.WriteHtonU32 (ad.GetHostOrder ());
}
-void WriteTo (Buffer::Iterator &i, MacAddress ad)
+void WriteTo (Buffer::Iterator &i, const Address &ad)
{
- uint8_t mac[MacAddress::MAX_LEN];
- ad.Peek (mac);
+ uint8_t mac[Address::MAX_SIZE];
+ ad.CopyTo (mac);
i.Write (mac, ad.GetLength ());
}
+void WriteTo (Buffer::Iterator &i, Eui48Address ad)
+{
+ uint8_t mac[6];
+ ad.CopyTo (mac);
+ i.Write (mac, 6);
+}
void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad)
{
ad.SetHostOrder (i.ReadNtohU32 ());
}
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len)
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len)
{
- uint8_t mac[MacAddress::MAX_LEN];
+ uint8_t mac[Address::MAX_SIZE];
i.Read (mac, len);
- ad.Set (mac, len);
+ ad.CopyFrom (mac, len);
+}
+void ReadFrom (Buffer::Iterator &i, Eui48Address &ad)
+{
+ uint8_t mac[6];
+ i.Read (mac, 6);
+ ad.CopyFrom (mac);
}
-
-
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/address-utils.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/address-utils.h Wed Sep 05 18:35:39 2007 +0100
@@ -22,16 +22,19 @@
#define ADDRESS_UTILS_H
#include "ns3/buffer.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ipv4-address.h"
+#include "address.h"
+#include "eui48-address.h"
namespace ns3 {
void WriteTo (Buffer::Iterator &i, Ipv4Address ad);
-void WriteTo (Buffer::Iterator &i, MacAddress ad);
+void WriteTo (Buffer::Iterator &i, const Address &ad);
+void WriteTo (Buffer::Iterator &i, Eui48Address ad);
void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad);
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len);
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len);
+void ReadFrom (Buffer::Iterator &i, Eui48Address &ad);
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,164 @@
+#include "ns3/assert.h"
+#include "address.h"
+#include <iostream>
+#include <iomanip>
+
+namespace ns3 {
+
+Address::Address ()
+ : m_type (0),
+ m_len (0)
+{
+ memset (m_data, 0, m_len);
+}
+
+Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len)
+ : m_type (type),
+ m_len (len)
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memset (m_data, 0, m_len);
+ memcpy (m_data, buffer, m_len);
+}
+Address::Address (const Address & address)
+ : m_type (address.m_type),
+ m_len (address.m_len)
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memset (m_data, 0, m_len);
+ memcpy (m_data, address.m_data, m_len);
+}
+Address &
+Address::operator = (const Address &address)
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ m_type = address.m_type;
+ m_len = address.m_len;
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memset (m_data, 0, m_len);
+ memcpy (m_data, address.m_data, m_len);
+ return *this;
+}
+
+bool
+Address::IsInvalid (void) const
+{
+ return m_len == 0 && m_type == 0;
+}
+
+uint8_t
+Address::GetLength (void) const
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ return m_len;
+}
+uint32_t
+Address::CopyTo (uint8_t buffer[MAX_SIZE]) const
+{
+ NS_ASSERT (m_len <= MAX_SIZE);
+ memcpy (buffer, m_data, m_len);
+ return m_len;
+}
+uint32_t
+Address::CopyAllTo (uint8_t *buffer, uint8_t len) const
+{
+ NS_ASSERT (len >= m_len + 2);
+ buffer[0] = m_type;
+ buffer[1] = m_len;
+ memcpy (buffer + 2, m_data, m_len);
+ return m_len + 2;
+}
+
+uint32_t
+Address::CopyFrom (const uint8_t *buffer, uint8_t len)
+{
+ NS_ASSERT (len <= MAX_SIZE);
+ memcpy (m_data, buffer, len);
+ m_len = len;
+ return m_len;
+}
+uint32_t
+Address::CopyAllFrom (const uint8_t *buffer, uint8_t len)
+{
+ NS_ASSERT (len >= 2);
+ m_type = buffer[0];
+ m_len = buffer[1];
+ NS_ASSERT (len >= m_len + 2);
+ memcpy (m_data, buffer + 2, m_len);
+ return m_len + 2;
+}
+bool
+Address::CheckCompatible (uint8_t type, uint8_t len) const
+{
+ NS_ASSERT (len <= MAX_SIZE);
+ return m_len == len && (m_type == type || m_type == 0);
+}
+bool
+Address::IsMatchingType (uint8_t type) const
+{
+ return m_type == type;
+}
+
+uint8_t
+Address::Register (void)
+{
+ static uint8_t type = 1;
+ type++;
+ return type;
+}
+
+bool operator == (const Address &a, const Address &b)
+{
+ NS_ASSERT (a.m_type == b.m_type ||
+ a.m_type == 0 ||
+ b.m_type == 0);
+ NS_ASSERT (a.GetLength() == b.GetLength());
+ return memcmp (a.m_data, b.m_data, a.m_len) == 0;
+}
+bool operator != (const Address &a, const Address &b)
+{
+ return !(a == b);
+}
+bool operator < (const Address &a, const Address &b)
+{
+ NS_ASSERT (a.m_type == b.m_type ||
+ a.m_type == 0 ||
+ b.m_type == 0);
+ NS_ASSERT (a.GetLength() == b.GetLength());
+ for (uint8_t i = 0; i < a.GetLength(); i++)
+ {
+ if (a.m_data[i] < b.m_data[i])
+ {
+ return true;
+ }
+ else if (a.m_data[i] > b.m_data[i])
+ {
+ return false;
+ }
+ }
+ return false;
+}
+
+std::ostream& operator<< (std::ostream& os, const Address & address)
+{
+ if (address.m_len == 0)
+ {
+ os << "NULL-ADDRESS";
+ return os;
+ }
+ os.setf (std::ios::hex, std::ios::basefield);
+ os.fill('0');
+ for (uint8_t i=0; i < (address.m_len-1); i++)
+ {
+ os << std::setw(2) << (uint32_t)address.m_data[i] << ":";
+ }
+ // Final byte not suffixed by ":"
+ os << std::setw(2) << (uint32_t)address.m_data[address.m_len-1];
+ os.setf (std::ios::dec, std::ios::basefield);
+ os.fill(' ');
+ return os;
+}
+
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,172 @@
+#ifndef ADDRESS_H
+#define ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+/**
+ * \brief a polymophic address class
+ *
+ * This class is very similar in design and spirit to the BSD sockaddr
+ * structure: they are both used to hold multiple types of addresses
+ * together with the type of the address.
+ *
+ * A new address class defined by a user needs to:
+ * - allocate a type id with Address::Register
+ * - provide a method to convert his new address to an Address
+ * instance. This method is typically a member method named ConvertTo:
+ * Address MyAddress::ConvertTo (void) const;
+ * - provide a method to convert an Address instance back to
+ * an instance of his new address type. This method is typically
+ * a static member method of his address class named ConvertFrom:
+ * static MyAddress MyAddress::ConvertFrom (const Address &address);
+ * - the ConvertFrom method is expected to check that the type of the
+ * input Address instance is compatible with its own type.
+ *
+ * Typical code to create a new class type looks like:
+ * \code
+ * // this class represents addresses which are 2 bytes long.
+ * class MyAddress
+ * {
+ * public:
+ * Address ConvertTo (void) const;
+ * static MyAddress ConvertFrom (void);
+ * private:
+ * static uint8_t GetType (void);
+ * };
+ *
+ * Address MyAddress::ConvertTo (void) const
+ * {
+ * return Address (GetType (), m_buffer, 2);
+ * }
+ * MyAddress MyAddress::ConvertFrom (const Address &address)
+ * {
+ * MyAddress ad;
+ * NS_ASSERT (address.CheckCompatible (GetType (), 2));
+ * address.CopyTo (ad.m_buffer, 2);
+ * return ad;
+ * }
+ * uint8_t MyAddress::GetType (void)
+ * {
+ * static uint8_t type = Address::Register ();
+ * return type;
+ * }
+ * \endcode
+ */
+class Address
+{
+public:
+ enum {
+ /**
+ * The maximum size of a byte buffer which
+ * can be stored in an Address instance.
+ */
+ MAX_SIZE = 30
+ };
+
+ /**
+ * Create an invalid address
+ */
+ Address ();
+ /**
+ * \param type the type of the Address to create
+ * \param buffer a pointer to a buffer of bytes which hold
+ * a serialized representation of the address in network
+ * byte order.
+ * \param len the length of the buffer.
+ *
+ * Create an address from a type and a buffer. This constructor
+ * is typically invoked from the conversion functions of various
+ * address types when they have to convert themselves to an
+ * Address instance.
+ */
+ Address (uint8_t type, const uint8_t *buffer, uint8_t len);
+ Address (const Address & address);
+ Address &operator = (const Address &address);
+
+ /**
+ * \returns true if this address is invalid, false otherwise.
+ *
+ * An address is invalid if and only if it was created
+ * through the default constructor and it was never
+ * re-initialized.
+ */
+ bool IsInvalid (void) const;
+ /**
+ * \returns the length of the underlying address.
+ */
+ uint8_t GetLength (void) const;
+ /**
+ * \param buffer buffer to copy the address bytes to.
+ * \returns the number of bytes copied.
+ */
+ uint32_t CopyTo (uint8_t buffer[MAX_SIZE]) const;
+ /**
+ * \param buffer buffer to copy the whole address data structure to
+ * \param len the size of the buffer
+ * \returns the number of bytes copied.
+ */
+ uint32_t CopyAllTo (uint8_t *buffer, uint8_t len) const;
+ /**
+ * \param buffer pointer to a buffer of bytes which contain
+ * a serialized representation of the address in network
+ * byte order.
+ * \param len length of buffer
+ * \returns the number of bytes copied.
+ *
+ * Copy the input buffer to the internal buffer of this address
+ * instance.
+ */
+ uint32_t CopyFrom (const uint8_t *buffer, uint8_t len);
+ /**
+ * \param buffer pointer to a buffer of bytes which contain
+ * a copy of all the members of this Address class.
+ * \param len the length of the buffer
+ * \returns the number of bytes copied.
+ */
+ uint32_t CopyAllFrom (const uint8_t *buffer, uint8_t len);
+ /**
+ * \param type a type id as returned by Address::Register
+ * \param len the length associated to this type id.
+ *
+ * \returns true if the type of the address stored internally
+ * is compatible with the requested type, false otherwise.
+ */
+ bool CheckCompatible (uint8_t type, uint8_t len) const;
+ /**
+ * \param type a type id as returned by Address::Register
+ * \returns true if the type of the address stored internally
+ * is compatible with the requested type, false otherwise.
+ *
+ * This method checks that the types are _exactly_ equal.
+ * This method is really used only by the PacketSocketAddress
+ * and there is little point in using it otherwise so,
+ * you have been warned: DO NOT USE THIS METHOD.
+ */
+ bool IsMatchingType (uint8_t type) const;
+ /**
+ * Allocate a new type id for a new type of address.
+ * \returns a new type id.
+ */
+ static uint8_t Register (void);
+private:
+ friend bool operator == (const Address &a, const Address &b);
+ friend bool operator < (const Address &a, const Address &b);
+ friend std::ostream& operator<< (std::ostream& os, const Address & address);
+
+ uint8_t m_type;
+ uint8_t m_len;
+ uint8_t m_data[MAX_SIZE];
+};
+
+bool operator == (const Address &a, const Address &b);
+bool operator != (const Address &a, const Address &b);
+bool operator < (const Address &a, const Address &b);
+std::ostream& operator<< (std::ostream& os, const Address & address);
+
+} // namespace ns3
+
+
+#endif /* ADDRESS_H */
--- a/src/node/channel.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/channel.h Wed Sep 05 18:35:39 2007 +0100
@@ -1,7 +1,5 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2007 University of Washington
- *
* 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;
@@ -14,11 +12,8 @@
* 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: Craig Dowell <craigdo@ee.washingon.edu>
- *
- * Wed Feb 14 16:05:46 PST 2007 craigdo: Created
*/
+
#ifndef CHANNEL_H
#define CHANNEL_H
@@ -41,6 +36,7 @@
{
public:
static const InterfaceId iid;
+
Channel ();
Channel (std::string name);
@@ -62,8 +58,8 @@
virtual Ptr<NetDevice> GetDevice (uint32_t i) const = 0;
protected:
- virtual ~Channel ();
- std::string m_name;
+ virtual ~Channel ();
+ std::string m_name;
private:
};
--- a/src/node/ethernet-header.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-header.cc Wed Sep 05 18:35:39 2007 +0100
@@ -19,6 +19,8 @@
* Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
*/
+#include <iomanip>
+#include <iostream>
#include "ns3/assert.h"
#include "ns3/debug.h"
#include "ns3/header.h"
@@ -29,6 +31,15 @@
namespace ns3 {
+NS_HEADER_ENSURE_REGISTERED (EthernetHeader);
+
+uint32_t
+EthernetHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<EthernetHeader> ("EthernetHeader.ns3");
+ return uid;
+}
+
EthernetHeader::EthernetHeader (bool hasPreamble)
: m_enPreambleSfd (hasPreamble),
m_lengthType (0)
@@ -39,9 +50,6 @@
m_lengthType (0)
{}
-EthernetHeader::~EthernetHeader ()
-{}
-
void
EthernetHeader::SetLengthType (uint16_t lengthType)
{
@@ -65,22 +73,22 @@
}
void
-EthernetHeader::SetSource (MacAddress source)
+EthernetHeader::SetSource (Eui48Address source)
{
m_source = source;
}
-MacAddress
+Eui48Address
EthernetHeader::GetSource (void) const
{
return m_source;
}
void
-EthernetHeader::SetDestination (MacAddress dst)
+EthernetHeader::SetDestination (Eui48Address dst)
{
m_destination = dst;
}
-MacAddress
+Eui48Address
EthernetHeader::GetDestination (void) const
{
return m_destination;
@@ -99,21 +107,21 @@
}
std::string
-EthernetHeader::DoGetName (void) const
+EthernetHeader::GetName (void) const
{
return "ETHERNET";
}
void
-EthernetHeader::PrintTo (std::ostream &os) const
+EthernetHeader::Print (std::ostream &os) const
{
// ethernet, right ?
- os << "(ethernet)";
if (m_enPreambleSfd)
{
os << " preamble/sfd=" << m_preambleSfd << ",";
}
- os << " length/type=" << m_lengthType
+
+ os << " length/type=0x" << std::hex << m_lengthType << std::dec
<< ", source=" << m_source
<< ", destination=" << m_destination;
}
@@ -123,13 +131,15 @@
if (m_enPreambleSfd)
{
return PREAMBLE_SIZE + LENGTH_SIZE + 2*MAC_ADDR_SIZE;
- } else {
+ }
+ else
+ {
return LENGTH_SIZE + 2*MAC_ADDR_SIZE;
}
}
void
-EthernetHeader::SerializeTo (Buffer::Iterator start) const
+EthernetHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
@@ -137,14 +147,12 @@
{
i.WriteU64(m_preambleSfd);
}
- NS_ASSERT (m_destination.GetLength () == MAC_ADDR_SIZE);
- NS_ASSERT (m_source.GetLength () == MAC_ADDR_SIZE);
WriteTo (i, m_destination);
WriteTo (i, m_source);
i.WriteU16 (m_lengthType);
}
uint32_t
-EthernetHeader::DeserializeFrom (Buffer::Iterator start)
+EthernetHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
@@ -153,11 +161,11 @@
m_enPreambleSfd = i.ReadU64 ();
}
- ReadFrom (i, m_destination, MAC_ADDR_SIZE);
- ReadFrom (i, m_source, MAC_ADDR_SIZE);
+ ReadFrom (i, m_destination);
+ ReadFrom (i, m_source);
m_lengthType = i.ReadU16 ();
return GetSerializedSize ();
}
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/ethernet-header.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-header.h Wed Sep 05 18:35:39 2007 +0100
@@ -23,7 +23,8 @@
#define ETHERNET_HEADER_H
#include "ns3/header.h"
-#include "ns3/mac-address.h"
+#include <string>
+#include "ns3/eui48-address.h"
namespace ns3 {
@@ -45,11 +46,10 @@
* the packet. Eventually the class will be improved to also support
* VLAN tags in packet headers.
*/
-class EthernetHeader : public Header {
+class EthernetHeader : public Header
+{
public:
- static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field
- static const int LENGTH_SIZE = 2; /// size of the length_type header field
- static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields
+ static uint32_t GetUid (void);
/**
* \brief Construct a null ethernet header
@@ -62,7 +62,6 @@
* By default, does not add or remove an ethernet preamble
*/
EthernetHeader ();
- virtual ~EthernetHeader ();
/**
* \param size The size of the payload in bytes
*/
@@ -70,11 +69,11 @@
/**
* \param source The source address of this packet
*/
- void SetSource (MacAddress source);
+ void SetSource (Eui48Address source);
/**
* \param destination The destination address of this packet.
*/
- void SetDestination (MacAddress destination);
+ void SetDestination (Eui48Address destination);
/**
* \param preambleSfd The value that the preambleSfd field should take
*/
@@ -90,11 +89,11 @@
/**
* \return The source address of this packet
*/
- MacAddress GetSource (void) const;
+ Eui48Address GetSource (void) const;
/**
* \return The destination address of this packet
*/
- MacAddress GetDestination (void) const;
+ Eui48Address GetDestination (void) const;
/**
* \return The value of the PreambleSfd field
*/
@@ -104,12 +103,15 @@
*/
uint32_t GetHeaderSize() const;
+ std::string GetName (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);
private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+ static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field
+ static const int LENGTH_SIZE = 2; /// size of the length_type header field
+ static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields
/**
* If false, the preamble/sfd are not serialised/deserialised.
@@ -117,8 +119,8 @@
bool m_enPreambleSfd;
uint64_t m_preambleSfd; /// Value of the Preamble/SFD fields
uint16_t m_lengthType; /// Length or type of the packet
- MacAddress m_source; /// Source address
- MacAddress m_destination; /// Destination address
+ Eui48Address m_source; /// Source address
+ Eui48Address m_destination; /// Destination address
};
}; // namespace ns3
--- a/src/node/ethernet-trailer.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-trailer.cc Wed Sep 05 18:35:39 2007 +0100
@@ -28,16 +28,22 @@
namespace ns3 {
+NS_TRAILER_ENSURE_REGISTERED (EthernetTrailer);
+
bool EthernetTrailer::m_calcFcs = false;
+uint32_t
+EthernetTrailer::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<EthernetTrailer> ("EthernetTrailer.ns3");
+ return uid;
+}
+
EthernetTrailer::EthernetTrailer ()
{
Init();
}
-EthernetTrailer::~EthernetTrailer ()
-{}
-
void EthernetTrailer::Init()
{
m_fcs = 0;
@@ -85,13 +91,13 @@
return GetSerializedSize();
}
std::string
-EthernetTrailer::DoGetName (void) const
+EthernetTrailer::GetName (void) const
{
return "ETHERNET";
}
void
-EthernetTrailer::PrintTo (std::ostream &os) const
+EthernetTrailer::Print (std::ostream &os) const
{
os << " fcs=" << m_fcs;
}
@@ -102,7 +108,7 @@
}
void
-EthernetTrailer::SerializeTo (Buffer::Iterator end) const
+EthernetTrailer::Serialize (Buffer::Iterator end) const
{
Buffer::Iterator i = end;
i.Prev(GetSerializedSize());
@@ -110,7 +116,7 @@
i.WriteU32 (m_fcs);
}
uint32_t
-EthernetTrailer::DeserializeFrom (Buffer::Iterator end)
+EthernetTrailer::Deserialize (Buffer::Iterator end)
{
Buffer::Iterator i = end;
uint32_t size = GetSerializedSize();
--- a/src/node/ethernet-trailer.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-trailer.h Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
#include "ns3/trailer.h"
#include "ns3/packet.h"
+#include <string>
namespace ns3 {
/**
@@ -33,13 +34,16 @@
* ethernet packet. The actual FCS functionality is not yet coded and
* so this acts more as a placeholder.
*/
-class EthernetTrailer : public Trailer {
+class EthernetTrailer : public Trailer
+{
public:
+ static uint32_t GetUid (void);
+
/**
* \brief Construct a null ethernet trailer
*/
EthernetTrailer ();
- virtual ~EthernetTrailer ();
+
/**
* \brief Enable or disabled FCS checking and calculations
* \param enable If true, enables FCS calculations.
@@ -77,12 +81,12 @@
*/
uint32_t GetTrailerSize() const;
+ std::string GetName (void) const;
+ void Print (std::ostream &os) const;
+ uint32_t GetSerializedSize (void) const;
+ void Serialize (Buffer::Iterator end) const;
+ uint32_t Deserialize (Buffer::Iterator end);
private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator end) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator end);
/**
* Initializes the trailer parameters during construction.
@@ -98,7 +102,7 @@
};
-}; // namespace ns3
+} // namespace ns3
#endif /* ETHERNET_TRAILER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui48-address.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 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 "eui48-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+ if (c >= ASCII_a && c <= ASCII_z) {
+ return c;
+ } else if (c >= ASCII_A && c <= ASCII_Z) {
+ return c + (ASCII_a - ASCII_A);
+ } else {
+ return c;
+ }
+}
+
+
+Eui48Address::Eui48Address ()
+{
+ memset (m_address, 0, 6);
+}
+Eui48Address::Eui48Address (const char *str)
+{
+ int i = 0;
+ while (*str != 0 && i < 6)
+ {
+ uint8_t byte = 0;
+ while (*str != ASCII_COLON && *str != 0)
+ {
+ byte <<= 4;
+ char low = AsciiToLowCase (*str);
+ if (low >= ASCII_a)
+ {
+ byte |= low - ASCII_a + 10;
+ }
+ else
+ {
+ byte |= low - ASCII_ZERO;
+ }
+ str++;
+ }
+ m_address[i] = byte;
+ i++;
+ if (*str == 0)
+ {
+ break;
+ }
+ str++;
+ }
+ NS_ASSERT (i == 6);
+}
+void
+Eui48Address::CopyFrom (const uint8_t buffer[6])
+{
+ memcpy (m_address, buffer, 6);
+}
+void
+Eui48Address::CopyTo (uint8_t buffer[6]) const
+{
+ memcpy (buffer, m_address, 6);
+}
+
+bool
+Eui48Address::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 6);
+}
+Eui48Address::operator Address ()
+{
+ return ConvertTo ();
+}
+Address
+Eui48Address::ConvertTo (void) const
+{
+ return Address (GetType (), m_address, 6);
+}
+Eui48Address
+Eui48Address::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 6));
+ Eui48Address retval;
+ address.CopyTo (retval.m_address);
+ return retval;
+}
+Eui48Address
+Eui48Address::Allocate (void)
+{
+ static uint64_t id = 0;
+ id++;
+ Eui48Address address;
+ address.m_address[0] = (id >> 40) & 0xff;
+ address.m_address[1] = (id >> 32) & 0xff;
+ address.m_address[2] = (id >> 24) & 0xff;
+ address.m_address[3] = (id >> 16) & 0xff;
+ address.m_address[4] = (id >> 8) & 0xff;
+ address.m_address[5] = (id >> 0) & 0xff;
+ return address;
+}
+uint8_t
+Eui48Address::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+bool operator == (const Eui48Address &a, const Eui48Address &b)
+{
+ uint8_t ada[6];
+ uint8_t adb[6];
+ a.CopyTo (ada);
+ b.CopyTo (adb);
+ return memcmp (ada, adb, 6) == 0;
+}
+bool operator != (const Eui48Address &a, const Eui48Address &b)
+{
+ return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Eui48Address & address)
+{
+ uint8_t ad[6];
+ address.CopyTo (ad);
+
+ os.setf (std::ios::hex, std::ios::basefield);
+ os.fill('0');
+ for (uint8_t i=0; i < 5; i++)
+ {
+ os << std::setw(2) << (uint32_t)ad[i] << ":";
+ }
+ // Final byte not suffixed by ":"
+ os << std::setw(2) << (uint32_t)ad[5];
+ os.setf (std::ios::dec, std::ios::basefield);
+ os.fill(' ');
+ return os;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui48-address.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 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 EUI48_ADDRESS_H
+#define EUI48_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-48 address
+ *
+ * This class can contain 48 bit IEEE addresses.
+ */
+class Eui48Address
+{
+public:
+ Eui48Address ();
+ /**
+ * \param str a string representing the new Eui48Address
+ *
+ * The format of the string is "xx:xx:xx:xx:xx:xx"
+ */
+ Eui48Address (const char *str);
+
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the input address to our internal buffer.
+ */
+ void CopyFrom (const uint8_t buffer[6]);
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the internal address to the input buffer.
+ */
+ void CopyTo (uint8_t buffer[6]) const;
+
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ operator Address ();
+ /**
+ * \param address a polymorphic address
+ * \returns a new Eui48Address from the polymorphic address
+ *
+ * This function performs a type check and asserts if the
+ * type of the input address is not compatible with an
+ * Eui48Address.
+ */
+ static Eui48Address ConvertFrom (const Address &address);
+ /**
+ * \returns true if the address matches, false otherwise.
+ */
+ static bool IsMatchingType (const Address &address);
+ /**
+ * Allocate a new Eui48Address.
+ */
+ static Eui48Address Allocate (void);
+private:
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ Address ConvertTo (void) const;
+ static uint8_t GetType (void);
+ uint8_t m_address[6];
+};
+
+bool operator == (const Eui48Address &a, const Eui48Address &b);
+bool operator != (const Eui48Address &a, const Eui48Address &b);
+std::ostream& operator<< (std::ostream& os, const Eui48Address & address);
+
+} // namespace ns3
+
+#endif /* EUI48_ADDRESS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui64-address.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 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 "eui64-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+ if (c >= ASCII_a && c <= ASCII_z) {
+ return c;
+ } else if (c >= ASCII_A && c <= ASCII_Z) {
+ return c + (ASCII_a - ASCII_A);
+ } else {
+ return c;
+ }
+}
+
+
+Eui64Address::Eui64Address ()
+{
+ memset (m_address, 0, 8);
+}
+Eui64Address::Eui64Address (const char *str)
+{
+ int i = 0;
+ while (*str != 0 && i < 8)
+ {
+ uint8_t byte = 0;
+ while (*str != ASCII_COLON && *str != 0)
+ {
+ byte <<= 4;
+ char low = AsciiToLowCase (*str);
+ if (low >= ASCII_a)
+ {
+ byte |= low - ASCII_a + 10;
+ }
+ else
+ {
+ byte |= low - ASCII_ZERO;
+ }
+ str++;
+ }
+ m_address[i] = byte;
+ i++;
+ if (*str == 0)
+ {
+ break;
+ }
+ str++;
+ }
+ NS_ASSERT (i == 6);
+}
+void
+Eui64Address::CopyFrom (const uint8_t buffer[8])
+{
+ memcpy (m_address, buffer, 8);
+}
+void
+Eui64Address::CopyTo (uint8_t buffer[8]) const
+{
+ memcpy (buffer, m_address, 8);
+}
+
+bool
+Eui64Address::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 8);
+}
+Eui64Address::operator Address ()
+{
+ return ConvertTo ();
+}
+Eui64Address
+Eui64Address::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 8));
+ Eui64Address retval;
+ address.CopyTo (retval.m_address);
+ return retval;
+}
+Address
+Eui64Address::ConvertTo (void) const
+{
+ return Address (GetType (), m_address, 8);
+}
+
+Eui64Address
+Eui64Address::Allocate (void)
+{
+ static uint64_t id = 0;
+ id++;
+ Eui64Address address;
+ address.m_address[0] = (id >> 56) & 0xff;
+ address.m_address[1] = (id >> 48) & 0xff;
+ address.m_address[2] = (id >> 40) & 0xff;
+ address.m_address[3] = (id >> 32) & 0xff;
+ address.m_address[4] = (id >> 24) & 0xff;
+ address.m_address[5] = (id >> 16) & 0xff;
+ address.m_address[6] = (id >> 8) & 0xff;
+ address.m_address[7] = (id >> 0) & 0xff;
+ return address;
+}
+uint8_t
+Eui64Address::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+bool operator == (const Eui64Address &a, const Eui64Address &b)
+{
+ uint8_t ada[8];
+ uint8_t adb[8];
+ a.CopyTo (ada);
+ b.CopyTo (adb);
+ return memcmp (ada, adb, 8) == 0;
+}
+bool operator != (const Eui64Address &a, const Eui64Address &b)
+{
+ return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Eui64Address & address)
+{
+ uint8_t ad[8];
+ address.CopyTo (ad);
+
+ os.setf (std::ios::hex, std::ios::basefield);
+ os.fill('0');
+ for (uint8_t i=0; i < 7; i++)
+ {
+ os << std::setw(2) << (uint32_t)ad[i] << ":";
+ }
+ // Final byte not suffixed by ":"
+ os << std::setw(2) << (uint32_t)ad[7];
+ os.setf (std::ios::dec, std::ios::basefield);
+ os.fill(' ');
+ return os;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui64-address.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 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 EUI64_ADDRESS_H
+#define EUI64_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-64 address
+ *
+ * This class can contain 64 bit IEEE addresses.
+ */
+class Eui64Address
+{
+public:
+ Eui64Address ();
+ /**
+ * \param str a string representing the new Eui64Address
+ *
+ * The format of the string is "xx:xx:xx:xx:xx:xx"
+ */
+ Eui64Address (const char *str);
+
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the input address to our internal buffer.
+ */
+ void CopyFrom (const uint8_t buffer[8]);
+ /**
+ * \param buffer address in network order
+ *
+ * Copy the internal address to the input buffer.
+ */
+ void CopyTo (uint8_t buffer[8]) const;
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ operator Address ();
+ /**
+ * \param address a polymorphic address
+ * \returns a new Eui64Address from the polymorphic address
+ *
+ * This function performs a type check and asserts if the
+ * type of the input address is not compatible with an
+ * Eui64Address.
+ */
+ static Eui64Address ConvertFrom (const Address &address);
+ /**
+ * \returns true if the address matches, false otherwise.
+ */
+ static bool IsMatchingType (const Address &address);
+ /**
+ * Allocate a new Eui64Address.
+ */
+ static Eui64Address Allocate (void);
+private:
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ Address ConvertTo (void) const;
+ static uint8_t GetType (void);
+ uint8_t m_address[8];
+};
+
+bool operator == (const Eui64Address &a, const Eui64Address &b);
+bool operator != (const Eui64Address &a, const Eui64Address &b);
+std::ostream& operator<< (std::ostream& os, const Eui64Address & address);
+
+} // namespace ns3
+
+#endif /* EUI64_ADDRESS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "inet-socket-address.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4, uint16_t port)
+ : m_ipv4 (ipv4),
+ m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4)
+ : m_ipv4 (ipv4),
+ m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (const char *ipv4, uint16_t port)
+ : m_ipv4 (Ipv4Address (ipv4)),
+ m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (const char * ipv4)
+ : m_ipv4 (Ipv4Address (ipv4)),
+ m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (uint16_t port)
+ : m_ipv4 (Ipv4Address::GetAny ()),
+ m_port (port)
+{}
+uint16_t
+InetSocketAddress::GetPort (void) const
+{
+ return m_port;
+}
+Ipv4Address
+InetSocketAddress::GetIpv4 (void) const
+{
+ return m_ipv4;
+}
+
+void
+InetSocketAddress::SetPort (uint16_t port)
+{
+ m_port = port;
+}
+void
+InetSocketAddress::SetIpv4 (Ipv4Address address)
+{
+ m_ipv4 = address;
+}
+
+bool
+InetSocketAddress::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 6);
+}
+
+InetSocketAddress::operator Address () const
+{
+ return ConvertTo ();
+}
+
+Address
+InetSocketAddress::ConvertTo (void) const
+{
+ uint8_t buf[6];
+ m_ipv4.Serialize (buf);
+ buf[4] = m_port & 0xff;
+ buf[5] = (m_port >> 8) & 0xff;
+ return Address (GetType (), buf, 6);
+}
+InetSocketAddress
+InetSocketAddress::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 6));
+ uint8_t buf[6];
+ address.CopyTo (buf);
+ Ipv4Address ipv4 = Ipv4Address::Deserialize (buf);
+ uint16_t port = buf[4] | (buf[5] << 8);
+ return InetSocketAddress (ipv4, port);
+}
+uint8_t
+InetSocketAddress::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#ifndef INET_SOCKET_ADDRESS_H
+#define INET_SOCKET_ADDRESS_H
+
+#include "address.h"
+#include "ipv4-address.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+
+/**
+ * \brief an Inet address class
+ *
+ * This class is similar to inet_sockaddr in the BSD socket
+ * API. i.e., this class holds an Ipv4Address and a port number
+ * to form an ipv4 transport endpoint.
+ */
+class InetSocketAddress
+{
+public:
+ /**
+ * \param ipv4 the ipv4 address
+ * \param port the port number
+ */
+ InetSocketAddress (Ipv4Address ipv4, uint16_t port);
+ /**
+ * \param ipv4 the ipv4 address
+ *
+ * The port number is set to zero by default.
+ */
+ InetSocketAddress (Ipv4Address ipv4);
+ /**
+ * \param port the port number
+ *
+ * The ipv4 address is set to the "Any" address by default.
+ */
+ InetSocketAddress (uint16_t port);
+ /**
+ * \param ipv4 string which represents an ipv4 address
+ * \param port the port number
+ */
+ InetSocketAddress (const char *ipv4, uint16_t port);
+ /**
+ * \param ipv4 string which represents an ipv4 address
+ *
+ * The port number is set to zero.
+ */
+ InetSocketAddress (const char *ipv4);
+ /**
+ * \returns the port number
+ */
+ uint16_t GetPort (void) const;
+ /**
+ * \returns the ipv4 address
+ */
+ Ipv4Address GetIpv4 (void) const;
+
+ /**
+ * \param port the new port number.
+ */
+ void SetPort (uint16_t port);
+ /**
+ * \param address the new ipv4 address
+ */
+ void SetIpv4 (Ipv4Address address);
+
+ /**
+ * \returns true if the address matches, false otherwise.
+ */
+ static bool IsMatchingType (const Address &address);
+
+ /**
+ * \returns an Address instance which represents this
+ * InetSocketAddress instance.
+ */
+ operator Address () const;
+
+ /**
+ * \param address the Address instance to convert from.
+ *
+ * Returns an InetSocketAddress which corresponds to the input
+ * Address
+ */
+ static InetSocketAddress ConvertFrom (const Address &address);
+private:
+ Address ConvertTo (void) const;
+
+ static uint8_t GetType (void);
+ Ipv4Address m_ipv4;
+ uint16_t m_port;
+};
+
+} // namespace ns3
+
+
+#endif /* INET_SOCKET_ADDRESS_H */
--- a/src/node/ipv4-address.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ipv4-address.cc Wed Sep 05 18:35:39 2007 +0100
@@ -19,11 +19,11 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "ns3/debug.h"
+#include "ipv4-address.h"
+#include "ns3/assert.h"
NS_DEBUG_COMPONENT_DEFINE("Ipv4Address");
-#include "ipv4-address.h"
-
namespace ns3 {
@@ -135,6 +135,17 @@
m_address = AsciiToIpv4Host (address);
}
+void
+Ipv4Address::Set (uint32_t address)
+{
+ m_address = address;
+}
+void
+Ipv4Address::Set (char const *address)
+{
+ m_address = AsciiToIpv4Host (address);
+}
+
bool
Ipv4Address::IsEqual (Ipv4Address other) const
{
@@ -160,8 +171,11 @@
bool
Ipv4Address::IsMulticast (void) const
{
- // XXX
- return false;
+//
+// Multicast addresses are defined as ranging from 224.0.0.0 through
+// 239.255.255.255 (which is E0000000 through EFFFFFFF in hex).
+//
+ return (m_address >= 0xe0000000 && m_address <= 0xefffffff);
}
uint32_t
@@ -182,6 +196,20 @@
buf[2] = (m_address >> 8) & 0xff;
buf[3] = (m_address >> 0) & 0xff;
}
+Ipv4Address
+Ipv4Address::Deserialize (const uint8_t buf[4])
+{
+ Ipv4Address ipv4;
+ ipv4.m_address = 0;
+ ipv4.m_address |= buf[0];
+ ipv4.m_address <<= 8;
+ ipv4.m_address |= buf[1];
+ ipv4.m_address <<= 8;
+ ipv4.m_address |= buf[2];
+ ipv4.m_address <<= 8;
+ ipv4.m_address |= buf[3];
+ return ipv4;
+}
void
Ipv4Address::Print (std::ostream &os) const
@@ -192,7 +220,39 @@
<< ((m_address >> 0) & 0xff);
}
+bool
+Ipv4Address::IsMatchingType (const Address &address)
+{
+ return address.CheckCompatible (GetType (), 4);
+}
+Ipv4Address::operator Address ()
+{
+ return ConvertTo ();
+}
+Address
+Ipv4Address::ConvertTo (void) const
+{
+ uint8_t buf[4];
+ Serialize (buf);
+ return Address (GetType (), buf, 4);
+}
+
+Ipv4Address
+Ipv4Address::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (address.CheckCompatible (GetType (), 4));
+ uint8_t buf[4];
+ address.CopyTo (buf);
+ return Deserialize (buf);
+}
+
+uint8_t
+Ipv4Address::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
Ipv4Address
Ipv4Address::GetZero (void)
--- a/src/node/ipv4-address.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ipv4-address.h Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <ostream>
+#include "address.h"
namespace ns3 {
@@ -52,6 +53,22 @@
Ipv4Address (char const *address);
/**
+ * input address is in host order.
+ * \param address The host order 32-bit address
+ */
+ void Set (uint32_t address);
+ /**
+ * \brief Sets an Ipv4Address by parsing a the input C-string
+ *
+ * Input address is in format:
+ * hhh.xxx.xxx.lll
+ * where h is the high byte and l the
+ * low byte
+ * \param address C-string containing the address as described above
+ */
+ void Set (char const *address);
+
+ /**
* \brief Comparison operation between two Ipv4Addresses
* \param other address to which to compare this address
* \return True if the addresses are equal. False otherwise.
@@ -70,11 +87,19 @@
void SetHostOrder (uint32_t ip);
/**
* Serialize this address to a 4-byte buffer
+ *
* \param buf output buffer to which this address gets overwritten with this
* Ipv4Address
*/
void Serialize (uint8_t buf[4]) const;
/**
+ * \param buf buffer to read address from
+ * \returns an Ipv4Address
+ *
+ * The input address is expected to be in network byte order format.
+ */
+ static Ipv4Address Deserialize (const uint8_t buf[4]);
+ /**
* \brief Print this address to the given output stream
*
* The print format is in the typical "192.168.1.1"
@@ -91,15 +116,21 @@
* (bitwise and) with a network mask, yielding an IPv4 network
* address.
*
- * \param a network mask
+ * \param mask a network mask
*/
Ipv4Address CombineMask (Ipv4Mask const &mask) const;
+ static bool IsMatchingType (const Address &address);
+ operator Address ();
+ static Ipv4Address ConvertFrom (const Address &address);
+
static Ipv4Address GetZero (void);
static Ipv4Address GetAny (void);
static Ipv4Address GetBroadcast (void);
static Ipv4Address GetLoopback (void);
private:
+ Address ConvertTo (void) const;
+ static uint8_t GetType (void);
uint32_t m_address;
};
--- a/src/node/llc-snap-header.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/llc-snap-header.cc Wed Sep 05 18:35:39 2007 +0100
@@ -19,17 +19,24 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+#include "llc-snap-header.h"
#include "ns3/assert.h"
-
-#include "llc-snap-header.h"
+#include <string>
namespace ns3 {
+NS_HEADER_ENSURE_REGISTERED (LlcSnapHeader);
+
+uint32_t
+LlcSnapHeader::GetUid (void)
+{
+ static uint32_t uid = AllocateUid<LlcSnapHeader> ("LlcSnapHeader.ns3");
+ return uid;
+}
+
LlcSnapHeader::LlcSnapHeader ()
{}
-LlcSnapHeader::~LlcSnapHeader ()
-{}
void
LlcSnapHeader::SetType (uint16_t type)
{
@@ -48,13 +55,13 @@
}
std::string
-LlcSnapHeader::DoGetName (void) const
+LlcSnapHeader::GetName (void) const
{
return "LLCSNAP";
}
void
-LlcSnapHeader::PrintTo (std::ostream &os) const
+LlcSnapHeader::Print (std::ostream &os) const
{
os << "(type 0x";
os.setf (std::ios::hex, std::ios::basefield);
@@ -64,7 +71,7 @@
}
void
-LlcSnapHeader::SerializeTo (Buffer::Iterator start) const
+LlcSnapHeader::Serialize (Buffer::Iterator start) const
{
Buffer::Iterator i = start;
uint8_t buf[] = {0xaa, 0xaa, 0x03, 0, 0, 0};
@@ -72,7 +79,7 @@
i.WriteHtonU16 (m_etherType);
}
uint32_t
-LlcSnapHeader::DeserializeFrom (Buffer::Iterator start)
+LlcSnapHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
i.Next (5+1);
@@ -81,4 +88,4 @@
}
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/llc-snap-header.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/llc-snap-header.h Wed Sep 05 18:35:39 2007 +0100
@@ -23,28 +23,30 @@
#define LLC_SNAP_HEADER_H
#include <stdint.h>
+#include <string>
#include "ns3/header.h"
namespace ns3 {
-class LlcSnapHeader : public Header {
- public:
+class LlcSnapHeader : public Header
+{
+public:
+ static uint32_t GetUid (void);
+
LlcSnapHeader ();
- virtual ~LlcSnapHeader ();
-
void SetType (uint16_t type);
uint16_t GetType (void);
+ std::string GetName (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);
private:
- virtual std::string DoGetName (void) const;
- virtual void PrintTo (std::ostream &os) const;
- virtual uint32_t GetSerializedSize (void) const;
- virtual void SerializeTo (Buffer::Iterator start) const;
- virtual uint32_t DeserializeFrom (Buffer::Iterator start);
uint16_t m_etherType;
};
-}; // namespace ns3
+} // namespace ns3
#endif /* LLC_SNAP_HEADER_H */
--- a/src/node/mac-address.cc Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#include <iostream>
-#include <iomanip>
-#include "ns3/assert.h"
-#include "mac-address.h"
-
-#define ASCII_a (0x41)
-#define ASCII_z (0x5a)
-#define ASCII_A (0x61)
-#define ASCII_Z (0x7a)
-#define ASCII_COLON (0x3a)
-#define ASCII_ZERO (0x30)
-
-namespace ns3 {
-
-// Static variables
-uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN];
-
-static char
-AsciiToLowCase (char c)
-{
- if (c >= ASCII_a && c <= ASCII_z) {
- return c;
- } else if (c >= ASCII_A && c <= ASCII_Z) {
- return c + (ASCII_a - ASCII_A);
- } else {
- return c;
- }
-}
-
-
-MacAddress::MacAddress () : m_len(0)
-{
- for (int i=0; i < MacAddress::MAX_LEN; i++)
- {
- m_address[i] = 0;
- }
-}
-
-MacAddress::MacAddress(uint8_t len) : m_len(len)
-{
- NS_ASSERT (len <= MacAddress::MAX_LEN);
- AdvanceAddress();
- memcpy(m_address, g_nextAddress, len);
-}
-
-MacAddress::MacAddress (uint8_t const *address, uint8_t len)
-{
- NS_ASSERT (len <= MacAddress::MAX_LEN);
- for (int i=0; i < len; i++)
- {
- m_address[i] = address[i];
- }
- for (int i=len; i < MacAddress::MAX_LEN; i++)
- {
- m_address[i] = 0;
- }
- m_len = len;
-}
-
-MacAddress::MacAddress (char const *str)
-{
- int i = 0;
- while (*str != 0 && i < MacAddress::MAX_LEN) {
- uint8_t byte = 0;
- while (*str != ASCII_COLON && *str != 0) {
- byte <<= 4;
- char low = AsciiToLowCase (*str);
- if (low >= ASCII_a) {
- byte |= low - ASCII_a + 10;
- } else {
- byte |= low - ASCII_ZERO;
- }
- str++;
- }
- m_address[i] = byte;
- i++;
- if (*str == 0) {
- break;
- }
- str++;
- }
- m_len = i;
-}
-
-MacAddress::~MacAddress ()
-{}
-
-bool
-MacAddress::IsEqual (MacAddress other) const
-{
- if (memcmp(other.m_address, m_address, m_len))
- {
- return false;
- }
- else
- {
- return true;
- }
-}
-
-void
-MacAddress::Print (std::ostream &os) const
-{
- int i;
- if (m_len == 0)
- {
- os << "NULL-ADDRESS";
- return;
- }
- os.setf (std::ios::hex, std::ios::basefield);
- std::cout.fill('0');
- for (i=0; i< (m_len-1); i++)
- {
- os << std::setw(2) << (uint32_t)m_address[i] << ":";
- }
- // Final byte not suffixed by ":"
- os << std::setw(2) << (uint32_t)m_address[i];
- os.setf (std::ios::dec, std::ios::basefield);
- std::cout.fill(' ');
-}
-
-uint8_t
-MacAddress::GetLength () const
-{
- return m_len;
-}
-
-void
-MacAddress::Peek (uint8_t ad[MacAddress::MAX_LEN]) const
-{
- memcpy (ad, m_address, MacAddress::MAX_LEN);
-}
-void
-MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len)
-{
- memcpy (m_address, ad, MacAddress::MAX_LEN);
- m_len = len;
-}
-
-// Static methods
-void MacAddress::AdvanceAddress()
- {
- // Advance to next address, little end first
- for(size_t i = 0; i < MAX_LEN; ++i)
- {
- if (++g_nextAddress[i] != 0) break;
- }
- }
-
-// Non-member operators
-bool operator == (MacAddress const&a, MacAddress const&b)
-{
- return a.IsEqual (b);
-}
-
-bool operator != (MacAddress const&a, MacAddress const&b)
-{
- return !a.IsEqual (b);
-}
-
-bool operator < (MacAddress const&a, MacAddress const&b)
-{
- uint8_t a_p[MacAddress::MAX_LEN];
- uint8_t b_p[MacAddress::MAX_LEN];
- a.Peek (a_p);
- b.Peek (b_p);
- NS_ASSERT (a.GetLength() == b.GetLength());
- for (uint8_t i = 0; i < a.GetLength(); i++)
- {
- if (a_p[i] < b_p[i])
- {
- return true;
- }
- else if (a_p[i] > b_p[i])
- {
- return false;
- }
- }
- return false;
-}
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address)
-{
- address.Print (os);
- return os;
-}
-
-
-}; // namespace ns3
--- a/src/node/mac-address.h Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 INRIA
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
- */
-
-#ifndef MAC_ADDRESS_H
-#define MAC_ADDRESS_H
-
-#include <stdint.h>
-#include <ostream>
-
-namespace ns3 {
-
-/**
- * \brief base class for Network Device addresses
- *
- * This class is a base class for different types of Network
- * Device addresses. It generically stores an address of
- * MAX_ADDR_LEN bytes, and provides methods to compare, print, and set
- * the address.
- */
-class MacAddress {
-public:
- enum {
- MAX_LEN = 32
- };
- /**
- * \brief Construct a null MacAddress
- *
- * This MacAddress has length of zero, and is internally all zeros
- */
- MacAddress (void);
- /**
- * \brief Construct a MacAddress using the next available
- * address.
- * \see MacAddres::Next
- * \param len length, in bytes, of the desired address
- */
- MacAddress(uint8_t len);
- /**
- * \brief Construct a MacAddress from a byte-array
- *
- * low byte should be first.
- * \param address a byte array indicating the address
- * \param len length, in bytes, of the address points to
- */
- MacAddress (uint8_t const *address, uint8_t len);
- /**
- * \brief Construct a MacAddress from a C-string
- *
- * The string should look like this:
- * hh:xx:xx:xx:xx:ll
- * where hh is the high byte and ll is
- * the low byte.
- * \param address the C-string representation of the address
- */
- MacAddress (char const *address);
- ~MacAddress ();
-
- /**
- * \brief Comparison operation between MacAddresses
- * \param other The address against which to compare this one
- * \return True if they are equal, false otherwise.
- */
- bool IsEqual (MacAddress other) const;
- /**
- * \brief Print this MacAddress to a stream
- *
- * The format is colon seperated groups of two hexadecimal digits
- * \param os The output stream desired
- */
- void Print (std::ostream &os) const;
-
- /**
- * \return The length in bytes of this MacAddress
- */
- uint8_t GetLength() const;
- /**
- * \brief Copy routine to peek the contents of the MacAddress
- *
- * \param ad Output parameter which holds a copy of this MacAddress
- */
- void Peek (uint8_t ad[MAX_LEN]) const;
- /**
- * \brief Sets this MacAddress to a specific value
- * \param ad byte buffer to set the MacAddress to
- * \param len the length of the buffer
- */
- void Set (uint8_t const ad[MAX_LEN], uint8_t len);
-
- // Static methods/members
- /**
- *
- * Advance the global to the next available mac address.
- */
- static void AdvanceAddress();
- static uint8_t g_nextAddress[MAX_LEN];
-
-private:
- uint8_t m_address[MAX_LEN];
- uint8_t m_len;
-};
-
-bool operator == (MacAddress const&a, MacAddress const&b);
-bool operator != (MacAddress const&a, MacAddress const&b);
-bool operator < (MacAddress const&a, MacAddress const&b);
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address);
-
-}; // namespace ns3
-
-#endif /* MAC_ADDRESS_H */
--- a/src/node/net-device.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/net-device.cc Wed Sep 05 18:35:39 2007 +0100
@@ -35,7 +35,7 @@
const InterfaceId NetDevice::iid = MakeInterfaceId ("NetDevice", Object::iid);
-NetDevice::NetDevice(Ptr<Node> node, const MacAddress& addr) :
+NetDevice::NetDevice(Ptr<Node> node, const Address& addr) :
m_node (node),
m_name(""),
m_ifIndex (0),
@@ -53,7 +53,7 @@
NetDevice::~NetDevice ()
{}
-MacAddress
+Address
NetDevice::GetAddress (void) const
{
return m_address;
@@ -113,7 +113,7 @@
{
return m_isBroadcast;
}
-MacAddress const &
+Address const &
NetDevice::GetBroadcast (void) const
{
NS_ASSERT (m_isBroadcast);
@@ -121,7 +121,7 @@
}
void
-NetDevice::EnableBroadcast (MacAddress broadcast)
+NetDevice::EnableBroadcast (Address broadcast)
{
m_isBroadcast = true;
m_broadcast = broadcast;
@@ -171,7 +171,7 @@
// Receive packet from above
bool
-NetDevice::Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber)
+NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber)
{
if (m_isUp)
{
@@ -197,18 +197,19 @@
// Receive packets from below
bool
-NetDevice::ForwardUp(Packet& p, uint32_t param)
+NetDevice::ForwardUp(const Packet& p, uint16_t param, const Address &from)
{
bool retval = false;
- Packet packet = p;
- NS_DEBUG ("NetDevice::ForwardUp: UID is " << packet.GetUid()
+ NS_DEBUG ("NetDevice::ForwardUp: UID is " << p.GetUid()
<< " device is: " << GetName());
if (!m_receiveCallback.IsNull ())
{
- retval = m_receiveCallback (this, packet, param);
- } else {
+ retval = m_receiveCallback (this, p, param, from);
+ }
+ else
+ {
NS_DEBUG ("NetDevice::Receive call back is NULL");
}
@@ -248,7 +249,7 @@
}
void
-NetDevice::SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb)
+NetDevice::SetReceiveCallback (ReceiveCallback cb)
{
m_receiveCallback = cb;
}
--- a/src/node/net-device.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/net-device.h Wed Sep 05 18:35:39 2007 +0100
@@ -28,7 +28,7 @@
#include "ns3/packet.h"
#include "ns3/object.h"
#include "ns3/ptr.h"
-#include "mac-address.h"
+#include "address.h"
namespace ns3 {
@@ -79,9 +79,9 @@
Ptr<Channel> GetChannel (void) const;
/**
- * \return the current MacAddress of this interface.
+ * \return the current Address of this interface.
*/
- MacAddress GetAddress (void) const;
+ Address GetAddress (void) const;
/**
* \param mtu MTU value, in bytes, to set for the device
* \return whether the MTU value was within legal bounds
@@ -137,7 +137,7 @@
* Calling this method is invalid if IsBroadcast returns
* not true.
*/
- MacAddress const &GetBroadcast (void) const;
+ Address const &GetBroadcast (void) const;
/**
* \return value of m_isMulticast flag
*/
@@ -154,11 +154,11 @@
* is received.
*
* Called from higher layer to send packet into Network Device
- * to the specified destination MacAddress
+ * to the specified destination Address
*
* \return whether the Send operation succeeded
*/
- bool Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber);
+ bool Send(const Packet& p, const Address& dest, uint16_t protocolNumber);
/**
* \returns the node base class which contains this network
* interface.
@@ -178,22 +178,35 @@
bool NeedsArp (void) const;
/**
+ * \param device a pointer to the net device which is calling this callback
+ * \param packet the packet received
+ * \param protocol the 16 bit protocol number associated with this packet.
+ * This protocol number is expected to be the same protocol number
+ * given to the Send method by the user on the sender side.
+ * \param address the address of the sender
+ * \returns true if the callback could handle the packet successfully, false
+ * otherwise.
+ */
+ typedef Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t,const Address &> ReceiveCallback;
+
+ /**
* \param cb callback to invoke whenever a packet has been received and must
* be forwarded to the higher layers.
+ *
*/
- void SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb);
+ void SetReceiveCallback (ReceiveCallback cb);
protected:
/**
* \param node base class node pointer of device's node
* \param addr MAC address of this device.
*/
- NetDevice(Ptr<Node> node, const MacAddress& addr);
+ NetDevice(Ptr<Node> node, const Address& addr);
/**
* Enable broadcast support. This method should be
* called by subclasses from their constructor
*/
- void EnableBroadcast (MacAddress broadcast);
+ void EnableBroadcast (Address broadcast);
/**
* Set m_isBroadcast flag to false
*/
@@ -230,6 +243,7 @@
* \param p packet sent from below up to Network Device
* \param param Extra parameter extracted from header and needed by
* some protocols
+ * \param address the address of the sender of this packet.
* \returns true if the packet was forwarded successfully,
* false otherwise.
*
@@ -237,7 +251,7 @@
* forwards it to the higher layers by calling this method
* which is responsible for passing it up to the Rx callback.
*/
- bool ForwardUp (Packet& p, uint32_t param);
+ bool ForwardUp (const Packet& p, uint16_t param, const Address &address);
/**
@@ -248,8 +262,6 @@
*/
virtual void DoDispose (void);
- Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> m_receiveCallback;
-
private:
/**
* \param p packet to send
@@ -262,7 +274,7 @@
* method. When the link is Up, this method is invoked to ask
* subclasses to forward packets. Subclasses MUST override this method.
*/
- virtual bool SendTo (Packet& p, const MacAddress &dest, uint16_t protocolNumber) = 0;
+ virtual bool SendTo (const Packet& p, const Address &dest, uint16_t protocolNumber) = 0;
/**
* \returns true if this NetDevice needs the higher-layers
* to perform ARP over it, false otherwise.
@@ -289,14 +301,15 @@
Ptr<Node> m_node;
std::string m_name;
uint16_t m_ifIndex;
- MacAddress m_address;
- MacAddress m_broadcast;
+ Address m_address;
+ Address m_broadcast;
uint16_t m_mtu;
bool m_isUp;
bool m_isBroadcast;
bool m_isMulticast;
bool m_isPointToPoint;
Callback<void> m_linkChangeCallback;
+ ReceiveCallback m_receiveCallback;
};
}; // namespace ns3
--- a/src/node/node-list.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node-list.cc Wed Sep 05 18:35:39 2007 +0100
@@ -40,6 +40,30 @@
namespace ns3 {
+NodeListIndex::NodeListIndex ()
+ : m_index (0)
+{}
+NodeListIndex::NodeListIndex (uint32_t index)
+ : m_index (index)
+{}
+void
+NodeListIndex::Print (std::ostream &os)
+{
+ os << "nodeid=" << m_index;
+}
+uint16_t
+NodeListIndex::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<NodeListIndex> ("NodeListIndex");
+ return uid;
+}
+uint32_t
+NodeListIndex::Get (void) const
+{
+ return m_index;
+}
+
+
/**
* The private node list used by the static-based API
*/
@@ -53,7 +77,6 @@
NodeList::Iterator Begin (void);
NodeList::Iterator End (void);
TraceResolver *CreateTraceResolver (TraceContext const &context);
- Node *PeekNode (uint32_t n);
Ptr<Node> GetNode (uint32_t n);
uint32_t GetNNodes (void);
@@ -99,11 +122,6 @@
{
return m_nodes.size ();
}
-Node *
-NodeListPriv::PeekNode (uint32_t n)
-{
- return PeekPointer (m_nodes[n]);
-}
Ptr<Node>
NodeListPriv::GetNode (uint32_t n)
@@ -115,11 +133,11 @@
TraceResolver *
NodeListPriv::CreateTraceResolver (TraceContext const &context)
{
- ArrayTraceResolver<Node> *resolver =
- new ArrayTraceResolver<Node>
+ ArrayTraceResolver<Ptr<Node>, NodeListIndex> *resolver =
+ new ArrayTraceResolver<Ptr<Node>, NodeListIndex>
(context,
MakeCallback (&NodeListPriv::GetNNodes, this),
- MakeCallback (&NodeListPriv::PeekNode, this));
+ MakeCallback (&NodeListPriv::GetNode, this));
return resolver;
}
--- a/src/node/node-list.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node-list.h Wed Sep 05 18:35:39 2007 +0100
@@ -23,7 +23,7 @@
#define NODE_LIST_H
#include <vector>
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
#include "ns3/ptr.h"
namespace ns3 {
@@ -32,6 +32,19 @@
class TraceResolver;
class TraceContext;
+class NodeListIndex : public TraceContextElement
+{
+public:
+ NodeListIndex ();
+ NodeListIndex (uint32_t index);
+ void Print (std::ostream &os);
+ static uint16_t GetUid (void);
+ uint32_t Get (void) const;
+private:
+ uint32_t m_index;
+};
+
+
/**
* \brief the list of simulation nodes.
*
@@ -40,7 +53,6 @@
class NodeList
{
public:
- typedef ArrayTraceResolver<Node>::Index NodeIndex;
typedef std::vector< Ptr<Node> >::iterator Iterator;
/**
--- a/src/node/node.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node.cc Wed Sep 05 18:35:39 2007 +0100
@@ -1,51 +1,82 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Implement the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "node.h"
#include "node-list.h"
#include "net-device.h"
#include "application.h"
+#include "packet-socket-factory.h"
#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "ns3/array-trace-resolver.h"
namespace ns3{
const InterfaceId Node::iid = MakeInterfaceId ("Node", Object::iid);
+NodeNetDeviceIndex::NodeNetDeviceIndex ()
+ : m_index (0)
+{}
+NodeNetDeviceIndex::NodeNetDeviceIndex (uint32_t index)
+ : m_index (index)
+{}
+uint32_t
+NodeNetDeviceIndex::Get (void) const
+{
+ return m_index;
+}
+void
+NodeNetDeviceIndex::Print (std::ostream &os) const
+{
+ os << "device=" << m_index;
+}
+uint16_t
+NodeNetDeviceIndex::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<NodeNetDeviceIndex> ("NodeNetDeviceIndex");
+ return uid;
+}
+
+
+
Node::Node()
: m_id(0),
m_sid(0)
{
- SetInterfaceId (Node::iid);
- m_id = NodeList::Add (this);
+ Construct ();
}
Node::Node(uint32_t sid)
: m_id(0),
m_sid(sid)
{
+ Construct ();
+}
+
+void
+Node::Construct (void)
+{
SetInterfaceId (Node::iid);
m_id = NodeList::Add (this);
+ Ptr<PacketSocketFactory> socketFactory = Create<PacketSocketFactory> ();
+ AddInterface (socketFactory);
}
Node::~Node ()
@@ -54,7 +85,9 @@
TraceResolver *
Node::CreateTraceResolver (TraceContext const &context)
{
- return DoCreateTraceResolver (context);
+ CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+ DoFillTraceResolver (*resolver);
+ return resolver;
}
uint32_t
@@ -74,8 +107,9 @@
{
uint32_t index = m_devices.size ();
m_devices.push_back (device);
- DoAddDevice (device);
device->SetIfIndex(index);
+ device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this));
+ NotifyDeviceAdded (device);
return index;
}
Ptr<NetDevice>
@@ -107,8 +141,27 @@
return m_applications.size ();
}
+TraceResolver *
+Node::CreateDevicesTraceResolver (const TraceContext &context)
+{
+ ArrayTraceResolver<Ptr<NetDevice>,NodeNetDeviceIndex> *resolver =
+ new ArrayTraceResolver<Ptr<NetDevice>,NodeNetDeviceIndex>
+ (context,
+ MakeCallback (&Node::GetNDevices, this),
+ MakeCallback (&Node::GetDevice, this));
+
+ return resolver;
+}
-void Node::DoDispose()
+void
+Node::DoFillTraceResolver (CompositeTraceResolver &resolver)
+{
+ resolver.Add ("devices",
+ MakeCallback (&Node::CreateDevicesTraceResolver, this));
+}
+
+void
+Node::DoDispose()
{
for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
i != m_devices.end (); i++)
@@ -129,4 +182,56 @@
Object::DoDispose ();
}
+void
+Node::NotifyDeviceAdded (Ptr<NetDevice> device)
+{}
+
+void
+Node::RegisterProtocolHandler (ProtocolHandler handler,
+ uint16_t protocolType,
+ Ptr<NetDevice> device)
+{
+ struct Node::ProtocolHandlerEntry entry;
+ entry.handler = handler;
+ entry.protocol = protocolType;
+ entry.device = device;
+ m_handlers.push_back (entry);
+}
+
+void
+Node::UnregisterProtocolHandler (ProtocolHandler handler)
+{
+ for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+ i != m_handlers.end (); i++)
+ {
+ if (i->handler.IsEqual (handler))
+ {
+ m_handlers.erase (i);
+ break;
+ }
+ }
+}
+
+bool
+Node::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from)
+{
+ bool found = false;
+ for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+ i != m_handlers.end (); i++)
+ {
+ if (i->device == 0 ||
+ (i->device != 0 && i->device == device))
+ {
+ if (i->protocol == 0 ||
+ i->protocol == protocol)
+ {
+ i->handler (device, packet, protocol, from);
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
}//namespace ns3
--- a/src/node/node.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node.h Wed Sep 05 18:35:39 2007 +0100
@@ -1,33 +1,31 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Define the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-#ifndef I_NODE_H
-#define I_NODE_H
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef NODE_H
+#define NODE_H
#include <vector>
#include "ns3/object.h"
+#include "ns3/callback.h"
+#include "ns3/trace-context-element.h"
namespace ns3 {
@@ -35,6 +33,21 @@
class TraceResolver;
class NetDevice;
class Application;
+class Packet;
+class Address;
+class CompositeTraceResolver;
+
+class NodeNetDeviceIndex : public TraceContextElement
+{
+public:
+ NodeNetDeviceIndex ();
+ NodeNetDeviceIndex (uint32_t index);
+ uint32_t Get (void) const;
+ void Print (std::ostream &os) const;
+ static uint16_t GetUid (void);
+private:
+ uint32_t m_index;
+};
/**
* \brief A network Node.
@@ -58,6 +71,17 @@
public:
static const InterfaceId iid;
+ /**
+ * Must be invoked by subclasses only.
+ */
+ Node();
+ /**
+ * \param systemId a unique integer used for parallel simulations.
+ *
+ * Must be invoked by subclasses only.
+ */
+ Node(uint32_t systemId);
+
virtual ~Node();
/**
@@ -93,11 +117,15 @@
* Associate this device to this node.
* This method is called automatically from NetDevice::NetDevice
* so the user has little reason to call this method himself.
+ * The index returned is always non-zero.
*/
uint32_t AddDevice (Ptr<NetDevice> device);
/**
* \param index the index of the requested NetDevice
* \returns the requested NetDevice associated to this Node.
+ *
+ * The indexes used by the GetDevice method start at one and
+ * end at GetNDevices ()
*/
Ptr<NetDevice> GetDevice (uint32_t index) const;
/**
@@ -127,32 +155,52 @@
*/
uint32_t GetNApplications (void) const;
-protected:
/**
- * Must be invoked by subclasses only.
+ * A protocol handler
*/
- Node();
+ typedef Callback<void,Ptr<NetDevice>, const Packet &,uint16_t,const Address &> ProtocolHandler;
/**
- * \param systemId a unique integer used for parallel simulations.
+ * \param handler the handler to register
+ * \param protocolType the type of protocol this handler is
+ * interested in. This protocol type is a so-called
+ * EtherType, as registered here:
+ * http://standards.ieee.org/regauth/ethertype/eth.txt
+ * the value zero is interpreted as matching all
+ * protocols.
+ * \param device the device attached to this handler. If the
+ * value is zero, the handler is attached to all
+ * devices on this node.
+ */
+ void RegisterProtocolHandler (ProtocolHandler handler,
+ uint16_t protocolType,
+ Ptr<NetDevice> device);
+ /**
+ * \param handler the handler to unregister
*
- * Must be invoked by subclasses only.
+ * After this call returns, the input handler will never
+ * be invoked anymore.
*/
- Node(uint32_t systemId);
+ void UnregisterProtocolHandler (ProtocolHandler handler);
+
+protected:
/**
* The dispose method. Subclasses must override this method
* and must chain up to it by calling Node::DoDispose at the
* end of their own DoDispose method.
*/
virtual void DoDispose (void);
+ /**
+ * \param resolver the resolver to store trace sources in.
+ *
+ * If a subclass wants to add new traces to a Node, it needs
+ * to override this method and record the new trace sources
+ * in the input resolver. Subclasses also _must_ chain up to
+ * their parent's DoFillTraceResolver method prior
+ * to recording they own trace sources.
+ */
+ virtual void DoFillTraceResolver (CompositeTraceResolver &resolver);
private:
/**
- * \param context the trace context
- * \returns a trace resolver to the user. The user must delete it.
- *
- * Subclasses must implement this method.
- */
- virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
- /**
* \param device the device added to this Node.
*
* This method is invoked whenever a user calls Node::AddDevice.
@@ -160,14 +208,26 @@
* at this point to setup the node's receive function for
* the NetDevice packets.
*/
- virtual void DoAddDevice (Ptr<NetDevice> device) = 0;
+ virtual void NotifyDeviceAdded (Ptr<NetDevice> device);
+
+ bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from);
+ void Construct (void);
+ TraceResolver *CreateDevicesTraceResolver (const TraceContext &context);
+ struct ProtocolHandlerEntry {
+ ProtocolHandler handler;
+ uint16_t protocol;
+ Ptr<NetDevice> device;
+ };
+ typedef std::vector<struct Node::ProtocolHandlerEntry> ProtocolHandlerList;
uint32_t m_id; // Node id for this node
uint32_t m_sid; // System id for this node
std::vector<Ptr<NetDevice> > m_devices;
std::vector<Ptr<Application> > m_applications;
+ ProtocolHandlerList m_handlers;
};
} //namespace ns3
-#endif /* I_NODE_H */
+#endif /* NODE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 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 "packet-socket-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+PacketSocketAddress::PacketSocketAddress ()
+{}
+void
+PacketSocketAddress::SetProtocol (uint16_t protocol)
+{
+ m_protocol = protocol;
+}
+void
+PacketSocketAddress::SetAllDevices (void)
+{
+ m_isSingleDevice = false;
+ m_device = 0;
+}
+void
+PacketSocketAddress::SetSingleDevice (uint32_t index)
+{
+ m_isSingleDevice = true;
+ m_device = index;
+}
+void
+PacketSocketAddress::SetPhysicalAddress (const Address address)
+{
+ m_address = address;
+}
+
+uint16_t
+PacketSocketAddress::GetProtocol (void) const
+{
+ return m_protocol;
+}
+bool
+PacketSocketAddress::IsSingleDevice (void) const
+{
+ return m_isSingleDevice;
+}
+uint32_t
+PacketSocketAddress::GetSingleDevice (void) const
+{
+ return m_device;
+}
+Address
+PacketSocketAddress::GetPhysicalAddress (void) const
+{
+ return m_address;
+}
+
+PacketSocketAddress::operator Address () const
+{
+ return ConvertTo ();
+}
+
+Address
+PacketSocketAddress::ConvertTo (void) const
+{
+ Address address;
+ uint8_t buffer[Address::MAX_SIZE];
+ buffer[0] = m_protocol & 0xff;
+ buffer[1] = (m_protocol >> 8) & 0xff;
+ buffer[2] = (m_device >> 24) & 0xff;
+ buffer[3] = (m_device >> 16) & 0xff;
+ buffer[4] = (m_device >> 8) & 0xff;
+ buffer[5] = (m_device >> 0) & 0xff;
+ buffer[6] = m_isSingleDevice?1:0;
+ uint32_t copied = m_address.CopyAllTo (buffer + 7, Address::MAX_SIZE - 7);
+ return Address (GetType (), buffer, 7 + copied);
+}
+PacketSocketAddress
+PacketSocketAddress::ConvertFrom (const Address &address)
+{
+ NS_ASSERT (IsMatchingType (address));
+ uint8_t buffer[Address::MAX_SIZE];
+ address.CopyTo (buffer);
+ uint16_t protocol = buffer[0] | (buffer[1] << 8);
+ uint32_t device = 0;
+ device |= buffer[2];
+ device <<= 8;
+ device |= buffer[3];
+ device <<= 8;
+ device |= buffer[4];
+ device <<= 8;
+ device |= buffer[5];
+ bool isSingleDevice = (buffer[6] == 1)?true:false;
+ Address physical;
+ physical.CopyAllFrom (buffer + 7, Address::MAX_SIZE - 7);
+ PacketSocketAddress ad;
+ ad.SetProtocol (protocol);
+ if (isSingleDevice)
+ {
+ ad.SetSingleDevice (device);
+ }
+ else
+ {
+ ad.SetAllDevices ();
+ }
+ ad.SetPhysicalAddress (physical);
+ return ad;
+}
+bool
+PacketSocketAddress::IsMatchingType (const Address &address)
+{
+ return address.IsMatchingType (GetType ());
+}
+uint8_t
+PacketSocketAddress::GetType (void)
+{
+ static uint8_t type = Address::Register ();
+ return type;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 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 PACKET_SOCKET_ADDRESS_H
+#define PACKET_SOCKET_ADDRESS_H
+
+#include "ns3/ptr.h"
+#include "address.h"
+#include "eui48-address.h"
+#include "eui64-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+class NetDevice;
+
+class PacketSocketAddress
+{
+ public:
+ PacketSocketAddress ();
+ void SetProtocol (uint16_t protocol);
+
+ void SetAllDevices (void);
+ void SetSingleDevice (uint32_t device);
+ void SetPhysicalAddress (const Address address);
+
+ uint16_t GetProtocol (void) const;
+ uint32_t GetSingleDevice (void) const;
+ bool IsSingleDevice (void) const;
+ Address GetPhysicalAddress (void) const;
+
+ /**
+ * \returns a new Address instance
+ *
+ * Convert an instance of this class to a polymorphic Address instance.
+ */
+ operator Address () const;
+ /**
+ * \param address a polymorphic address
+ *
+ * Convert a polymorphic address to an Eui48Address instance.
+ * The conversion performs a type check.
+ */
+ static PacketSocketAddress 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;
+ uint16_t m_protocol;
+ bool m_isSingleDevice;
+ uint32_t m_device;
+ Address m_address;
+};
+
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_ADDRESS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#include "packet-socket-factory.h"
+#include "node.h"
+
+namespace ns3 {
+
+const InterfaceId PacketSocketFactory::iid = MakeInterfaceId ("Packet",
+ SocketFactory::iid);
+
+PacketSocketFactory::PacketSocketFactory ()
+{
+ SetInterfaceId (PacketSocketFactory::iid);
+}
+
+Ptr<Socket> PacketSocketFactory::CreateSocket (void)
+{
+ Ptr<Node> node = QueryInterface<Node> (Node::iid);
+ Ptr<PacketSocket> socket = Create<PacketSocket> (node);
+ return socket;
+}
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,52 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#ifndef PACKET_SOCKET_FACTORY_H
+#define PACKET_SOCKET_FACTORY_H
+
+#include "socket-factory.h"
+#include "packet-socket.h"
+
+namespace ns3 {
+
+class Socket;
+
+/**
+ * This can be used as an interface in a node in order for the node to
+ * generate PacketSockets that can connect to net devices.
+ */
+class PacketSocketFactory : public SocketFactory
+{
+public:
+ static const InterfaceId iid; /// Interface identifier
+
+ PacketSocketFactory ();
+
+ /**
+ * Creates a PacketSocket and returns a pointer to it.
+ *
+ * \return a pointer to the created socket
+ */
+ virtual Ptr<Socket> CreateSocket (void);
+};
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_FACTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,285 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, 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
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "packet-socket.h"
+#include "packet-socket-address.h"
+#include "ns3/debug.h"
+#include "ns3/node.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("PacketSocket");
+
+namespace ns3 {
+
+PacketSocket::PacketSocket (Ptr<Node> node)
+ : m_node (node)
+{
+ Init();
+}
+
+void
+PacketSocket::Init()
+{
+ m_state = STATE_OPEN;
+ m_shutdownSend = false;
+ m_shutdownRecv = false;
+ m_errno = ERROR_NOTERROR;
+}
+
+PacketSocket::~PacketSocket ()
+{}
+
+void
+PacketSocket::DoDispose (void)
+{
+ m_device = 0;
+}
+
+enum Socket::SocketErrno
+PacketSocket::GetErrno (void) const
+{
+ return m_errno;
+}
+
+Ptr<Node>
+PacketSocket::GetNode (void) const
+{
+ return m_node;
+}
+
+int
+PacketSocket::Bind (void)
+{
+ PacketSocketAddress address;
+ address.SetProtocol (0);
+ address.SetAllDevices ();
+ return DoBind (address);
+}
+int
+PacketSocket::Bind (const Address &address)
+{
+ if (!PacketSocketAddress::IsMatchingType (address))
+ {
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (address);
+ return DoBind (ad);
+}
+
+int
+PacketSocket::DoBind (const PacketSocketAddress &address)
+{
+ if (m_state == STATE_BOUND ||
+ m_state == STATE_CONNECTED)
+ {
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ Ptr<NetDevice> dev ;
+ if (address.IsSingleDevice ())
+ {
+ dev = 0;
+ }
+ else
+ {
+ m_node->GetDevice (address.GetSingleDevice ());
+ }
+ m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
+ address.GetProtocol (), dev);
+ m_state = STATE_BOUND;
+ m_protocol = address.GetProtocol ();
+ m_isSingleDevice = address.IsSingleDevice ();
+ m_device = address.GetSingleDevice ();
+ return 0;
+}
+
+int
+PacketSocket::ShutdownSend (void)
+{
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ m_shutdownSend = true;
+ return 0;
+}
+int
+PacketSocket::ShutdownRecv (void)
+{
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ m_shutdownRecv = false;
+ return 0;
+}
+int
+PacketSocket::Close(void)
+{
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ m_state = STATE_CLOSED;
+ NotifyCloseCompleted ();
+ return 0;
+}
+
+int
+PacketSocket::Connect(const Address &ad)
+{
+ PacketSocketAddress address;
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ goto error;
+ }
+ if (m_state == STATE_OPEN)
+ {
+ // connect should happen _after_ bind.
+ m_errno = ERROR_INVAL; // generic error condition.
+ goto error;
+ }
+ if (m_state == STATE_CONNECTED)
+ {
+ m_errno = ERROR_ISCONN;
+ goto error;
+ }
+ if (!PacketSocketAddress::IsMatchingType (ad))
+ {
+ m_errno = ERROR_AFNOSUPPORT;
+ goto error;
+ }
+ m_destAddr = ad;
+ m_state = STATE_CONNECTED;
+ NotifyConnectionSucceeded ();
+ return 0;
+ error:
+ NotifyConnectionFailed ();
+ return -1;
+}
+
+int
+PacketSocket::Send (const Packet &p)
+{
+ if (m_state == STATE_OPEN ||
+ m_state == STATE_BOUND)
+ {
+ m_errno = ERROR_NOTCONN;
+ return -1;
+ }
+ return SendTo (m_destAddr, p);
+}
+
+int
+PacketSocket::SendTo(const Address &address, const Packet &p)
+{
+ PacketSocketAddress ad;
+ if (m_state == STATE_CLOSED)
+ {
+ m_errno = ERROR_BADF;
+ return -1;
+ }
+ if (m_state == STATE_OPEN)
+ {
+ // XXX should return another error here.
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ if (m_shutdownSend)
+ {
+ m_errno = ERROR_SHUTDOWN;
+ return -1;
+ }
+ if (!PacketSocketAddress::IsMatchingType (address))
+ {
+ m_errno = ERROR_AFNOSUPPORT;
+ return -1;
+ }
+ ad = PacketSocketAddress::ConvertFrom (address);
+
+ bool error = false;
+ Address dest = ad.GetPhysicalAddress ();
+ if (ad.IsSingleDevice ())
+ {
+ Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
+ if (!device->Send (p, dest, ad.GetProtocol ()))
+ {
+ error = true;
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
+ {
+ Ptr<NetDevice> device = m_node->GetDevice (i);
+ if (!device->Send (p, dest, ad.GetProtocol ()))
+ {
+ error = true;
+ }
+ }
+ }
+ if (!error)
+ {
+ NotifyDataSent (p.GetSize ());
+ }
+
+ if (error)
+ {
+ m_errno = ERROR_INVAL;
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void
+PacketSocket::ForwardUp (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from)
+{
+ if (m_shutdownRecv)
+ {
+ return;
+ }
+
+ Packet p = packet;
+
+ PacketSocketAddress address;
+ address.SetPhysicalAddress (from);
+ address.SetSingleDevice (device->GetIfIndex ());
+ address.SetProtocol (protocol);
+
+ NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid()
+ << " PacketSocket " << this);
+ NotifyDataReceived (p, address);
+}
+
+}//namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, 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
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>,
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_SOCKET_H
+#define PACKET_SOCKET_H
+
+#include <stdint.h>
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "ns3/socket.h"
+
+namespace ns3 {
+
+class Node;
+class Packet;
+class NetDevice;
+class PacketSocketAddress;
+
+/**
+ * \brief A PacketSocket is a link between an application and a net device.
+ *
+ * A PacketSocket can be used to connect an application to a net
+ * device. The application provides the buffers of data, the socket
+ * conserts them to a raw packet and the net device then adds the
+ * protocol specific headers and trailers. 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
+ * PacketSocketAddress. If none are provided, Bind uses
+ * zero for both, which means that the socket is bound
+ * to all protocols on all devices on the node.
+ *
+ * - Connect: uses only the protocol, device and "physical address"
+ * field of the PacketSocketAddress. It is used to set the default
+ * destination address for outgoing packets.
+ *
+ * - Send: send the input packet to the underlying NetDevices
+ * with the default destination address. The socket must
+ * be bound and connected.
+ *
+ * - SendTo: uses the protocol, device, and "physical address"
+ * fields of the PacketSocketAddress. The device value is
+ * used to specialize the packet transmission to a single
+ * device, the protocol value specifies the protocol of this
+ * packet only and the "physical address" field is used to override the
+ * default destination address. The socket must be bound.
+ *
+ * - Recv: The address represents the address of the packer originator.
+ * The fields "physical address", device, and protocol are filled.
+ *
+ * - Accept: not allowed
+ */
+class PacketSocket : public Socket
+{
+public:
+ PacketSocket (Ptr<Node> node);
+ virtual ~PacketSocket ();
+
+ 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 Send (const Packet &p);
+ virtual int SendTo(const Address &address,const Packet &p);
+
+
+private:
+
+private:
+ void Init (void);
+ void ForwardUp (Ptr<NetDevice> device, const Packet &packet,
+ uint16_t protocol, const Address &from);
+ int DoBind (const PacketSocketAddress &address);
+ virtual void DoDispose (void);
+
+ enum State {
+ STATE_OPEN,
+ STATE_BOUND, // open and bound
+ STATE_CONNECTED, // open, bound and connected
+ STATE_CLOSED
+ };
+ Ptr<Node> m_node;
+ enum SocketErrno m_errno;
+ bool m_shutdownSend;
+ bool m_shutdownRecv;
+ enum State m_state;
+ uint16_t m_protocol;
+ bool m_isSingleDevice;
+ uint32_t m_device;
+ Address m_destAddr; /// Default destination address
+};
+
+}//namespace ns3
+
+#endif /* PACKET_SOCKET_H */
+
+
--- a/src/node/queue.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/queue.cc Wed Sep 05 18:35:39 2007 +0100
@@ -31,6 +31,52 @@
static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue",
Queue::iid, "DropTailQueue");
+
+uint16_t
+QueueTraceType::GetUid (void)
+{
+ static uint16_t uid = AllocateUid<QueueTraceType> ("QueueTraceType");
+ return uid;
+}
+QueueTraceType::QueueTraceType ()
+ : m_type (QueueTraceType::ENQUEUE)
+{}
+QueueTraceType::QueueTraceType (enum Type type)
+ : m_type (type)
+{}
+bool
+QueueTraceType::IsEnqueue (void) const
+{
+ return m_type == ENQUEUE;
+}
+bool
+QueueTraceType::IsDequeue (void) const
+{
+ return m_type == DEQUEUE;
+}
+bool
+QueueTraceType::IsDrop (void) const
+{
+ return m_type == DROP;
+}
+
+void
+QueueTraceType::Print (std::ostream &os) const
+{
+ os << "queue-";
+ switch (m_type) {
+ case QueueTraceType::ENQUEUE:
+ os << "enqueue";
+ break;
+ case QueueTraceType::DEQUEUE:
+ os << "dequeue";
+ break;
+ case QueueTraceType::DROP:
+ os << "drop";
+ break;
+ }
+}
+
Queue::Queue() :
m_nBytes(0),
m_nTotalReceivedBytes(0),
@@ -52,9 +98,9 @@
Queue::CreateTraceResolver (TraceContext const &context)
{
CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
- resolver->Add ("enqueue", m_traceEnqueue, Queue::ENQUEUE);
- resolver->Add ("dequeue", m_traceDequeue, Queue::DEQUEUE);
- resolver->Add ("drop", m_traceDrop, Queue::DROP);
+ resolver->Add ("enqueue", m_traceEnqueue, QueueTraceType (QueueTraceType::ENQUEUE));
+ resolver->Add ("dequeue", m_traceDequeue, QueueTraceType (QueueTraceType::DEQUEUE));
+ resolver->Add ("drop", m_traceDrop, QueueTraceType (QueueTraceType::DROP));
return resolver;
}
--- a/src/node/queue.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/queue.h Wed Sep 05 18:35:39 2007 +0100
@@ -31,11 +31,32 @@
#include "ns3/object.h"
#include "ns3/callback-trace-source.h"
#include "ns3/trace-resolver.h"
+#include "ns3/trace-context-element.h"
namespace ns3 {
class StringEnumDefaultValue;
+class QueueTraceType : public TraceContextElement
+{
+public:
+ enum Type {
+ ENQUEUE,
+ DEQUEUE,
+ DROP
+ };
+ static uint16_t GetUid (void);
+ QueueTraceType ();
+ QueueTraceType (enum Type type);
+ bool IsEnqueue (void) const;
+ bool IsDequeue (void) const;
+ bool IsDrop (void) const;
+ void Print (std::ostream &os) const;
+private:
+ enum Type m_type;
+};
+
+
/**
* \brief Abstract base class for packet Queues
*
@@ -46,11 +67,6 @@
public:
static const InterfaceId iid;
- enum TraceType {
- ENQUEUE,
- DEQUEUE,
- DROP,
- };
Queue ();
virtual ~Queue ();
--- a/src/node/socket.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/socket.cc Wed Sep 05 18:35:39 2007 +0100
@@ -1,4 +1,26 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ * 2007 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#include "socket.h"
+#include "ns3/packet.h"
namespace ns3 {
@@ -6,76 +28,117 @@
{}
void
-Socket::Close(Callback<void, Ptr<Socket> > closeCompleted)
+Socket::SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted)
+{
+ m_closeCompleted = closeCompleted;
+}
+void
+Socket::SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
+ Callback<void, Ptr<Socket> > connectionFailed,
+ Callback<void, Ptr<Socket> > halfClose)
{
- DoClose (closeCompleted);
+ m_connectionSucceeded = connectionSucceeded;
+ m_connectionFailed = connectionFailed;
+ m_halfClose = halfClose;
+}
+void
+Socket::SetAcceptCallback (Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+ Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+ Callback<void, Ptr<Socket> > closeRequested)
+{
+ m_connectionRequest = connectionRequest;
+ m_newConnectionCreated = newConnectionCreated;
+ m_closeRequested = closeRequested;
+}
+void
+Socket::SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent)
+{
+ m_dataSent = dataSent;
+}
+void
+Socket::SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData)
+{
+ m_receivedData = receivedData;
}
void
-Socket::Connect(const Ipv4Address & address,
- uint16_t portNumber,
- Callback<void, Ptr<Socket> > connectionSucceeded,
- Callback<void, Ptr<Socket> > connectionFailed,
- Callback<void, Ptr<Socket> > halfClose)
+Socket::NotifyCloseCompleted (void)
{
- DoConnect (address, portNumber, connectionSucceeded, connectionFailed, halfClose);
-}
-int
-Socket::Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- Callback<void, Ptr<Socket> > closeRequested)
-{
- return DoAccept (connectionRequest, newConnectionCreated, closeRequested);
+ if (!m_closeCompleted.IsNull ())
+ {
+ m_closeCompleted (this);
+ }
}
-int
-Socket::Send (const uint8_t* buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent)
+void
+Socket::NotifyConnectionSucceeded (void)
{
- return DoSend (buffer, size, dataSent);
+ if (!m_connectionSucceeded.IsNull ())
+ {
+ m_connectionSucceeded (this);
+ }
}
-int
-Socket::SendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent)
+void
+Socket::NotifyConnectionFailed (void)
{
- return DoSendTo (address, port, buffer, size, dataSent);
+ if (!m_connectionFailed.IsNull ())
+ {
+ m_connectionFailed (this);
+ }
}
void
-Socket::Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
+Socket::NotifyHalfClose (void)
+{
+ if (!m_halfClose.IsNull ())
+ {
+ m_halfClose (this);
+ }
+}
+bool
+Socket::NotifyConnectionRequest (const Address &from)
{
- DoRecv (callback);
+ if (!m_connectionRequest.IsNull ())
+ {
+ return m_connectionRequest (this, from);
+ }
+ else
+ {
+ // refuse all incomming connections by default.
+ return false;
+ }
}
void
-Socket::RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
+Socket::NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from)
+{
+ if (!m_newConnectionCreated.IsNull ())
+ {
+ m_newConnectionCreated (socket, from);
+ }
+}
+void
+Socket::NotifyCloseRequested (void)
{
- DoRecvDummy (callback);
+ if (!m_closeRequested.IsNull ())
+ {
+ m_closeRequested (this);
+ }
+}
+void
+Socket::NotifyDataSent (uint32_t size)
+{
+ if (!m_dataSent.IsNull ())
+ {
+ m_dataSent (this, size);
+ }
+}
+void
+Socket::NotifyDataReceived (const Packet &p, const Address &from)
+{
+ if (!m_receivedData.IsNull ())
+ {
+ m_receivedData (this, p, from);
+ }
}
-bool
-Socket::RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port)
-{
- return false;
-}
-void
-Socket::DummyCallbackVoidSocket (Ptr<Socket> socket)
-{}
-void
-Socket::DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t)
-{}
-void
-Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t)
-{}
-void
-Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t,
- const Ipv4Address &, uint16_t)
-{}
-void
-Socket::DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t)
-{}
-
}//namespace ns3
--- a/src/node/socket.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/socket.h Wed Sep 05 18:35:39 2007 +0100
@@ -1,42 +1,44 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation;
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// Author: George F. Riley<riley@ece.gatech.edu>
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ * 2007 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include "ns3/callback.h"
#include "ns3/ptr.h"
-#include "ipv4-address.h"
#include "ns3/object.h"
+#include "address.h"
#include <stdint.h>
namespace ns3 {
class Node;
+class Packet;
/**
* \brief Define a Socket API based on the BSD Socket API.
*
* Contrary to the original BSD socket API, this API is asynchronous:
- * it does not contain blocking calls. This API also does not use
- * the dreaded BSD sockaddr_t type. Other than that, it tries to stick
+ * it does not contain blocking calls. Other than that, it tries to stick
* to the BSD API to make it easier those who know the BSD API to use
* this API.
*/
@@ -53,6 +55,9 @@
ERROR_AGAIN,
ERROR_SHUTDOWN,
ERROR_OPNOTSUPP,
+ ERROR_AFNOSUPPORT,
+ ERROR_INVAL,
+ ERROR_BADF,
SOCKET_ERRNO_LAST
};
@@ -68,53 +73,77 @@
*/
virtual Ptr<Node> GetNode (void) const = 0;
+ /**
+ * \param closeCompleted Callback invoked when the close operation is
+ * completed.
+ */
+ void SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted);
+
+ /**
+ * \param connectionSucceeded this callback is invoked when the connection request
+ * initiated by the user is successfully completed. The callback is passed
+ * back a pointer to the same socket object.
+ * \param connectionFailed this callback is invoked when the connection request
+ * initiated by the user is unsuccessfully completed. The callback is passed
+ * back a pointer to the same socket object.
+ * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
+ * other side closes the connection ? Or when I call Close ?
+ */
+ void SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
+ Callback<void, Ptr<Socket> > connectionFailed,
+ Callback<void, Ptr<Socket> > halfClose);
+ /**
+ * \brief Accept connection requests from remote hosts
+ * \param connectionRequest Callback for connection request from peer.
+ * This user callback is passed a pointer to this socket, the
+ * ip address and the port number of the connection originator.
+ * This callback must return true to accept the incoming connection,
+ * false otherwise. If the connection is accepted, the
+ * "newConnectionCreated" callback will be invoked later to give access
+ * to the user to the socket created to match this new connection. If the
+ * user does not explicitely specify this callback, all incoming
+ * connections will be refused.
+ * \param newConnectionCreated Callback for new connection: when a new
+ * is accepted, it is created and the corresponding socket is passed
+ * back to the user through this callback. This user callback is passed
+ * a pointer to the new socket, and the ip address and port number
+ * of the connection originator.
+ * \param closeRequested Callback for connection close request from peer.
+ * XXX: when is this callback invoked ?
+ */
+ void SetAcceptCallback (Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+ Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+ Callback<void, Ptr<Socket> > closeRequested);
+ void SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent);
+ /**
+ * \brief Receive data
+ * \param receivedData Invoked whenever new data is received.
+ *
+ */
+ void SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData);
+
/**
- * Allocate a free port number and
- * bind this socket to this port number on all
- * interfaces of this system.
+ * \param address the address to try to allocate
+ * \returns 0 on success, -1 on failure.
+ *
+ * Allocate a local endpoint for this socket.
+ */
+ virtual int Bind (const Address &address) = 0;
+
+ /**
+ * Allocate a local endpoint for this socket.
*
* \returns 0 on success, -1 on failure.
*/
- virtual int Bind (void) = 0;
-
- /**
- * Allocate a free port number and
- * bind this socket to this port number on the
- * specified interface.
- *
- * \param address address of interface to bind to.
- * \returns 0 on success, -1 on failure.
- */
- virtual int Bind (Ipv4Address address) = 0;
-
- /**
- * Bind this socket to this port number
- * on all interfaces of this system.
- *
- * \param port port to bind to on all interfaces
- * \returns 0 on success, -1 on failure.
- */
- virtual int Bind (uint16_t port) = 0;
-
- /**
- * Bind this socket to this port number
- * on the interface specified by address.
- *
- * \param address address of interface to bind to.
- * \param port port to bind to on specified interface
- * \returns 0 on success, -1 on failure.
- */
- virtual int Bind (Ipv4Address address, uint16_t port) = 0;
+ virtual int Bind () = 0;
/**
* \brief Close a socket.
- * \param closeCompleted Callback invoked when the close operation is
- * completed.
*
* After the Close call, the socket is no longer valid, and cannot
* safely be used for subsequent operations.
*/
- void Close(Callback<void, Ptr<Socket> > closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket));
+ virtual int Close(void) = 0;
/**
* \returns zero on success, -1 on failure.
@@ -134,127 +163,47 @@
/**
* \brief Initiate a connection to a remote host
- * \param address IP Address of remote.
- * \param portNumber Port number of remote
- * \param connectionSucceeded this callback is invoked when the connection request
- * initiated by the user is successfully completed. The callback is passed
- * back a pointer to the same socket object.
- * \param connectionFailed this callback is invoked when the connection request
- * initiated by the user is unsuccessfully completed. The callback is passed
- * back a pointer to the same socket object.
- * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
- * other side closes the connection ? Or when I call Close ?
+ * \param address Address of remote.
*/
- void Connect(const Ipv4Address & address,
- uint16_t portNumber,
- Callback<void, Ptr<Socket> > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket),
- Callback<void, Ptr<Socket> > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket),
- Callback<void, Ptr<Socket> > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket));
+ virtual int Connect(const Address &address) = 0;
/**
- * \brief Accept connection requests from remote hosts
- * \param connectionRequest Callback for connection request from peer.
- * This user callback is passed a pointer to this socket, the
- * ip address and the port number of the connection originator.
- * This callback must return true to accept the incoming connection,
- * false otherwise. If the connection is accepted, the
- * "newConnectionCreated" callback will be invoked later to give access
- * to the user to the socket created to match this new connection. If the
- * user does not explicitely specify this callback, all incoming
- * connections will be refused.
- * \param newConnectionCreated Callback for new connection: when a new
- * is accepted, it is created and the corresponding socket is passed
- * back to the user through this callback. This user callback is passed
- * a pointer to the new socket, and the ip address and port number
- * of the connection originator.
- * \param closeRequested Callback for connection close request from peer.
- * XXX: when is this callback invoked ?
- */
- int Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest =
- MakeCallback(&Socket::RefuseAllConnections),
- Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated =
- MakeCallback (&Socket::DummyCallbackVoidSocketIpv4AddressUi16),
- Callback<void, Ptr<Socket> > closeRequested = MakeCallback (&Socket::DummyCallbackVoidSocket));
-
- /**
* \brief Send data (or dummy data) to the remote host
- * \param buffer Data to send (nil if dummy data).
- * \param size Number of bytes to send.
- * \param dataSent Data sent callback.
+ * \param p packet to send
* \returns -1 in case of error or the number of bytes copied in the
* internal buffer and accepted for transmission.
*/
- int Send (const uint8_t* buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
+ virtual int Send (const Packet &p) = 0;
/**
* \brief Send data to a specified peer.
* \param address IP Address of remote host
- * \param port port number
- * \param buffer Data to send (nil if dummy data).
- * \param size Number of bytes to send.
- * \param dataSent Data sent callback.
+ * \param p packet to send
* \returns -1 in case of error or the number of bytes copied in the
* internal buffer and accepted for transmission.
*/
- int SendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
-
- /**
- * \brief Receive data
- * \param receivedData Invoked whenever new data is received.
- *
- * If you wish to transport only dummy packets, this method is not a very
- * efficient way to receive these dummy packets: it will trigger a memory
- * allocation to hold the dummy memory into a buffer which can be passed
- * to the user. Instead, consider using the RecvDummy method.
- */
- void Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receivedData =
- MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16));
-
- /**
- * \brief Receive data
- * \param receivedData Invoked whenever new data is received.
- *
- * This method is included because it is vastly more efficient than the
- * Recv method when you use dummy payload.
- */
- void RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> receivedData =
- MakeCallback (&Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16));
+ virtual int SendTo(const Address &address,const Packet &p) = 0;
-private:
- virtual void DoClose(Callback<void, Ptr<Socket> > closeCompleted) = 0;
- virtual void DoConnect(const Ipv4Address & address,
- uint16_t portNumber,
- Callback<void, Ptr<Socket> > connectionSucceeded,
- Callback<void, Ptr<Socket> > connectionFailed,
- Callback<void, Ptr<Socket> > halfClose) = 0;
- virtual int DoAccept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
- Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
- Callback<void, Ptr<Socket> > closeRequested) = 0;
- virtual int DoSend (const uint8_t* buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
- virtual int DoSendTo(const Ipv4Address &address,
- uint16_t port,
- const uint8_t *buffer,
- uint32_t size,
- Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
- virtual void DoRecv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receive) = 0;
- virtual void DoRecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>) = 0;
+protected:
+ void NotifyCloseCompleted (void);
+ void NotifyConnectionSucceeded (void);
+ void NotifyConnectionFailed (void);
+ void NotifyHalfClose (void);
+ bool NotifyConnectionRequest (const Address &from);
+ void NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from);
+ void NotifyCloseRequested (void);
+ void NotifyDataSent (uint32_t size);
+ void NotifyDataReceived (const Packet &p, const Address &from);
-
- static bool RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port);
- static void DummyCallbackVoidSocket (Ptr<Socket> socket);
- static void DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t);
- static void DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t);
- static void DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t,
- const Ipv4Address &, uint16_t);
- static void DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t);
+ Callback<void,Ptr<Socket> > m_closeCompleted;
+ Callback<void, Ptr<Socket> > m_connectionSucceeded;
+ Callback<void, Ptr<Socket> > m_connectionFailed;
+ Callback<void, Ptr<Socket> > m_halfClose;
+ Callback<void, Ptr<Socket> > m_closeRequested;
+ Callback<bool, Ptr<Socket>, const Address &> m_connectionRequest;
+ Callback<void, Ptr<Socket>, const Address&> m_newConnectionCreated;
+ Callback<void, Ptr<Socket>, uint32_t> m_dataSent;
+ Callback<void, Ptr<Socket>, const Packet &,const Address&> m_receivedData;
};
} //namespace ns3
--- a/src/node/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -1,16 +1,17 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
- node = bld.create_obj('cpp', 'shlib')
- node.name = 'ns3-node'
- node.target = node.name
- node.uselib_local = ['ns3-core', 'ns3-common', 'ns3-simulator']
+ node = bld.create_ns3_module('node', ['core', 'common', 'simulator'])
node.source = [
+ 'address.cc',
+ 'eui48-address.cc',
+ 'eui64-address.cc',
+ 'inet-socket-address.cc',
+ 'packet-socket-address.cc',
'node.cc',
'ipv4-address.cc',
'net-device.cc',
- 'mac-address.cc',
- 'address-utils.cc',
+ 'address-utils.cc',
'llc-snap-header.cc',
'ethernet-header.cc',
'ethernet-trailer.cc',
@@ -21,6 +22,8 @@
'node-list.cc',
'socket.cc',
'socket-factory.cc',
+ 'packet-socket-factory.cc',
+ 'packet-socket.cc',
'udp.cc',
'ipv4.cc',
'application.cc',
@@ -28,11 +31,15 @@
headers = bld.create_obj('ns3header')
headers.source = [
+ 'address.h',
+ 'eui48-address.h',
+ 'eui64-address.h',
+ 'inet-socket-address.h',
+ 'packet-socket-address.h',
'node.h',
'ipv4-address.h',
'net-device.h',
- 'mac-address.h',
- 'address-utils.h',
+ 'address-utils.h',
'ipv4-route.h',
'queue.h',
'drop-tail-queue.h',
@@ -43,6 +50,7 @@
'node-list.h',
'socket.h',
'socket-factory.h',
+ 'packet-socket-factory.h',
'udp.h',
'ipv4.h',
'application.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include "ns3/debug.h"
+#include "ns3/assert.h"
+#include "candidate-queue.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("CandidateQueue");
+
+namespace ns3 {
+
+CandidateQueue::CandidateQueue()
+ : m_candidates ()
+{
+ NS_DEBUG("CandidateQueue::CandidateQueue ()");
+}
+
+CandidateQueue::~CandidateQueue()
+{
+ NS_DEBUG("CandidateQueue::~CandidateQueue ()");
+ Clear ();
+}
+
+ void
+CandidateQueue::Clear (void)
+{
+ NS_DEBUG("CandidateQueue::Clear ()");
+
+ while (!m_candidates.empty ())
+ {
+ SPFVertex *p = Pop ();
+ delete p;
+ p = 0;
+ }
+}
+
+ void
+CandidateQueue::Push (SPFVertex *vNew)
+{
+ NS_DEBUG("CandidateQueue::Push (" << vNew << ")");
+
+ CandidateList_t::iterator i = m_candidates.begin ();
+
+ for (; i != m_candidates.end (); i++)
+ {
+ SPFVertex *v = *i;
+ if (vNew->GetDistanceFromRoot () < v->GetDistanceFromRoot ())
+ {
+ break;
+ }
+ }
+ m_candidates.insert(i, vNew);
+}
+
+ SPFVertex *
+CandidateQueue::Pop (void)
+{
+ NS_DEBUG("CandidateQueue::Pop ()");
+
+ if (m_candidates.empty ())
+ {
+ return 0;
+ }
+
+ SPFVertex *v = m_candidates.front ();
+ m_candidates.pop_front ();
+ return v;
+}
+
+ SPFVertex *
+CandidateQueue::Top (void) const
+{
+ NS_DEBUG("CandidateQueue::Top ()");
+
+ if (m_candidates.empty ())
+ {
+ return 0;
+ }
+
+ return m_candidates.front ();
+}
+
+ bool
+CandidateQueue::Empty (void) const
+{
+ NS_DEBUG("CandidateQueue::Empty ()");
+
+ return m_candidates.empty ();
+}
+
+ uint32_t
+CandidateQueue::Size (void) const
+{
+ NS_DEBUG("CandidateQueue::Size ()");
+
+ return m_candidates.size ();
+}
+
+ SPFVertex *
+CandidateQueue::Find (const Ipv4Address addr) const
+{
+ NS_DEBUG("CandidateQueue::Find ()");
+
+ CandidateList_t::const_iterator i = m_candidates.begin ();
+
+ for (; i != m_candidates.end (); i++)
+ {
+ SPFVertex *v = *i;
+ if (v->GetVertexId() == addr)
+ {
+ return v;
+ }
+ }
+
+ return 0;
+}
+
+ void
+CandidateQueue::Reorder (void)
+{
+ NS_DEBUG("CandidateQueue::Reorder ()");
+
+ std::list<SPFVertex*> temp;
+
+ while (!m_candidates.empty ()) {
+ SPFVertex *v = m_candidates.front ();
+ m_candidates.pop_front ();
+ temp.push_back(v);
+ }
+
+ while (!temp.empty ()) {
+ Push (temp.front ());
+ temp.pop_front ();
+ }
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,181 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef CANDIDATE_QUEUE_H
+#define CANDIDATE_QUEUE_H
+
+#include <stdint.h>
+#include <list>
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+/**
+ * \brief A Candidate Queue used in static routing.
+ *
+ * The CandidateQueue is used in the OSPF shortest path computations. It
+ * is a priority queue used to store candidates for the shortest path to a
+ * given network.
+ *
+ * The queue holds Shortest Path First Vertex pointers and orders them
+ * according to the lowest value of the field m_distanceFromRoot. Remaining
+ * vertices are ordered according to increasing distance. This implements a
+ * priority queue.
+ *
+ * Although a STL priority_queue almost does what we want, the requirement
+ * for a Find () operation, the dynamic nature of the data and the derived
+ * requirement for a Reorder () operation led us to implement this simple
+ * enhanced priority queue.
+ */
+class CandidateQueue
+{
+public:
+/**
+ * @brief Create an empty SPF Candidate Queue.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+ CandidateQueue ();
+
+/**
+ * @internal Destroy an SPF Candidate Queue and release any resources held
+ * by the contents.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+ virtual ~CandidateQueue ();
+
+/**
+ * @brief Empty the Candidate Queue and release all of the resources
+ * associated with the Shortest Path First Vertex pointers in the queue.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+ void Clear (void);
+
+/**
+ * @brief Push a Shortest Path First Vertex pointer onto the queue according
+ * to the priority scheme.
+ * @internal
+ *
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot. Remaining vertices are ordered according to
+ * increasing distance.
+ *
+ * @see SPFVertex
+ * @param vNew The Shortest Path First Vertex to add to the queue.
+ */
+ void Push (SPFVertex *vNew);
+
+/**
+ * @brief Pop the Shortest Path First Vertex pointer at the top of the queue.
+ * @internal
+ *
+ * The caller is given the responsiblity for releasing the resources
+ * associated with the vertex.
+ *
+ * @see SPFVertex
+ * @see Top ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+ SPFVertex* Pop (void);
+
+/**
+ * @brief Return the Shortest Path First Vertex pointer at the top of the
+ * queue.
+ * @internal
+ *
+ * This method does not pop the SPFVertex* off of the queue, it simply
+ * returns the pointer.
+ *
+ * @see SPFVertex
+ * @see Pop ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+ SPFVertex* Top (void) const;
+
+/**
+ * @brief Test the Candidate Queue to determine if it is empty.
+ * @internal
+ *
+ * @returns True if the queue is empty, false otherwise.
+ */
+ bool Empty (void) const;
+
+/**
+ * @brief Return the number of Shortest Path First Vertex pointers presently
+ * stored in the Candidate Queue.
+ * @internal
+ *
+ * @see SPFVertex
+ * @returns The number of SPFVertex* pointers in the Candidate Queue.
+ */
+ uint32_t Size (void) const;
+
+/**
+ * @brief Searches the Candidate Queue for a Shortest Path First Vertex
+ * pointer that points to a vertex having the given IP address.
+ * @internal
+ *
+ * @see SPFVertex
+ * @param addr The IP address to search for.
+ * @returns The SPFVertex* pointer corresponding to the given IP address.
+ */
+ SPFVertex* Find (const Ipv4Address addr) const;
+
+/**
+ * @brief Reorders the Candidate Queue according to the priority scheme.
+ * @internal
+ *
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot. Remaining vertices are ordered according to
+ * increasing distance.
+ *
+ * This method is provided in case the values of m_distanceFromRoot change
+ * during the routing calculations.
+ *
+ * @see SPFVertex
+ */
+ void Reorder (void);
+
+protected:
+ typedef std::list<SPFVertex*> CandidateList_t;
+ CandidateList_t m_candidates;
+
+private:
+/**
+ * Candidate Queue copy construction is disallowed (not implemented) to
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+ CandidateQueue (CandidateQueue& sr);
+
+/**
+ * Candidate Queue assignment operator is disallowed (not implemented) to
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+ CandidateQueue& operator= (CandidateQueue& sr);
+};
+
+} // namespace ns3
+
+#endif /* CANDIDATE_QUEUE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,1711 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include <utility>
+#include <vector>
+#include <queue>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/debug.h"
+#include "ns3/node-list.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+#include "global-route-manager-impl.h"
+#include "candidate-queue.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("GlobalRouteManager");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// SPFVertex Implementation
+//
+// ---------------------------------------------------------------------------
+
+SPFVertex::SPFVertex () :
+ m_vertexType (VertexUnknown),
+ m_vertexId ("255.255.255.255"),
+ m_lsa (0),
+ m_distanceFromRoot (SPF_INFINITY),
+ m_rootOif (SPF_INFINITY),
+ m_nextHop ("0.0.0.0"),
+ m_parent (0),
+ m_children ()
+{
+}
+
+SPFVertex::SPFVertex (GlobalRoutingLSA* lsa) :
+ m_vertexId (lsa->GetLinkStateId ()),
+ m_lsa (lsa),
+ m_distanceFromRoot (SPF_INFINITY),
+ m_rootOif (SPF_INFINITY),
+ m_nextHop ("0.0.0.0"),
+ m_parent (0),
+ m_children ()
+{
+ if (lsa->GetLSType () == GlobalRoutingLSA::RouterLSA)
+ {
+ NS_DEBUG ("SPFVertex:: setting m_vertexType to VertexRouter");
+ m_vertexType = SPFVertex::VertexRouter;
+ }
+ else if (lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA)
+ {
+ NS_DEBUG ("SPFVertex:: setting m_vertexType to VertexNetwork");
+ m_vertexType = SPFVertex::VertexNetwork;
+ }
+}
+
+SPFVertex::~SPFVertex ()
+{
+ for ( ListOfSPFVertex_t::iterator i = m_children.begin ();
+ i != m_children.end ();
+ i++)
+ {
+ SPFVertex *p = *i;
+ delete p;
+ p = 0;
+ *i = 0;
+ }
+ m_children.clear ();
+}
+
+ void
+SPFVertex::SetVertexType (SPFVertex::VertexType type)
+{
+ m_vertexType = type;
+}
+
+ SPFVertex::VertexType
+SPFVertex::GetVertexType (void) const
+{
+ return m_vertexType;
+}
+
+ void
+SPFVertex::SetVertexId (Ipv4Address id)
+{
+ m_vertexId = id;
+}
+
+ Ipv4Address
+SPFVertex::GetVertexId (void) const
+{
+ return m_vertexId;
+}
+
+ void
+SPFVertex::SetLSA (GlobalRoutingLSA* lsa)
+{
+ m_lsa = lsa;
+}
+
+ GlobalRoutingLSA*
+SPFVertex::GetLSA (void) const
+{
+ return m_lsa;
+}
+
+ void
+SPFVertex::SetDistanceFromRoot (uint32_t distance)
+{
+ m_distanceFromRoot = distance;
+}
+
+ uint32_t
+SPFVertex::GetDistanceFromRoot (void) const
+{
+ return m_distanceFromRoot;
+}
+
+ void
+SPFVertex::SetOutgoingInterfaceId (uint32_t id)
+{
+ m_rootOif = id;
+}
+
+ uint32_t
+SPFVertex::GetOutgoingInterfaceId (void) const
+{
+ return m_rootOif;
+}
+
+ void
+SPFVertex::SetNextHop (Ipv4Address nextHop)
+{
+ m_nextHop = nextHop;
+}
+
+ Ipv4Address
+SPFVertex::GetNextHop (void) const
+{
+ return m_nextHop;
+}
+
+ void
+SPFVertex::SetParent (SPFVertex* parent)
+{
+ m_parent = parent;
+}
+
+ SPFVertex*
+SPFVertex::GetParent (void) const
+{
+ return m_parent;
+}
+
+ uint32_t
+SPFVertex::GetNChildren (void) const
+{
+ return m_children.size ();
+}
+
+ SPFVertex*
+SPFVertex::GetChild (uint32_t n) const
+{
+ uint32_t j = 0;
+
+ for ( ListOfSPFVertex_t::const_iterator i = m_children.begin ();
+ i != m_children.end ();
+ i++, j++)
+ {
+ if (j == n)
+ {
+ return *i;
+ }
+ }
+ NS_ASSERT_MSG(false, "Index <n> out of range.");
+ return 0;
+}
+
+ uint32_t
+SPFVertex::AddChild (SPFVertex* child)
+{
+ m_children.push_back (child);
+ return m_children.size ();
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerLSDB Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerLSDB::GlobalRouteManagerLSDB ()
+:
+ m_database ()
+{
+ NS_DEBUG ("GlobalRouteManagerLSDB::GlobalRouteManagerLSDB ()");
+}
+
+GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ()
+{
+ NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ()");
+
+ LSDBMap_t::iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ():free LSA");
+ GlobalRoutingLSA* temp = i->second;
+ delete temp;
+ }
+ NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB (): clear map");
+ m_database.clear ();
+}
+
+ void
+GlobalRouteManagerLSDB::Initialize ()
+{
+ NS_DEBUG ("GlobalRouteManagerLSDB::Initialize ()");
+
+ LSDBMap_t::iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ GlobalRoutingLSA* temp = i->second;
+ temp->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+ }
+}
+
+ void
+GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRoutingLSA* lsa)
+{
+ NS_DEBUG ("GlobalRouteManagerLSDB::Insert ()");
+ m_database.insert (LSDBPair_t (addr, lsa));
+}
+
+ GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const
+{
+ NS_DEBUG ("GlobalRouteManagerLSDB::GetLSA ()");
+//
+// Look up an LSA by its address.
+//
+ LSDBMap_t::const_iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ if (i->first == addr)
+ {
+ return i->second;
+ }
+ }
+ return 0;
+}
+
+ GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSAByLinkData (Ipv4Address addr) const
+{
+ NS_DEBUG ("GlobalRouteManagerLSDB::GetLSAByLinkData ()");
+//
+// Look up an LSA by its address.
+//
+ LSDBMap_t::const_iterator i;
+ for (i= m_database.begin (); i!= m_database.end (); i++)
+ {
+ GlobalRoutingLSA* temp = i->second;
+// Iterate among temp's Link Records
+ for (uint32_t j = 0; j < temp->GetNLinkRecords (); j++)
+ {
+ GlobalRoutingLinkRecord *lr = temp->GetLinkRecord (j);
+ if ( lr->GetLinkType () == GlobalRoutingLinkRecord::TransitNetwork &&
+ lr->GetLinkData () == addr)
+ {
+ return temp;
+ }
+ }
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerImpl Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerImpl::GlobalRouteManagerImpl ()
+:
+ m_spfroot (0)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::GlobalRoutemanagerImpl ()");
+ m_lsdb = new GlobalRouteManagerLSDB ();
+}
+
+GlobalRouteManagerImpl::~GlobalRouteManagerImpl ()
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::~GlobalRouteManagerImpl ()");
+
+ if (m_lsdb)
+ {
+ delete m_lsdb;
+ }
+}
+
+ void
+GlobalRouteManagerImpl::DebugUseLsdb (GlobalRouteManagerLSDB* lsdb)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::DebugUseLsdb ()");
+
+ if (m_lsdb)
+ {
+ delete m_lsdb;
+ }
+ m_lsdb = lsdb;
+}
+
+//
+// In order to build the routing database, we need at least one of the nodes
+// to participate as a router. Eventually we expect to provide a mechanism
+// for selecting a subset of the nodes to participate; for now, we just make
+// all nodes routers. We do this by walking the list of nodes in the system
+// and aggregating a Global Router Interface to each of the nodes.
+//
+ void
+GlobalRouteManagerImpl::SelectRouterNodes ()
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes ()");
+
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+ NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes (): "
+ "Adding GlobalRouter interface to node " <<
+ node->GetId ());
+
+ Ptr<GlobalRouter> globalRouter = Create<GlobalRouter> (node);
+ node->AddInterface (globalRouter);
+ }
+}
+
+//
+// In order to build the routing database, we need to walk the list of nodes
+// in the system and look for those that support the GlobalRouter interface.
+// These routers will export a number of Link State Advertisements (LSAs)
+// that describe the links and networks that are "adjacent" (i.e., that are
+// on the other side of a point-to-point link). We take these LSAs and put
+// add them to the Link State DataBase (LSDB) from which the routes will
+// ultimately be computed.
+//
+ void
+GlobalRouteManagerImpl::BuildGlobalRoutingDatabase ()
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::BuildGlobalRoutingDatabase()");
+//
+// Walk the list of nodes looking for the GlobalRouter Interface.
+//
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// Ignore nodes that aren't participating in routing.
+//
+ if (!rtr)
+ {
+ continue;
+ }
+//
+// You must call DiscoverLSAs () before trying to use any routing info or to
+// update LSAs. DiscoverLSAs () drives the process of discovering routes in
+// the GlobalRouter. Afterward, you may use GetNumLSAs (), which is a very
+// computationally inexpensive call. If you call GetNumLSAs () before calling
+// DiscoverLSAs () will get zero as the number since no routes have been
+// found.
+//
+ uint32_t numLSAs = rtr->DiscoverLSAs ();
+ NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs");
+
+ for (uint32_t j = 0; j < numLSAs; ++j)
+ {
+ GlobalRoutingLSA* lsa = new GlobalRoutingLSA ();
+//
+// This is the call to actually fetch a Link State Advertisement from the
+// router.
+//
+ rtr->GetLSA (j, *lsa);
+ NS_DEBUG (*lsa);
+//
+// Write the newly discovered link state advertisement to the database.
+//
+ m_lsdb->Insert (lsa->GetLinkStateId (), lsa);
+ }
+ }
+}
+
+//
+// For each node that is a global router (which is determined by the presence
+// of an aggregated GlobalRouter interface), run the Dijkstra SPF calculation
+// on the database rooted at that router, and populate the node forwarding
+// tables.
+//
+// This function parallels RFC2328, Section 16.1.1, and quagga ospfd
+//
+// This calculation yields the set of intra-area routes associated
+// with an area (called hereafter Area A). A router calculates the
+// shortest-path tree using itself as the root. The formation
+// of the shortest path tree is done here in two stages. In the
+// first stage, only links between routers and transit networks are
+// considered. Using the Dijkstra algorithm, a tree is formed from
+// this subset of the link state database. In the second stage,
+// leaves are added to the tree by considering the links to stub
+// networks.
+//
+// The area's link state database is represented as a directed graph.
+// The graph's vertices are routers, transit networks and stub networks.
+//
+// The first stage of the procedure (i.e., the Dijkstra algorithm)
+// can now be summarized as follows. At each iteration of the
+// algorithm, there is a list of candidate vertices. Paths from
+// the root to these vertices have been found, but not necessarily
+// the shortest ones. However, the paths to the candidate vertex
+// that is closest to the root are guaranteed to be shortest; this
+// vertex is added to the shortest-path tree, removed from the
+// candidate list, and its adjacent vertices are examined for
+// possible addition to/modification of the candidate list. The
+// algorithm then iterates again. It terminates when the candidate
+// list becomes empty.
+//
+ void
+GlobalRouteManagerImpl::InitializeRoutes ()
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::InitializeRoutes ()");
+//
+// Walk the list of nodes in the system.
+//
+ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+//
+// Look for the GlobalRouter interface that indicates that the node is
+// participating in routing.
+//
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// if the node has a global router interface, then run the global routing
+// algorithms.
+//
+ if (rtr && rtr->GetNumLSAs () )
+ {
+ SPFCalculate (rtr->GetRouterId ());
+ }
+ }
+}
+
+//
+// This method is derived from quagga ospf_spf_next (). See RFC2328 Section
+// 16.1 (2) for further details.
+//
+// We're passed a parameter <v> that is a vertex which is already in the SPF
+// tree. A vertex represents a router node. We also get a reference to the
+// SPF candidate queue, which is a priority queue containing the shortest paths
+// to the networks we know about.
+//
+// We examine the links in v's LSA and update the list of candidates with any
+// vertices not already on the list. If a lower-cost path is found to a
+// vertex already on the candidate list, store the new (lower) cost.
+//
+ void
+GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate)
+{
+ SPFVertex* w = 0;
+ GlobalRoutingLSA* w_lsa = 0;
+ GlobalRoutingLinkRecord *l = 0;
+ uint32_t distance = 0;
+ uint32_t numRecordsInVertex = 0;
+
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFNext ()");
+
+// V points to a Router-LSA or Network-LSA
+// Loop over the links in router LSA or attached routers in Network LSA
+ if (v->GetVertexType () == SPFVertex::VertexRouter)
+ {
+ numRecordsInVertex = v->GetLSA ()->GetNLinkRecords ();
+ }
+ if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+ numRecordsInVertex = v->GetLSA ()->GetNAttachedRouters ();
+ }
+
+ for (uint32_t i = 0; i < numRecordsInVertex; i++)
+ {
+// Get w_lsa: In case of V is Router-LSA
+ if (v->GetVertexType () == SPFVertex::VertexRouter)
+ {
+ NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " <<
+ v->GetLSA ()->GetNLinkRecords () << " link records");
+//
+// (a) If this is a link to a stub network, examine the next link in V's LSA.
+// Links to stub networks will be considered in the second stage of the
+// shortest path calculation.
+//
+ l = v->GetLSA ()->GetLinkRecord (i);
+ if (l->GetLinkType () == GlobalRoutingLinkRecord::StubNetwork)
+ {
+ NS_DEBUG ("SPFNext: Found a Stub record to " <<
+ l->GetLinkId ());
+ continue;
+ }
+//
+// (b) Otherwise, W is a transit vertex (router or transit network). Look up
+// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state
+// database.
+//
+ if (l->GetLinkType () == GlobalRoutingLinkRecord::PointToPoint)
+ {
+//
+// Lookup the link state advertisement of the new link -- we call it <w> in
+// the link state database.
+//
+ w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+ NS_ASSERT (w_lsa);
+ NS_DEBUG ("SPFNext: Found a P2P record from " <<
+ v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+ }
+ else if (l->GetLinkType () ==
+ GlobalRoutingLinkRecord::TransitNetwork)
+ {
+ w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+ NS_ASSERT (w_lsa);
+ NS_DEBUG ("SPFNext: Found a Transit record from " <<
+ v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+ }
+ else
+ {
+ NS_ASSERT_MSG (0, "illegal Link Type");
+ }
+ }
+// Get w_lsa: In case of V is Network-LSA
+ if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+ w_lsa = m_lsdb->GetLSAByLinkData
+ (v->GetLSA ()->GetAttachedRouter (i));
+ if (!w_lsa)
+ {
+ continue;
+ }
+ NS_DEBUG ("SPFNext: Found a Network LSA from " <<
+ v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+ }
+
+// Note: w_lsa at this point may be either RouterLSA or NetworkLSA
+//
+// (c) If vertex W is already on the shortest-path tree, examine the next
+// link in the LSA.
+//
+// If the link is to a router that is already in the shortest path first tree
+// then we have it covered -- ignore it.
+//
+ if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_IN_SPFTREE)
+ {
+ NS_DEBUG ("SPFNext: Skipping-> LSA "<<
+ w_lsa->GetLinkStateId () << " already in SPF tree");
+ continue;
+ }
+//
+// (d) Calculate the link state cost D of the resulting path from the root to
+// vertex W. D is equal to the sum of the link state cost of the (already
+// calculated) shortest path to vertex V and the advertised cost of the link
+// between vertices V and W.
+//
+ if (v->GetLSA ()->GetLSType () == GlobalRoutingLSA::RouterLSA)
+ {
+ distance = v->GetDistanceFromRoot () + l->GetMetric ();
+ }
+ else
+ {
+ distance = v->GetDistanceFromRoot ();
+ }
+
+ NS_DEBUG ("SPFNext: Considering w_lsa " << w_lsa->GetLinkStateId ());
+
+// Is there already vertex w in candidate list?
+ if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+ {
+
+// prepare vertex w
+ w = new SPFVertex (w_lsa);
+// Calculate nexthop to w
+// We need to figure out how to actually get to the new router represented
+// by <w>. This will (among other things) find the next hop address to send
+// packets destined for this network to, and also find the outbound interface
+// used to forward the packets.
+//
+ if (SPFNexthopCalculation (v, w, l, distance))
+ {
+ w_lsa->SetStatus (GlobalRoutingLSA::LSA_SPF_CANDIDATE);
+//
+// Push this new vertex onto the priority queue (ordered by distance from the
+// root node).
+//
+ candidate.Push (w);
+ NS_DEBUG ("SPFNext: Pushing " <<
+ w->GetVertexId () << ", parent vertexId: " <<
+ v->GetVertexId ());
+ }
+ }
+ else if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_CANDIDATE)
+ {
+//
+// We have already considered the link represented by <w>. What wse have to
+// do now is to decide if this new router represents a route with a shorter
+// distance metric.
+//
+// So, locate the vertex in the candidate queue and take a look at the
+// distance.
+ w = candidate.Find (w_lsa->GetLinkStateId ());
+ if (w->GetDistanceFromRoot () < distance)
+ {
+//
+// This is not a shorter path, so don't do anything.
+//
+ continue;
+ }
+ else if (w->GetDistanceFromRoot () == distance)
+ {
+//
+// This path is one with an equal cost. Do nothing for now -- we're not doing
+// equal-cost multipath cases yet.
+//
+ }
+ else
+ {
+//
+// this path represents a new, lower-cost path to <w> (the vertex we found in
+// the current link record of the link state advertisement of the current root
+// (vertex <v>)
+//
+// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop
+// it will call spf_add_parents, which will flush the old parents
+//
+ if (SPFNexthopCalculation (v, w, l, distance))
+ {
+//
+// If we've changed the cost to get to the vertex represented by <w>, we
+// must reorder the priority queue keyed to that cost.
+//
+ candidate.Reorder ();
+ }
+ } // new lower cost path found
+ } // end W is already on the candidate list
+ } // end loop over the links in V's LSA
+}
+
+//
+// This method is derived from quagga ospf_next_hop_calculation() 16.1.1.
+//
+// Calculate nexthop from root through V (parent) to vertex W (destination)
+// with given distance from root->W.
+//
+// As appropriate, set w's parent, distance, and nexthop information
+//
+// For now, this is greatly simplified from the quagga code
+//
+ int
+GlobalRouteManagerImpl::SPFNexthopCalculation (
+ SPFVertex* v,
+ SPFVertex* w,
+ GlobalRoutingLinkRecord* l,
+ uint32_t distance)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFNexthopCalculation ()");
+
+// If w is a NetworkVertex, l should be null
+/*
+ if (w->GetVertexType () == SPFVertex::VertexNetwork && l)
+ {
+ NS_ASSERT_MSG(0, "Error: SPFNexthopCalculation parameter problem");
+ }
+*/
+
+//
+// The vertex m_spfroot is a distinguished vertex representing the node at
+// the root of the calculations. That is, it is the node for which we are
+// calculating the routes.
+//
+// There are two distinct cases for calculating the next hop information.
+// First, if we're considering a hop from the root to an "adjacent" network
+// (one that is on the other side of a point-to-point link connected to the
+// root), then we need to store the information needed to forward down that
+// link. The second case is if the network is not directly adjacent. In that
+// case we need to use the forwarding information from the vertex on the path
+// to the destination that is directly adjacent [node 1] in both cases of the
+// diagram below.
+//
+// (1) [root] -> [point-to-point] -> [node 1]
+// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2]
+//
+// We call the propagation of next hop information down vertices of a path
+// "inheriting" the next hop information.
+//
+// The point-to-point link information is only useful in this calculation when
+// we are examining the root node.
+//
+ if (v == m_spfroot)
+ {
+//
+// In this case <v> is the root node, which means it is the starting point
+// for the packets forwarded by that node. This also means that the next hop
+// address of packets headed for some arbitrary off-network destination must
+// be the destination at the other end of one of the links off of the root
+// node if this root node is a router. We then need to see if this node <w>
+// is a router.
+//
+ if (w->GetVertexType () == SPFVertex::VertexRouter)
+ {
+//
+// In the case of point-to-point links, the link data field (m_linkData) of a
+// Global Router Link Record contains the local IP address. If we look at the
+// link record describing the link from the perspecive of <w> (the remote
+// node from the viewpoint of <v>) back to the root node, we can discover the
+// IP address of the router to which <v> is adjacent. This is a distinguished
+// address -- the next hop address to get from <v> to <w> and all networks
+// accessed through that path.
+//
+// SPFGetNextLink () is a little odd. used in this way it is just going to
+// return the link record describing the link from <w> to <v>. Think of it as
+// SPFGetLink.
+//
+ NS_ASSERT(l);
+ GlobalRoutingLinkRecord *linkRemote = 0;
+ linkRemote = SPFGetNextLink (w, v, linkRemote);
+//
+// At this point, <l> is the Global Router Link Record describing the point-
+// to point link from <v> to <w> from the perspective of <v>; and <linkRemote>
+// is the Global Router Link Record describing that same link from the
+// perspective of <w> (back to <v>). Now we can just copy the next hop
+// address from the m_linkData member variable.
+//
+// The next hop member variable we put in <w> has the sense "in order to get
+// from the root node to the host represented by vertex <w>, you have to send
+// the packet to the next hop address specified in w->m_nextHop.
+//
+ w->SetNextHop(linkRemote->GetLinkData ());
+//
+// Now find the outgoing interface corresponding to the point to point link
+// from the perspective of <v> -- remember that <l> is the link "from"
+// <v> "to" <w>.
+//
+ w->SetOutgoingInterfaceId (
+ FindOutgoingInterfaceId (l->GetLinkData ()));
+
+ NS_DEBUG ("SPFNexthopCalculation: Next hop from " <<
+ v->GetVertexId () << " to " << w->GetVertexId () <<
+ " goes through next hop " << w->GetNextHop () <<
+ " via outgoing interface " << w->GetOutgoingInterfaceId ());
+ } // end W is a router vertes
+ else
+ {
+ NS_ASSERT (w->GetVertexType () == SPFVertex::VertexNetwork);
+// W is a directly connected network; no next hop is required
+ GlobalRoutingLSA* w_lsa = w->GetLSA ();
+ NS_ASSERT (w_lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA);
+// Find outgoing interface ID for this network
+ w->SetOutgoingInterfaceId (
+ FindOutgoingInterfaceId (w_lsa->GetLinkStateId (),
+ w_lsa->GetNetworkLSANetworkMask () ));
+ w->SetDistanceFromRoot (distance);
+ w->SetParent (v);
+ NS_DEBUG ("SPFNexthopCalculation: Next hop from " <<
+ v->GetVertexId () << " to network " << w->GetVertexId () <<
+ " via outgoing interface " << w->GetOutgoingInterfaceId ());
+ return 1;
+ }
+ } // end v is the root
+ else if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+// See if any of v's parents are the root
+ if (v->GetParent () == m_spfroot)
+ {
+// 16.1.1 para 5. ...the parent vertex is a network that
+// directly connects the calculating router to the destination
+// router. The list of next hops is then determined by
+// examining the destination's router-LSA...
+ NS_ASSERT (w->GetVertexType () == SPFVertex::VertexRouter);
+ GlobalRoutingLinkRecord *linkRemote = 0;
+ while ((linkRemote = SPFGetNextLink (w, v, linkRemote)))
+ {
+/* ...For each link in the router-LSA that points back to the
+ * parent network, the link's Link Data field provides the IP
+ * address of a next hop router. The outgoing interface to
+ * use can then be derived from the next hop IP address (or
+ * it can be inherited from the parent network).
+ */
+ w->SetNextHop(linkRemote->GetLinkData ());
+ w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+ NS_DEBUG ("SPFNexthopCalculation: Next hop from " <<
+ v->GetVertexId () << " to " << w->GetVertexId () <<
+ " goes through next hop " << w->GetNextHop () <<
+ " via outgoing interface " << w->GetOutgoingInterfaceId ());
+ }
+ }
+ else
+ {
+ w->SetNextHop (v->GetNextHop ());
+ w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+ }
+ }
+ else
+ {
+//
+// If we're calculating the next hop information from a node (v) that is
+// *not* the root, then we need to "inherit" the information needed to
+// forward the packet from the vertex closer to the root. That is, we'll
+// still send packets to the next hop address of the router adjacent to the
+// root on the path toward <w>.
+//
+// Above, when we were considering the root node, we calculated the next hop
+// address and outgoing interface required to get off of the root network.
+// At this point, we are further away from the root network along one of the
+// (shortest) paths. So the next hop and outoing interface remain the same
+// (are inherited).
+//
+ w->SetNextHop (v->GetNextHop ());
+ w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+ }
+//
+// In all cases, we need valid values for the distance metric and a parent.
+//
+ w->SetDistanceFromRoot (distance);
+ w->SetParent (v);
+
+ return 1;
+}
+
+//
+// This method is derived from quagga ospf_get_next_link ()
+//
+// First search the Global Router Link Records of vertex <v> for one
+// representing a point-to point link to vertex <w>.
+//
+// What is done depends on prev_link. Contrary to appearances, prev_link just
+// acts as a flag here. If prev_link is NULL, we return the first Global
+// Router Link Record we find that describes a point-to-point link from <v>
+// to <w>. If prev_link is not NULL, we return a Global Router Link Record
+// representing a possible *second* link from <v> to <w>.
+//
+ GlobalRoutingLinkRecord*
+GlobalRouteManagerImpl::SPFGetNextLink (
+ SPFVertex* v,
+ SPFVertex* w,
+ GlobalRoutingLinkRecord* prev_link)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFGetNextLink ()");
+
+ bool skip = true;
+ bool found_prev_link = false;
+ GlobalRoutingLinkRecord* l;
+//
+// If prev_link is 0, we are really looking for the first link, not the next
+// link.
+//
+ if (prev_link == 0)
+ {
+ skip = false;
+ found_prev_link = true;
+ }
+//
+// Iterate through the Global Router Link Records advertised by the vertex
+// <v> looking for records representing the point-to-point links off of this
+// vertex.
+//
+ for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i)
+ {
+ l = v->GetLSA ()->GetLinkRecord (i);
+//
+// The link ID of a link record representing a point-to-point link is set to
+// the router ID of the neighboring router -- the router to which the link
+// connects from the perspective of <v> in this case. The vertex ID is also
+// set to the router ID (using the link state advertisement of a router node).
+// We're just checking to see if the link <l> is actually the link from <v> to
+// <w>.
+//
+ if (l->GetLinkId () == w->GetVertexId ())
+ {
+ if (!found_prev_link)
+ {
+ NS_DEBUG ("SPFGetNextLink: Skipping links before prev_link found");
+ found_prev_link = true;
+ continue;
+ }
+
+ NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " <<
+ l->GetLinkId () << " linkData = " << l->GetLinkData ());
+//
+// If skip is false, don't (not too surprisingly) skip the link found -- it's
+// the one we're interested in. That's either because we didn't pass in a
+// previous link, and we're interested in the first one, or because we've
+// skipped a previous link and moved forward to the next (which is then the
+// one we want).
+//
+ if (skip == false)
+ {
+ NS_DEBUG ("SPFGetNextLink: Returning the found link");
+ return l;
+ }
+ else
+ {
+//
+// Skip is true and we've found a link from <v> to <w>. We want the next one.
+// Setting skip to false gets us the next point-to-point global router link
+// record in the LSA from <v>.
+//
+ NS_DEBUG ("SPFGetNextLink: Skipping the found link");
+ skip = false;
+ continue;
+ }
+ }
+ }
+ return 0;
+}
+
+//
+// Used for unit tests.
+//
+ void
+GlobalRouteManagerImpl::DebugSPFCalculate (Ipv4Address root)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::DebugSPFCalculate ()");
+ SPFCalculate (root);
+}
+
+// quagga ospf_spf_calculate
+ void
+GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFCalculate (): "
+ "root = " << root);
+
+ SPFVertex *v;
+//
+// Initialize the Link State Database.
+//
+ m_lsdb->Initialize ();
+//
+// The candidate queue is a priority queue of SPFVertex objects, with the top
+// of the queue being the closest vertex in terms of distance from the root
+// of the tree. Initially, this queue is empty.
+//
+ CandidateQueue candidate;
+ NS_ASSERT(candidate.Size () == 0);
+//
+// Initialize the shortest-path tree to only contain the router doing the
+// calculation. Each router (and corresponding network) is a vertex in the
+// shortest path first (SPF) tree.
+//
+ v = new SPFVertex (m_lsdb->GetLSA (root));
+//
+// This vertex is the root of the SPF tree and it is distance 0 from the root.
+// We also mark this vertex as being in the SPF tree.
+//
+ m_spfroot= v;
+ v->SetDistanceFromRoot (0);
+ v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+
+ for (;;)
+ {
+//
+// The operations we need to do are given in the OSPF RFC which we reference
+// as we go along.
+//
+// RFC2328 16.1. (2).
+//
+// We examine the Global Router Link Records in the Link State
+// Advertisements of the current vertex. If there are any point-to-point
+// links to unexplored adjacent vertices we add them to the tree and update
+// the distance and next hop information on how to get there. We also add
+// the new vertices to the candidate queue (the priority queue ordered by
+// shortest path). If the new vertices represent shorter paths, we use them
+// and update the path cost.
+//
+ SPFNext (v, candidate);
+//
+// RFC2328 16.1. (3).
+//
+// If at this step the candidate list is empty, the shortest-path tree (of
+// transit vertices) has been completely built and this stage of the
+// procedure terminates.
+//
+ if (candidate.Size () == 0)
+ {
+ break;
+ }
+//
+// Choose the vertex belonging to the candidate list that is closest to the
+// root, and add it to the shortest-path tree (removing it from the candidate
+// list in the process).
+//
+// Recall that in the previous step, we created SPFVertex structures for each
+// of the routers found in the Global Router Link Records and added tehm to
+// the candidate list.
+//
+ v = candidate.Pop ();
+ NS_DEBUG ("SPFCalculate: Popped vertex " << v->GetVertexId ());
+//
+// Update the status field of the vertex to indicate that it is in the SPF
+// tree.
+//
+ v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+//
+// The current vertex has a parent pointer. By calling this rather oddly
+// named method (blame quagga) we add the current vertex to the list of
+// children of that parent vertex. In the next hop calculation called during
+// SPFNext, the parent pointer was set but the vertex has been orphaned up
+// to now.
+//
+ SPFVertexAddParent (v);
+//
+// Note that when there is a choice of vertices closest to the root, network
+// vertices must be chosen before router vertices in order to necessarily
+// find all equal-cost paths. We don't do this at this moment, we should add
+// the treatment above codes. -- kunihiro.
+//
+// RFC2328 16.1. (4).
+//
+// This is the method that actually adds the routes. It'll walk the list
+// of nodes in the system, looking for the node corresponding to the router
+// ID of the root of the tree -- that is the router we're building the routes
+// for. It looks for the Ipv4 interface of that node and remembers it. So
+// we are only actually adding routes to that one node at the root of the SPF
+// tree.
+//
+// We're going to pop of a pointer to every vertex in the tree except the
+// root in order of distance from the root. For each of the vertices, we call
+// SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the
+// point-to-point Global Router Link Records (the links to nodes adjacent to
+// the node represented by the vertex). We add a route to the IP address
+// specified by the m_linkData field of each of those link records. This will
+// be the *local* IP address associated with the interface attached to the
+// link. We use the outbound interface and next hop information present in
+// the vertex <v> which have possibly been inherited from the root.
+//
+// To summarize, we're going to look at the node represented by <v> and loop
+// through its point-to-point links, adding a *host* route to the local IP
+// address (at the <v> side) for each of those links.
+//
+ if (v->GetVertexType () == SPFVertex::VertexRouter)
+ {
+ SPFIntraAddRouter (v);
+ }
+ else if (v->GetVertexType () == SPFVertex::VertexNetwork)
+ {
+ SPFIntraAddTransit (v);
+ }
+ else
+ {
+ NS_ASSERT_MSG(0, "illegal SPFVertex type");
+ }
+//
+// RFC2328 16.1. (5).
+//
+// Iterate the algorithm by returning to Step 2 until there are no more
+// candidate vertices.
+//
+ }
+//
+// Second stage of SPF calculation procedure's
+// NOTYET: ospf_spf_process_stubs (area, area->spf, new_table);
+//
+// We're all done setting the routing information for the node at the root of
+// the SPF tree. Delete all of the vertices and corresponding resources. Go
+// possibly do it again for the next router.
+//
+ delete m_spfroot;
+ m_spfroot = 0;
+}
+
+//
+// XXX This should probably be a method on Ipv4
+//
+// Return the interface index corresponding to a given IP address
+//
+ uint32_t
+GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a)
+{
+//
+// We have an IP address <a> and a vertex ID of the root of the SPF tree.
+// The question is what interface index does this address correspond to.
+// The answer is a little complicated since we have to find a pointer to
+// the node corresponding to the vertex ID, find the Ipv4 interface on that
+// node in order to iterate the interfaces and find the one corresponding to
+// the address in question.
+//
+ Ipv4Address routerId = m_spfroot->GetVertexId ();
+//
+// Walk the list of nodes in the system looking for the one corresponding to
+// the node at the root of the SPF tree. This is the node for which we are
+// building the routing table.
+//
+ NodeList::Iterator i = NodeList::Begin ();
+ for (; i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// If the node doesn't have a GlobalRouter interface it can't be the one
+// we're interested in.
+//
+ if (rtr == 0)
+ {
+ continue;
+ }
+
+ if (rtr->GetRouterId () == routerId)
+ {
+//
+// This is the node we're building the routing table for. We're going to need
+// the Ipv4 interface to look for the ipv4 interface index. Since this node
+// is participating in routing IP version 4 packets, it certainly must have
+// an Ipv4 interface.
+//
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4,
+ "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+ "QI for <Ipv4> interface failed");
+//
+// Look through the interfaces on this node for one that has the IP address
+// we're looking for. If we find one, return the corresponding interface
+// index.
+//
+ for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
+ {
+ if (ipv4->GetAddress (i) == a)
+ {
+ NS_DEBUG (
+ "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+ "Interface match for " << a);
+ return i;
+ }
+ }
+ }
+ }
+//
+// Couldn't find it.
+//
+ return 0;
+}
+
+//
+// XXX This should probably be a method on Ipv4
+//
+// Return the interface index corresponding to a given IP address
+//
+ uint32_t
+GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask)
+{
+//
+// We have an IP address <a> and a vertex ID of the root of the SPF tree.
+// The question is what interface index does this address correspond to.
+// The answer is a little complicated since we have to find a pointer to
+// the node corresponding to the vertex ID, find the Ipv4 interface on that
+// node in order to iterate the interfaces and find the one corresponding to
+// the address in question.
+//
+ Ipv4Address routerId = m_spfroot->GetVertexId ();
+//
+// Walk the list of nodes in the system looking for the one corresponding to
+// the node at the root of the SPF tree. This is the node for which we are
+// building the routing table.
+//
+ NodeList::Iterator i = NodeList::Begin ();
+ for (; i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// If the node doesn't have a GlobalRouter interface it can't be the one
+// we're interested in.
+//
+ if (rtr == 0)
+ {
+ continue;
+ }
+
+ if (rtr->GetRouterId () == routerId)
+ {
+//
+// This is the node we're building the routing table for. We're going to need
+// the Ipv4 interface to look for the ipv4 interface index. Since this node
+// is participating in routing IP version 4 packets, it certainly must have
+// an Ipv4 interface.
+//
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4,
+ "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+ "QI for <Ipv4> interface failed");
+//
+// Look through the interfaces on this node for one that has the IP address
+// we're looking for. If we find one, return the corresponding interface
+// index.
+//
+ for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
+ {
+ if (ipv4->GetAddress (i).CombineMask(amask) ==
+ a.CombineMask(amask) )
+ {
+ NS_DEBUG (
+ "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+ "Interface match for " << a);
+ return i;
+ }
+ }
+ }
+ }
+//
+// Couldn't find it.
+//
+ return 0;
+}
+
+//
+// This method is derived from quagga ospf_intra_add_router ()
+//
+// This is where we are actually going to add the host routes to the routing
+// tables of the individual nodes.
+//
+// The vertex passed as a parameter has just been added to the SPF tree.
+// This vertex must have a valid m_root_oid, corresponding to the outgoing
+// interface on the root router of the tree that is the first hop on the path
+// to the vertex. The vertex must also have a next hop address, corresponding
+// to the next hop on the path to the vertex. The vertex has an m_lsa field
+// that has some number of link records. For each point to point link record,
+// the m_linkData is the local IP address of the link. This corresponds to
+// a destination IP address, reachable from the root, to which we add a host
+// route.
+//
+ void
+GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter ()");
+
+ NS_ASSERT_MSG (m_spfroot,
+ "GlobalRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are
+// going to write the actual routing table entries. The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node. We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+ Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex. This is the one we're going to write
+// the routing information to.
+//
+ NodeList::Iterator i = NodeList::Begin ();
+ for (; i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface. If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+//
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+ if (rtr == 0)
+ {
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "No GlobalRouter interface on node " << node->GetId ());
+ continue;
+ }
+//
+// If the router ID of the current node is equal to the router ID of the
+// root of the SPF tree, then this node is the one for which we need to
+// write the routing tables.
+//
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "Considering router " << rtr->GetRouterId ());
+
+ if (rtr->GetRouterId () == routerId)
+ {
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface. We need to QI
+// for that interface. If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4,
+ "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to. The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node. We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+ GlobalRoutingLSA *lsa = v->GetLSA ();
+ NS_ASSERT_MSG (lsa,
+ "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ "Expected valid LSA in SPFVertex* v");
+
+ uint32_t nLinkRecords = lsa->GetNLinkRecords ();
+//
+// Iterate through the link records on the vertex to which we're going to add
+// routes. To make sure we're being clear, we're going to add routing table
+// entries to the tables on the node corresping to the root of the SPF tree.
+// These entries will have routes to the IP addresses we find from looking at
+// the local side of the point-to-point links found on the node described by
+// the vertex <v>.
+//
+ for (uint32_t j = 0; j < nLinkRecords; j += 2)
+ {
+//
+// We are only concerned about point-to-point links
+//
+ GlobalRoutingLinkRecord *lr = lsa->GetLinkRecord (j);
+ if (lr->GetLinkType () != GlobalRoutingLinkRecord::PointToPoint)
+ {
+ continue;
+ }
+
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+ " Node " << node->GetId () <<
+ " add route to " << lr->GetLinkData () <<
+ " using next hop " << v->GetNextHop () <<
+ " via interface " << v->GetOutgoingInterfaceId ());
+//
+// Here's why we did all of that work. We're going to add a host route to the
+// host address found in the m_linkData field of the point-to-point link
+// record. In the case of a point-to-point link, this is the local IP address
+// of the node connected to the link. Each of these point-to-point links
+// will correspond to a local interface that has an IP address to which
+// the node at the root of the SPF tree can send packets. The vertex <v>
+// (corresponding to the node that has these links and interfaces) has
+// an m_nextHop address precalculated for us that is the address to which the
+// root node should send packets to be forwarded to these IP addresses.
+// Similarly, the vertex <v> has an m_rootOif (outbound interface index) to
+// which the packets should be send for forwarding.
+//
+ ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (),
+ v->GetOutgoingInterfaceId ());
+ }
+//
+// Done adding the routes for the selected node.
+//
+ return;
+ }
+ }
+}
+ void
+GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v)
+{
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit ()");
+
+ NS_ASSERT_MSG (m_spfroot,
+ "GlobalRouteManagerImpl::SPFIntraAddTransit (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are
+// going to write the actual routing table entries. The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node. We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+ Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex. This is the one we're going to write
+// the routing information to.
+//
+ NodeList::Iterator i = NodeList::Begin ();
+ for (; i != NodeList::End (); i++)
+ {
+ Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface. If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+//
+ Ptr<GlobalRouter> rtr =
+ node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+ if (rtr == 0)
+ {
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "No GlobalRouter interface on node " << node->GetId ());
+ continue;
+ }
+//
+// If the router ID of the current node is equal to the router ID of the
+// root of the SPF tree, then this node is the one for which we need to
+// write the routing tables.
+//
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "Considering router " << rtr->GetRouterId ());
+
+ if (rtr->GetRouterId () == routerId)
+ {
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface. We need to QI
+// for that interface. If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG (ipv4,
+ "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to. The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node. We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+ GlobalRoutingLSA *lsa = v->GetLSA ();
+ NS_ASSERT_MSG (lsa,
+ "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+ "Expected valid LSA in SPFVertex* v");
+ Ipv4Mask tempmask = lsa->GetNetworkLSANetworkMask ();
+ Ipv4Address tempip = lsa->GetLinkStateId ();
+ tempip = tempip.CombineMask (tempmask);
+ ipv4->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (),
+ v->GetOutgoingInterfaceId ());
+ NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddNetwork (): "
+ " Node " << node->GetId () <<
+ " add network route to " << tempip <<
+ " using next hop " << v->GetNextHop () <<
+ " via interface " << v->GetOutgoingInterfaceId ());
+ }
+ }
+}
+
+// Derived from quagga ospf_vertex_add_parents ()
+//
+// This is a somewhat oddly named method (blame quagga). Although you might
+// expect it to add a parent *to* something, it actually adds a vertex
+// to the list of children *in* each of its parents.
+//
+// Given a pointer to a vertex, it links back to the vertex's parent that it
+// already has set and adds itself to that vertex's list of children.
+//
+// For now, only one parent (not doing equal-cost multipath)
+//
+ void
+GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v)
+{
+ v->GetParent ()->AddChild (v);
+}
+
+} // namespace ns3
+
+#ifdef RUN_SELF_TESTS
+
+// ---------------------------------------------------------------------------
+//
+// Unit Tests
+//
+// ---------------------------------------------------------------------------
+
+#include "ns3/test.h"
+#include "ns3/simulator.h"
+
+namespace ns3 {
+
+class GlobalRouterTestNode : public Node
+{
+public:
+ GlobalRouterTestNode ();
+
+private:
+ virtual void DoAddDevice (Ptr<NetDevice> device) const {};
+ virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
+};
+
+GlobalRouterTestNode::GlobalRouterTestNode ()
+{
+// Ptr<Ipv4L3Protocol> ipv4 = Create<Ipv4L3Protocol> (this);
+}
+
+ TraceResolver*
+GlobalRouterTestNode::DoCreateTraceResolver (TraceContext const &context)
+{
+ return 0;
+}
+
+class GlobalRouteManagerImplTest : public Test {
+public:
+ GlobalRouteManagerImplTest ();
+ virtual ~GlobalRouteManagerImplTest ();
+ virtual bool RunTests (void);
+};
+
+GlobalRouteManagerImplTest::GlobalRouteManagerImplTest ()
+ : Test ("GlobalRouteManagerImpl")
+{
+}
+
+GlobalRouteManagerImplTest::~GlobalRouteManagerImplTest ()
+{}
+
+ bool
+GlobalRouteManagerImplTest::RunTests (void)
+{
+ bool ok = true;
+
+ CandidateQueue candidate;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ SPFVertex *v = new SPFVertex;
+ v->SetDistanceFromRoot (rand () % 100);
+ candidate.Push (v);
+ }
+
+ uint32_t lastDistance = 0;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ SPFVertex *v = candidate.Pop ();
+ if (v->GetDistanceFromRoot () < lastDistance)
+ {
+ ok = false;
+ }
+ lastDistance = v->GetDistanceFromRoot ();
+ delete v;
+ v = 0;
+ }
+
+ // Build fake link state database; four routers (0-3), 3 point-to-point
+ // links
+ //
+ // n0
+ // \ link 0
+ // \ link 2
+ // n2 -------------------------n3
+ // /
+ // / link 1
+ // n1
+ //
+ // link0: 10.1.1.1/30, 10.1.1.2/30
+ // link1: 10.1.2.1/30, 10.1.2.2/30
+ // link2: 10.1.3.1/30, 10.1.3.2/30
+ //
+ // Router 0
+ GlobalRoutingLinkRecord* lr0 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.2", // router ID 0.0.0.2
+ "10.1.1.1", // local ID
+ 1); // metric
+
+ GlobalRoutingLinkRecord* lr1 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.1.1",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa0 = new GlobalRoutingLSA ();
+ lsa0->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa0->SetLinkStateId ("0.0.0.0");
+ lsa0->SetAdvertisingRouter ("0.0.0.0");
+ lsa0->AddLinkRecord (lr0);
+ lsa0->AddLinkRecord (lr1);
+
+ // Router 1
+ GlobalRoutingLinkRecord* lr2 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.2",
+ "10.1.2.1",
+ 1);
+
+ GlobalRoutingLinkRecord* lr3 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.2.1",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa1 = new GlobalRoutingLSA ();
+ lsa1->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa1->SetLinkStateId ("0.0.0.1");
+ lsa1->SetAdvertisingRouter ("0.0.0.1");
+ lsa1->AddLinkRecord (lr2);
+ lsa1->AddLinkRecord (lr3);
+
+ // Router 2
+ GlobalRoutingLinkRecord* lr4 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.0",
+ "10.1.1.2",
+ 1);
+
+ GlobalRoutingLinkRecord* lr5 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.1.2",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLinkRecord* lr6 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.1",
+ "10.1.2.2",
+ 1);
+
+ GlobalRoutingLinkRecord* lr7 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.2.2",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLinkRecord* lr8 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.3",
+ "10.1.3.2",
+ 1);
+
+ GlobalRoutingLinkRecord* lr9 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.3.2",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa2 = new GlobalRoutingLSA ();
+ lsa2->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa2->SetLinkStateId ("0.0.0.2");
+ lsa2->SetAdvertisingRouter ("0.0.0.2");
+ lsa2->AddLinkRecord (lr4);
+ lsa2->AddLinkRecord (lr5);
+ lsa2->AddLinkRecord (lr6);
+ lsa2->AddLinkRecord (lr7);
+ lsa2->AddLinkRecord (lr8);
+ lsa2->AddLinkRecord (lr9);
+
+ // Router 3
+ GlobalRoutingLinkRecord* lr10 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::PointToPoint,
+ "0.0.0.2",
+ "10.1.2.1",
+ 1);
+
+ GlobalRoutingLinkRecord* lr11 = new GlobalRoutingLinkRecord (
+ GlobalRoutingLinkRecord::StubNetwork,
+ "10.1.2.1",
+ "255.255.255.252",
+ 1);
+
+ GlobalRoutingLSA* lsa3 = new GlobalRoutingLSA ();
+ lsa3->SetLSType (GlobalRoutingLSA::RouterLSA);
+ lsa3->SetLinkStateId ("0.0.0.3");
+ lsa3->SetAdvertisingRouter ("0.0.0.3");
+ lsa3->AddLinkRecord (lr10);
+ lsa3->AddLinkRecord (lr11);
+
+ // Test the database
+ GlobalRouteManagerLSDB* srmlsdb = new GlobalRouteManagerLSDB ();
+ srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0);
+ srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1);
+ srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2);
+ srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3);
+ NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ()));
+
+ // next, calculate routes based on the manually created LSDB
+ GlobalRouteManagerImpl* srm = new GlobalRouteManagerImpl ();
+ srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB
+ // Note-- this will succeed without any nodes in the topology
+ // because the NodeList is empty
+ srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+
+ // This delete clears the srm, which deletes the LSDB, which clears
+ // all of the LSAs, which each destroys the attached LinkRecords.
+ delete srm;
+
+ return ok;
+}
+
+// Instantiate this class for the unit tests
+// XXX here we should do some verification of the routes built
+static GlobalRouteManagerImplTest g_globalRouteManagerTest;
+
+} // namespace ns3
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,763 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_IMPL_H
+#define GLOBAL_ROUTE_MANAGER_IMPL_H
+
+#include <stdint.h>
+#include <list>
+#include <queue>
+#include <map>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "global-router-interface.h"
+
+namespace ns3 {
+
+const uint32_t SPF_INFINITY = 0xffffffff;
+
+class CandidateQueue;
+
+/**
+ * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328,
+ * Section 16.
+ *
+ * Each router in the simulation is associated with an SPFVertex object. When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes. Each of these
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is the SPFVertex representing the router that is having
+ * its routing tables set. The SPFVertex objects representing other routers
+ * or networks in the simulation are arranged in the SPF tree. It is this
+ * tree that represents the Shortest Paths to the other networks.
+ *
+ * Each SPFVertex has a pointer to the Global Router Link State Advertisement
+ * (LSA) that its underlying router has exported. Within these LSAs are
+ * Global Router Link Records that describe the point to point links from the
+ * underlying router to other nodes (represented by other SPFVertex objects)
+ * in the simulation topology. The combination of the arrangement of the
+ * SPFVertex objects in the SPF tree, along with the details of the link
+ * records that connect them provide the information required to construct the
+ * required routes.
+ */
+class SPFVertex
+{
+public:
+/**
+ * @brief Enumeration of the possible types of SPFVertex objects.
+ * @internal
+ *
+ * Currently we use VertexRouter to identify objects that represent a router
+ * in the simulation topology, and VertexNetwork to identify objects that
+ * represent a network.
+ */
+ enum VertexType {
+ VertexUnknown = 0, /**< Uninitialized Link Record */
+ VertexRouter, /**< Vertex representing a router in the topology */
+ VertexNetwork /**< Vertex representing a network in the topology */
+ };
+
+/**
+ * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First
+ * Vertex).
+ * @internal
+ *
+ * The Vertex Type is set to VertexUnknown, the Vertex ID is set to
+ * 255.255.255.255, and the distance from root is set to infinity
+ * (UINT32_MAX). The referenced Link State Advertisement (LSA) is set to
+ * null as is the parent SPFVertex. The outgoing interface index is set to
+ * infinity, the next hop address is set to 0.0.0.0 and the list of children
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see VertexType
+ */
+ SPFVertex();
+
+/**
+ * @brief Construct an initialized SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The Vertex Type is initialized to VertexRouter and the Vertex ID is found
+ * from the Link State ID of the Link State Advertisement (LSA) passed as a
+ * parameter. The Link State ID is set to the Router ID of the advertising
+ * router. The referenced LSA (m_lsa) is set to the given LSA. Other than
+ * these members, initialization is as in the default constructor.
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see SPFVertex::SPFVertex ()
+ * @see VertexType
+ * @see GlobalRoutingLSA
+ * @param lsa The Link State Advertisement used for finding initial values.
+ */
+ SPFVertex(GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Destroy an SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The children vertices of the SPFVertex are recursively deleted.
+ *
+ * @see SPFVertex::SPFVertex ()
+ */
+ ~SPFVertex();
+
+/**
+ * @brief Get the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @returns The VertexType of the current SPFVertex object.
+ */
+ VertexType GetVertexType (void) const;
+
+/**
+ * @brief Set the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @param type The new VertexType for the current SPFVertex object.
+ */
+ void SetVertexType (VertexType type);
+
+/**
+ * @brief Get the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents. Typically, this is the Router ID for SPFVertex objects
+ * representing routers, and comes from the Link State Advertisement of a
+ * router aggregated to a node in the simulation. These IDs are allocated
+ * automatically by the routing environment and look like IP addresses
+ * beginning at 0.0.0.0 and monotonically increasing as new routers are
+ * instantiated.
+ *
+ * @returns The Ipv4Address Vertex ID of the current SPFVertex object.
+ */
+ Ipv4Address GetVertexId (void) const;
+
+/**
+ * @brief Set the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents. Typically, this is the Router ID for SPFVertex objects
+ * representing routers, and comes from the Link State Advertisement of a
+ * router aggregated to a node in the simulation. These IDs are allocated
+ * automatically by the routing environment and look like IP addresses
+ * beginning at 0.0.0.0 and monotonically increase as new routers are
+ * instantiated. This method is an explicit override of the automatically
+ * generated value.
+ *
+ * @param id The new Ipv4Address Vertex ID for the current SPFVertex object.
+ */
+ void SetVertexId (Ipv4Address id);
+
+/**
+ * @brief Get the Global Router Link State Advertisement returned by the
+ * Global Router represented by this SPFVertex during the route discovery
+ * process.
+ * @internal
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @returns A pointer to the GlobalRoutingLSA found by the router represented
+ * by this SPFVertex object.
+ */
+ GlobalRoutingLSA* GetLSA (void) const;
+
+/**
+ * @brief Set the Global Router Link State Advertisement returned by the
+ * Global Router represented by this SPFVertex during the route discovery
+ * process.
+ * @internal
+ *
+ * @see SPFVertex::GetLSA ()
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You
+ * must not delete the LSA after calling this method.
+ * @param lsa A pointer to the GlobalRoutingLSA.
+ */
+ void SetLSA (GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Get the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object. When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes. Each of these
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root. The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * The distance is calculated during route discovery and is stored in a
+ * member variable. This method simply fetches that value.
+ *
+ * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex.
+ */
+ uint32_t GetDistanceFromRoot (void) const;
+
+/**
+ * @brief Set the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object. When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes. Each of these
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root. The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * @param distance The distance, in hops, from the root SPFVertex to "this"
+ * SPFVertex.
+ */
+ void SetDistanceFromRoot (uint32_t distance);
+
+/**
+ * @brief Get the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter. These interfaces are used to
+ * forward packets off of the root's network down those links. As other
+ * vertices are discovered which are further away from the root, they will
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which of my local interfaces
+ * should I use to get a packet to the network or host represented by 'this'
+ * SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The interface index to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+ uint32_t GetOutgoingInterfaceId (void) const;
+
+/**
+ * @brief Set the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter. These interfaces are used to
+ * forward packets off of the root's network down those links. As other
+ * vertices are discovered which are further away from the root, they will
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, we are letting the root node know which of its local
+ * interfaces it should use to get a packet to the network or host represented
+ * by "this" SPFVertex.
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param id The interface index to use when forwarding packets to the host or
+ * network represented by "this" SPFVertex.
+ */
+ void SetOutgoingInterfaceId (uint32_t id);
+
+/**
+ * @brief Get the IP address that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The IP address that we're asking for is the address on the
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter. This
+ * address is used to forward packets off of the root's network down those
+ * links. As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which router should I send a
+ * packet to in order to get that packet to the network or host represented
+ * by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+ Ipv4Address GetNextHop (void) const;
+
+/**
+ * @brief Set the IP address that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set. The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from
+ * the root. The IP address that we're asking for is the address on the
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter. This
+ * address is used to forward packets off of the root's network down those
+ * links. As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ *
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface. This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices. We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method we are telling the root node which router it should send
+ * should I send a packet to in order to get that packet to the network or
+ * host represented by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param nextHop The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+ void SetNextHop (Ipv4Address nextHop);
+
+/**
+ * @brief Get a pointer to the SPFVector that is the parent of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method returns a pointer to the parent node of "this" SPFVertex
+ * (both of which reside in that SPF tree).
+ *
+ * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex
+ * in the SPF tree.
+ */
+ SPFVertex* GetParent (void) const;
+
+/**
+ * @brief Set the pointer to the SPFVector that is the parent of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method sets the parent pointer of "this" SPFVertex (both of which
+ * reside in that SPF tree).
+ *
+ * @param parent A pointer to the SPFVertex that is the parent of "this"
+ * SPFVertex* in the SPF tree.
+ */
+ void SetParent (SPFVertex* parent);
+
+/**
+ * @brief Get the number of children of "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree. Each vertex
+ * in the SPF tree can have a number of children that represent host or
+ * network routes available via that vertex.
+ *
+ * This method returns the number of children of "this" SPFVertex (which
+ * reside in the SPF tree).
+ *
+ * @returns The number of children of "this" SPFVertex (which reside in the
+ * SPF tree).
+ */
+ uint32_t GetNChildren (void) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree. Each vertex
+ * in the SPF tree can have a number of children that represent host or
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @param n The index (from 0 to the number of children minus 1) of the
+ * child SPFVertex to return.
+ * @warning The pointer returned by GetChild () is a borrowed pointer. You
+ * do not have any ownership of the underlying object and must not delete
+ * that object.
+ * @returns A pointer to the specified child SPFVertex (which resides in the
+ * SPF tree).
+ */
+ SPFVertex* GetChild (uint32_t n) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this"
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree. Each vertex
+ * in the SPF tree can have a number of children that represent host or
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @warning Ownership of the pointer added to the children of "this"
+ * SPFVertex is transferred to the "this" SPFVertex. You must not delete the
+ * (now) child SPFVertex after calling this method.
+ * @param child A pointer to the SPFVertex (which resides in the SPF tree) to
+ * be added to the list of children of "this" SPFVertex.
+ * @returns The number of children of "this" SPFVertex after the addition of
+ * the new child.
+ */
+ uint32_t AddChild (SPFVertex* child);
+
+private:
+ VertexType m_vertexType;
+ Ipv4Address m_vertexId;
+ GlobalRoutingLSA* m_lsa;
+ uint32_t m_distanceFromRoot;
+ uint32_t m_rootOif;
+ Ipv4Address m_nextHop;
+ SPFVertex* m_parent;
+ typedef std::list<SPFVertex*> ListOfSPFVertex_t;
+ ListOfSPFVertex_t m_children;
+
+/**
+ * @brief The SPFVertex copy construction is disallowed. There's no need for
+ * it and a compiler provided shallow copy would be wrong.
+ */
+ SPFVertex (SPFVertex& v);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ SPFVertex& operator= (SPFVertex& v);
+};
+
+/**
+ * @brief The Link State DataBase (LSDB) of the Global Route Manager.
+ *
+ * Each node in the simulation participating in global routing has a
+ * GlobalRouter interface. The primary job of this interface is to export
+ * Global Router Link State Advertisements (LSAs). These advertisements in
+ * turn contain a number of Global Router Link Records that describe the
+ * point to point links from the underlying node to other nodes (that will
+ * also export their own LSAs.
+ *
+ * This class implements a searchable database of LSAs gathered from every
+ * router in the simulation.
+ */
+class GlobalRouteManagerLSDB
+{
+public:
+/**
+ * @brief Construct an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map composing the Link State Database is initialized in
+ * this constructor.
+ */
+ GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Destroy an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map is walked and all of the Link State Advertisements stored
+ * in the database are freed; then the database map itself is clear ()ed to
+ * release any remaining resources.
+ */
+ ~GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Insert an IP address / Link State Advertisement pair into the Link
+ * State Database.
+ * @internal
+ *
+ * The IPV4 address and the GlobalRoutingLSA given as parameters are converted
+ * to an STL pair and are inserted into the database map.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA. Typically the Router
+ * ID.
+ * @param lsa A pointer to the Link State Advertisement for the router.
+ */
+ void Insert(Ipv4Address addr, GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address).
+ * @internal
+ *
+ * The database map is searched for the given IPV4 address and corresponding
+ * GlobalRoutingLSA is returned.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA. Typically the Router
+ * ID.
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ */
+ GlobalRoutingLSA* GetLSA (Ipv4Address addr) const;
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address). This is a variation of the GetLSA call
+ * to allow the LSA to be found by matching addr with the LinkData field
+ * of the TransitNetwork link record.
+ * @internal
+ *
+ * @see GetLSA
+ * @param addr The IP address associated with the LSA. Typically the Router
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ * ID.
+ */
+ GlobalRoutingLSA* GetLSAByLinkData (Ipv4Address addr) const;
+
+/**
+ * @brief Set all LSA flags to an initialized state, for SPF computation
+ * @internal
+ *
+ * This function walks the database and resets the status flags of all of the
+ * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done
+ * prior to each SPF calculation to reset the state of the SPFVertex structures
+ * that will reference the LSAs during the calculation.
+ *
+ * @see GlobalRoutingLSA
+ * @see SPFVertex
+ */
+ void Initialize ();
+
+private:
+ typedef std::map<Ipv4Address, GlobalRoutingLSA*> LSDBMap_t;
+ typedef std::pair<Ipv4Address, GlobalRoutingLSA*> LSDBPair_t;
+
+ LSDBMap_t m_database;
+/**
+ * @brief GlobalRouteManagerLSDB copy construction is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ GlobalRouteManagerLSDB (GlobalRouteManagerLSDB& lsdb);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ GlobalRouteManagerLSDB& operator= (GlobalRouteManagerLSDB& lsdb);
+};
+
+/**
+ * @brief A global router implementation.
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface. For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers,
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManagerImpl
+{
+public:
+ GlobalRouteManagerImpl ();
+ virtual ~GlobalRouteManagerImpl ();
+/**
+ * @brief Select which nodes in the system are to be router nodes and
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+ virtual void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ */
+ virtual void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+ virtual void InitializeRoutes ();
+
+/**
+ * @brief Debugging routine; allow client code to supply a pre-built LSDB
+ * @internal
+ */
+ void DebugUseLsdb (GlobalRouteManagerLSDB*);
+
+/**
+ * @brief Debugging routine; call the core SPF from the unit tests
+ * @internal
+ */
+ void DebugSPFCalculate (Ipv4Address root);
+
+private:
+/**
+ * @brief GlobalRouteManagerImpl copy construction is disallowed.
+ * There's no need for it and a compiler provided shallow copy would be
+ * wrong.
+ */
+ GlobalRouteManagerImpl (GlobalRouteManagerImpl& srmi);
+
+/**
+ * @brief Global Route Manager Implementation assignment operator is
+ * disallowed. There's no need for it and a compiler provided shallow copy
+ * would be hopelessly wrong.
+ */
+ GlobalRouteManagerImpl& operator= (GlobalRouteManagerImpl& srmi);
+
+ SPFVertex* m_spfroot;
+ GlobalRouteManagerLSDB* m_lsdb;
+ void SPFCalculate (Ipv4Address root);
+ void SPFNext (SPFVertex*, CandidateQueue&);
+ int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w,
+ GlobalRoutingLinkRecord* l, uint32_t distance);
+ void SPFVertexAddParent (SPFVertex* v);
+ GlobalRoutingLinkRecord* SPFGetNextLink (SPFVertex* v, SPFVertex* w,
+ GlobalRoutingLinkRecord* prev_link);
+ void SPFIntraAddRouter (SPFVertex* v);
+ void SPFIntraAddTransit (SPFVertex* v);
+ uint32_t FindOutgoingInterfaceId (Ipv4Address a);
+ uint32_t FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_IMPL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include "ns3/assert.h"
+#include "ns3/debug.h"
+#include "ns3/simulation-singleton.h"
+#include "global-route-manager.h"
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManager Implementation
+//
+// ---------------------------------------------------------------------------
+
+ void
+GlobalRouteManager::PopulateRoutingTables ()
+{
+ SelectRouterNodes ();
+ BuildGlobalRoutingDatabase ();
+ InitializeRoutes ();
+}
+
+ void
+GlobalRouteManager::SelectRouterNodes ()
+{
+ SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+ SelectRouterNodes ();
+}
+
+ void
+GlobalRouteManager::BuildGlobalRoutingDatabase ()
+{
+ SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+ BuildGlobalRoutingDatabase ();
+}
+
+ void
+GlobalRouteManager::InitializeRoutes ()
+{
+ SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+ InitializeRoutes ();
+}
+
+ uint32_t
+GlobalRouteManager::AllocateRouterId ()
+{
+ static uint32_t routerId = 0;
+ return routerId++;
+}
+
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_H
+#define GLOBAL_ROUTE_MANAGER_H
+
+namespace ns3 {
+
+/**
+ * @brief A global global router
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface. For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers,
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManager
+{
+public:
+/**
+ * @brief Build a routing database and initialize the routing tables of
+ * the nodes in the simulation.
+ *
+ * All this function does is call BuildGlobalRoutingDatabase () and
+ * InitializeRoutes ().
+ *
+ * @see BuildGlobalRoutingDatabase ();
+ * @see InitializeRoutes ();
+ */
+ static void PopulateRoutingTables ();
+
+/**
+ * @brief Allocate a 32-bit router ID from monotonically increasing counter.
+ */
+ static uint32_t AllocateRouterId ();
+
+private:
+/**
+ * @brief Select which nodes in the system are to be router nodes and
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+ static void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ *
+ */
+ static void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+ static void InitializeRoutes ();
+
+/**
+ * @brief Global Route Manager copy construction is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ *
+ */
+ GlobalRouteManager (GlobalRouteManager& srm);
+
+/**
+ * @brief Global Router copy assignment operator is disallowed. There's no
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+ GlobalRouteManager& operator= (GlobalRouteManager& srm);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.cc Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,821 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include "ns3/debug.h"
+#include "ns3/assert.h"
+#include "ns3/channel.h"
+#include "ns3/net-device.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("GlobalRouter");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLinkRecord Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ()
+:
+ m_linkId ("0.0.0.0"),
+ m_linkData ("0.0.0.0"),
+ m_linkType (Unknown),
+ m_metric (0)
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ()");
+}
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord (
+ LinkType linkType,
+ Ipv4Address linkId,
+ Ipv4Address linkData,
+ uint32_t metric)
+:
+ m_linkId (linkId),
+ m_linkData (linkData),
+ m_linkType (linkType),
+ m_metric (metric)
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::GlobalRoutingLinkRecord (" <<
+ linkType << ", " << linkId << ", " << linkData << ", " << metric << ")");
+}
+
+GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord ()
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord ()");
+}
+
+ Ipv4Address
+GlobalRoutingLinkRecord::GetLinkId (void) const
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::GetLinkId ()");
+ return m_linkId;
+}
+
+ void
+GlobalRoutingLinkRecord::SetLinkId (Ipv4Address addr)
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::SetLinkId ()");
+ m_linkId = addr;
+}
+
+ Ipv4Address
+GlobalRoutingLinkRecord::GetLinkData (void) const
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::GetLinkData ()");
+ return m_linkData;
+}
+
+ void
+GlobalRoutingLinkRecord::SetLinkData (Ipv4Address addr)
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::SetLinkData ()");
+ m_linkData = addr;
+}
+
+ GlobalRoutingLinkRecord::LinkType
+GlobalRoutingLinkRecord::GetLinkType (void) const
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::GetLinkType ()");
+ return m_linkType;
+}
+
+ void
+GlobalRoutingLinkRecord::SetLinkType (
+ GlobalRoutingLinkRecord::LinkType linkType)
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::SetLinkType ()");
+ m_linkType = linkType;
+}
+
+ uint32_t
+GlobalRoutingLinkRecord::GetMetric (void) const
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::GetMetric ()");
+ return m_metric;
+}
+
+ void
+GlobalRoutingLinkRecord::SetMetric (uint32_t metric)
+{
+ NS_DEBUG("GlobalRoutingLinkRecord::SetMetric ()");
+ m_metric = metric;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLSA Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLSA::GlobalRoutingLSA()
+ :
+ m_lsType (GlobalRoutingLSA::Unknown),
+ m_linkStateId("0.0.0.0"),
+ m_advertisingRtr("0.0.0.0"),
+ m_linkRecords(),
+ m_networkLSANetworkMask("0.0.0.0"),
+ m_attachedRouters(),
+ m_status(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+{
+ NS_DEBUG("GlobalRoutingLSA::GlobalRoutingLSA ()");
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (
+ GlobalRoutingLSA::SPFStatus status,
+ Ipv4Address linkStateId,
+ Ipv4Address advertisingRtr)
+:
+ m_lsType (GlobalRoutingLSA::Unknown),
+ m_linkStateId(linkStateId),
+ m_advertisingRtr(advertisingRtr),
+ m_linkRecords(),
+ m_networkLSANetworkMask("0.0.0.0"),
+ m_attachedRouters(),
+ m_status(status)
+{
+ NS_DEBUG("GlobalRoutingLSA::GlobalRoutingLSA (" << status << ", " <<
+ linkStateId << ", " << advertisingRtr << ")");
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (GlobalRoutingLSA& lsa)
+ : m_lsType(lsa.m_lsType), m_linkStateId(lsa.m_linkStateId),
+ m_advertisingRtr(lsa.m_advertisingRtr),
+ m_networkLSANetworkMask(lsa.m_networkLSANetworkMask),
+ m_status(lsa.m_status)
+{
+ NS_ASSERT_MSG(IsEmpty(),
+ "GlobalRoutingLSA::GlobalRoutingLSA (): Non-empty LSA in constructor");
+ CopyLinkRecords (lsa);
+}
+
+ GlobalRoutingLSA&
+GlobalRoutingLSA::operator= (const GlobalRoutingLSA& lsa)
+{
+ m_lsType = lsa.m_lsType;
+ m_linkStateId = lsa.m_linkStateId;
+ m_advertisingRtr = lsa.m_advertisingRtr;
+ m_networkLSANetworkMask = lsa.m_networkLSANetworkMask,
+ m_status = lsa.m_status;
+
+ ClearLinkRecords ();
+ CopyLinkRecords (lsa);
+ return *this;
+}
+
+ void
+GlobalRoutingLSA::CopyLinkRecords (const GlobalRoutingLSA& lsa)
+{
+ for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin ();
+ i != lsa.m_linkRecords.end ();
+ i++)
+ {
+ GlobalRoutingLinkRecord *pSrc = *i;
+ GlobalRoutingLinkRecord *pDst = new GlobalRoutingLinkRecord;
+
+ pDst->SetLinkType (pSrc->GetLinkType ());
+ pDst->SetLinkId (pSrc->GetLinkId ());
+ pDst->SetLinkData (pSrc->GetLinkData ());
+
+ m_linkRecords.push_back(pDst);
+ pDst = 0;
+ }
+
+ m_attachedRouters = lsa.m_attachedRouters;
+}
+
+GlobalRoutingLSA::~GlobalRoutingLSA()
+{
+ NS_DEBUG("GlobalRoutingLSA::~GlobalRoutingLSA ()");
+ ClearLinkRecords ();
+}
+
+ void
+GlobalRoutingLSA::ClearLinkRecords(void)
+{
+ for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin ();
+ i != m_linkRecords.end ();
+ i++)
+ {
+ NS_DEBUG("GlobalRoutingLSA::ClearLinkRecords (): free link record");
+
+ GlobalRoutingLinkRecord *p = *i;
+ delete p;
+ p = 0;
+
+ *i = 0;
+ }
+ NS_DEBUG("GlobalRoutingLSA::ClearLinkRecords(): clear list");
+ m_linkRecords.clear();
+}
+
+ uint32_t
+GlobalRoutingLSA::AddLinkRecord (GlobalRoutingLinkRecord* lr)
+{
+ m_linkRecords.push_back (lr);
+ return m_linkRecords.size ();
+}
+
+ uint32_t
+GlobalRoutingLSA::GetNLinkRecords (void) const
+{
+ return m_linkRecords.size ();
+}
+
+ GlobalRoutingLinkRecord *
+GlobalRoutingLSA::GetLinkRecord (uint32_t n) const
+{
+ uint32_t j = 0;
+ for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+ i != m_linkRecords.end ();
+ i++, j++)
+ {
+ if (j == n)
+ {
+ return *i;
+ }
+ }
+ NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetLinkRecord (): invalid index");
+ return 0;
+}
+
+ bool
+GlobalRoutingLSA::IsEmpty (void) const
+{
+ return m_linkRecords.size () == 0;
+}
+
+ GlobalRoutingLSA::LSType
+GlobalRoutingLSA::GetLSType (void) const
+{
+ return m_lsType;
+}
+
+ void
+GlobalRoutingLSA::SetLSType (GlobalRoutingLSA::LSType typ)
+{
+ m_lsType = typ;
+}
+
+ Ipv4Address
+GlobalRoutingLSA::GetLinkStateId (void) const
+{
+ return m_linkStateId;
+}
+
+ void
+GlobalRoutingLSA::SetLinkStateId (Ipv4Address addr)
+{
+ m_linkStateId = addr;
+}
+
+ Ipv4Address
+GlobalRoutingLSA::GetAdvertisingRouter (void) const
+{
+ return m_advertisingRtr;
+}
+
+ void
+GlobalRoutingLSA::SetAdvertisingRouter (Ipv4Address addr)
+{
+ m_advertisingRtr = addr;
+}
+
+ void
+GlobalRoutingLSA::SetNetworkLSANetworkMask (Ipv4Mask mask)
+{
+ m_networkLSANetworkMask = mask;
+}
+
+ Ipv4Mask
+GlobalRoutingLSA::GetNetworkLSANetworkMask (void) const
+{
+ return m_networkLSANetworkMask;
+}
+
+ GlobalRoutingLSA::SPFStatus
+GlobalRoutingLSA::GetStatus (void) const
+{
+ return m_status;
+}
+
+ uint32_t
+GlobalRoutingLSA::AddAttachedRouter (Ipv4Address addr)
+{
+ m_attachedRouters.push_back (addr);
+ return m_attachedRouters.size ();
+}
+
+ uint32_t
+GlobalRoutingLSA::GetNAttachedRouters (void) const
+{
+ return m_attachedRouters.size ();
+}
+
+ Ipv4Address
+GlobalRoutingLSA::GetAttachedRouter (uint32_t n) const
+{
+ uint32_t j = 0;
+ for ( ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin ();
+ i != m_attachedRouters.end ();
+ i++, j++)
+ {
+ if (j == n)
+ {
+ return *i;
+ }
+ }
+ NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
+ return Ipv4Address("0.0.0.0");
+}
+
+ void
+GlobalRoutingLSA::SetStatus (GlobalRoutingLSA::SPFStatus status)
+{
+ m_status = status;
+}
+
+ void
+GlobalRoutingLSA::Print (std::ostream &os) const
+{
+ os << "m_lsType = " << m_lsType << std::endl <<
+ "m_linkStateId = " << m_linkStateId << std::endl <<
+ "m_advertisingRtr = " << m_advertisingRtr << std::endl;
+
+ if (m_lsType == GlobalRoutingLSA::RouterLSA)
+ {
+ for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+ i != m_linkRecords.end ();
+ i++)
+ {
+ GlobalRoutingLinkRecord *p = *i;
+ os << "----------" << std::endl;
+ os << "m_linkId = " << p->GetLinkId () << std::endl;
+ os << "m_linkData = " << p->GetLinkData () << std::endl;
+ }
+ }
+ else if (m_lsType == GlobalRoutingLSA::NetworkLSA)
+ {
+ os << "----------" << std::endl;
+ os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask
+ << std::endl;
+ for ( ListOfAttachedRouters_t::const_iterator i =
+ m_attachedRouters.begin ();
+ i != m_attachedRouters.end ();
+ i++)
+ {
+ Ipv4Address p = *i;
+ os << "attachedRouter = " << p << std::endl;
+ }
+ }
+ else
+ {
+ NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType);
+ }
+}
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa)
+{
+ lsa.Print (os);
+ return os;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouter Implementation
+//
+// ---------------------------------------------------------------------------
+
+const InterfaceId GlobalRouter::iid =
+ MakeInterfaceId ("GlobalRouter", Object::iid);
+
+GlobalRouter::GlobalRouter (Ptr<Node> node)
+ : m_node(node), m_LSAs()
+{
+ NS_DEBUG("GlobalRouter::GlobalRouter ()");
+ SetInterfaceId (GlobalRouter::iid);
+ m_routerId.Set(GlobalRouteManager::AllocateRouterId ());
+}
+
+GlobalRouter::~GlobalRouter ()
+{
+ NS_DEBUG("GlobalRouter::~GlobalRouter ()");
+ ClearLSAs();
+}
+
+void
+GlobalRouter::DoDispose ()
+{
+ m_node = 0;
+ Object::DoDispose ();
+}
+
+ void
+GlobalRouter::ClearLSAs ()
+{
+ NS_DEBUG("GlobalRouter::ClearLSAs ()");
+
+ for ( ListOfLSAs_t::iterator i = m_LSAs.begin ();
+ i != m_LSAs.end ();
+ i++)
+ {
+ NS_DEBUG("GlobalRouter::ClearLSAs (): free LSA");
+
+ GlobalRoutingLSA *p = *i;
+ delete p;
+ p = 0;
+
+ *i = 0;
+ }
+ NS_DEBUG("GlobalRouter::ClearLSAs (): clear list");
+ m_LSAs.clear();
+}
+
+ Ipv4Address
+GlobalRouter::GetRouterId (void) const
+{
+ return m_routerId;
+}
+
+//
+// Go out and discover any adjacent routers and build the Link State
+// Advertisements that reflect them and their associated networks.
+//
+ uint32_t
+GlobalRouter::DiscoverLSAs (void)
+{
+ NS_DEBUG("GlobalRouter::DiscoverLSAs () for node " << m_node->GetId () );
+ NS_ASSERT_MSG(m_node,
+ "GlobalRouter::DiscoverLSAs (): <Node> interface not set");
+
+ ClearLSAs ();
+
+// While building the router-LSA, keep a list of those NetDevices for
+// which I am the designated router and need to later build a NetworkLSA
+ std::list<Ptr<NetDevice> > listOfDRInterfaces;
+
+//
+// We're aggregated to a node. We need to ask the node for a pointer to its
+// Ipv4 interface. This is where the information regarding the attached
+// interfaces lives.
+//
+ Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG(ipv4Local,
+ "GlobalRouter::DiscoverLSAs (): QI for <Ipv4> interface failed");
+//
+// Each node originates a Router-LSA
+//
+ GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+ pLSA->SetLSType (GlobalRoutingLSA::RouterLSA);
+ pLSA->SetLinkStateId (m_routerId);
+ pLSA->SetAdvertisingRouter (m_routerId);
+ pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+//
+// We need to ask the node for the number of net devices attached. This isn't
+// necessarily equal to the number of links to adjacent nodes (other routers)
+// as the number of devices may include those for stub networks (e.g.,
+// ethernets, etc.).
+//
+ uint32_t numDevices = m_node->GetNDevices();
+ NS_DEBUG("GlobalRouter::DiscoverLSAs (): numDevices = " << numDevices);
+ for (uint32_t i = 0; i < numDevices; ++i)
+ {
+ Ptr<NetDevice> ndLocal = m_node->GetDevice(i);
+
+ if (ndLocal->IsBroadcast () && !ndLocal->IsPointToPoint () )
+ {
+ NS_DEBUG("GlobalRouter::DiscoverLSAs (): broadcast link");
+ GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+//
+// We need to determine whether we are on a transit or stub network
+// If we find at least one more router on this channel, we are a transit
+//
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we
+// just found. This is still the IP on the local side of the channel. There
+// is a function to do this used down in the guts of the stack, but it's not
+// exported so we had to whip up an equivalent.
+//
+ uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+ NS_DEBUG("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of
+// the point-to-point channel we now know we have. This is where our adjacent
+// router (to use OSPF lingo) is running.
+//
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ uint32_t nDevices = ch->GetNDevices();
+ if (nDevices == 1)
+ {
+ // This is a stub broadcast interface
+ NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA stub broadcast link");
+ // XXX in future, need to consider if >1 includes other routers
+ plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+ // Link ID is IP network number of attached network
+ plr->SetLinkId (addrLocal.CombineMask(maskLocal));
+ // Link Data is network mask; convert to Ipv4Address
+ Ipv4Address maskLocalAddr;
+ maskLocalAddr.Set(maskLocal.GetHostOrder ());
+ plr->SetLinkData (maskLocalAddr);
+ // Cost is interface's configured output cost (NOTYET)
+ plr->SetMetric (1);
+ pLSA->AddLinkRecord(plr);
+ plr = 0;
+ continue;
+ }
+ else
+ {
+ NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA Broadcast link");
+ // multiple routers on a broadcast interface
+ // lowest IP address is designated router
+ plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork);
+ // Link ID is IP interface address of designated router
+ Ipv4Address desigRtr =
+ FindDesignatedRouterForLink (m_node, ndLocal);
+ if (desigRtr == addrLocal)
+ {
+ listOfDRInterfaces.push_back (ndLocal);
+ NS_DEBUG("GlobalRouter::DiscoverLSAs (): " <<
+ m_node->GetId () << " is a DR");
+ }
+ plr->SetLinkId (desigRtr);
+ // Link Data is router's own IP address
+ plr->SetLinkData (addrLocal);
+ // Cost is interface's configured output cost (NOTYET)
+ plr->SetMetric (1);
+ pLSA->AddLinkRecord (plr);
+ plr = 0;
+ continue;
+ }
+ }
+ else if (ndLocal->IsPointToPoint () )
+ {
+ NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA Point-to-point device");
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we
+// just found. This is still the IP on the local side of the channel. There
+// is a function to do this used down in the guts of the stack, but it's not
+// exported so we had to whip up an equivalent.
+//
+ uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+//
+// Now that we have the Ipv4 interface index, we can get the address and mask
+// we need.
+//
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+ NS_DEBUG("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of
+// the point-to-point channel we now know we have. This is where our adjacent
+// router (to use OSPF lingo) is running.
+//
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
+//
+// The adjacent net device is aggregated to a node. We need to ask that net
+// device for its node, then ask that node for its Ipv4 interface.
+//
+ Ptr<Node> nodeRemote = ndRemote->GetNode();
+ Ptr<Ipv4> ipv4Remote = nodeRemote->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG(ipv4Remote,
+ "GlobalRouter::DiscoverLSAs (): QI for remote <Ipv4> failed");
+//
+// Per the OSPF spec, we're going to need the remote router ID, so we might as
+// well get it now.
+//
+ Ptr<GlobalRouter> srRemote =
+ nodeRemote->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+ NS_ASSERT_MSG(srRemote,
+ "GlobalRouter::DiscoverLSAs():QI for remote <GlobalRouter> failed");
+ Ipv4Address rtrIdRemote = srRemote->GetRouterId();
+ NS_DEBUG("Working with remote router " << rtrIdRemote);
+//
+// Now, just like we did above, we need to get the IP interface index for the
+// net device on the other end of the point-to-point channel.
+//
+ uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote);
+//
+// Now that we have the Ipv4 interface, we can get the (remote) address and
+// mask we need.
+//
+ Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote);
+ Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote);
+ NS_DEBUG("Working with remote address " << addrRemote);
+//
+// Now we can fill out the link records for this link. There are always two
+// link records; the first is a point-to-point record describing the link and
+// the second is a stub network record with the network number.
+//
+ GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+ plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint);
+ plr->SetLinkId (rtrIdRemote);
+ plr->SetLinkData (addrLocal);
+ pLSA->AddLinkRecord (plr);
+ plr = 0;
+
+ plr = new GlobalRoutingLinkRecord;
+ plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+ plr->SetLinkId (addrRemote);
+ plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown
+ pLSA->AddLinkRecord (plr);
+ plr = 0;
+ }
+ else
+ {
+ NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type");
+ }
+
+ }
+//
+// The LSA goes on a list of LSAs in case we want to begin exporting other
+// kinds of advertisements (than Router LSAs).
+ m_LSAs.push_back (pLSA);
+ NS_DEBUG(*pLSA);
+
+
+// Now, determine whether we need to build a NetworkLSA
+ if (listOfDRInterfaces.size () > 0)
+ {
+ for (std::list<Ptr<NetDevice> >::iterator i = listOfDRInterfaces.begin ();
+ i != listOfDRInterfaces.end (); i++)
+ {
+// Build one NetworkLSA for each interface that is a DR
+ Ptr<NetDevice> ndLocal = *i;
+ uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+ GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+ pLSA->SetLSType (GlobalRoutingLSA::NetworkLSA);
+ pLSA->SetLinkStateId (addrLocal);
+ pLSA->SetAdvertisingRouter (m_routerId);
+ pLSA->SetNetworkLSANetworkMask (maskLocal);
+ pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+// Build list of AttachedRouters
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ uint32_t nDevices = ch->GetNDevices();
+ NS_ASSERT (nDevices);
+ for (uint32_t i = 0; i < nDevices; i++)
+ {
+ Ptr<NetDevice> tempNd = ch->GetDevice (i);
+ NS_ASSERT (tempNd);
+ Ptr<Node> tempNode = tempNd->GetNode ();
+ uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+ Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT (tempIpv4);
+ Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+ pLSA->AddAttachedRouter (tempAddr);
+ }
+ m_LSAs.push_back (pLSA);
+ NS_DEBUG(*pLSA);
+ }
+ }
+
+ return m_LSAs.size ();
+}
+
+ Ipv4Address
+GlobalRouter::FindDesignatedRouterForLink (Ptr<Node> node,
+ Ptr<NetDevice> ndLocal) const
+{
+ uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
+ Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT (ipv4Local);
+ Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+ Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+ Ptr<Channel> ch = ndLocal->GetChannel();
+ uint32_t nDevices = ch->GetNDevices();
+ NS_ASSERT (nDevices);
+ Ipv4Address lowest = addrLocal;
+ // iterate all NetDevices and return the lowest numbered IP address
+ for (uint32_t i = 0; i < nDevices; i++)
+ {
+ Ptr<NetDevice> tempNd = ch->GetDevice (i);
+ NS_ASSERT (tempNd);
+ Ptr<Node> tempNode = tempNd->GetNode ();
+ uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+ Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT (tempIpv4);
+ Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+ if (tempAddr < addrLocal)
+ {
+ addrLocal = tempAddr;
+ }
+ }
+ return addrLocal;
+}
+
+ uint32_t
+GlobalRouter::GetNumLSAs (void) const
+{
+ NS_DEBUG("GlobalRouter::GetNumLSAs ()");
+ return m_LSAs.size ();
+}
+
+//
+// Get the nth link state advertisement from this router.
+//
+ bool
+GlobalRouter::GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const
+{
+ NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA");
+//
+// All of the work was done in GetNumLSAs. All we have to do here is to
+// walk the list of link state advertisements created there and return the
+// one the client is interested in.
+//
+ ListOfLSAs_t::const_iterator i = m_LSAs.begin ();
+ uint32_t j = 0;
+
+ for (; i != m_LSAs.end (); i++, j++)
+ {
+ if (j == n)
+ {
+ GlobalRoutingLSA *p = *i;
+ lsa = *p;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Link through the given channel and find the net device that's on the
+// other end. This only makes sense with a point-to-point channel.
+//
+ Ptr<NetDevice>
+GlobalRouter::GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const
+{
+
+ NS_ASSERT_MSG(ch->GetNDevices() == 2,
+ "GlobalRouter::GetAdjacent (): Channel with other than two devices");
+//
+// This is a point to point channel with two endpoints. Get both of them.
+//
+ Ptr<NetDevice> nd1 = ch->GetDevice(0);
+ Ptr<NetDevice> nd2 = ch->GetDevice(1);
+//
+// One of the endpoints is going to be "us" -- that is the net device attached
+// to the node on which we're running -- i.e., "nd". The other endpoint (the
+// one to which we are connected via the channel) is the adjacent router.
+//
+ if (nd1 == nd)
+ {
+ return nd2;
+ }
+ else if (nd2 == nd)
+ {
+ return nd1;
+ }
+ else
+ {
+ NS_ASSERT_MSG(false,
+ "GlobalRouter::GetAdjacent (): Wrong or confused channel?");
+ return 0;
+ }
+}
+
+//
+// Given a node and a net device, find the IPV4 interface index that
+// corresponds to that net device.
+//
+ uint32_t
+GlobalRouter::FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const
+{
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_ASSERT_MSG(ipv4, "QI for <Ipv4> interface failed");
+ for (uint32_t i = 0; i < ipv4->GetNInterfaces(); ++i )
+ {
+ if (ipv4->GetNetDevice(i) == nd)
+ {
+ return i;
+ }
+ }
+
+ NS_ASSERT_MSG(0, "Cannot find interface for device");
+ return 0;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.h Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,667 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef GLOBAL_ROUTER_INTERFACE_H
+#define GLOBAL_ROUTER_INTERFACE_H
+
+#include <stdint.h>
+#include <list>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/global-route-manager.h"
+
+namespace ns3 {
+
+/**
+ * @brief A single link record for a link state advertisement.
+ *
+ * The GlobalRoutingLinkRecord is modeled after the OSPF link record field of
+ * a Link State Advertisement. Right now we will only see two types of link
+ * records corresponding to a stub network and a point-to-point link (channel).
+ */
+class GlobalRoutingLinkRecord
+{
+public:
+/**
+ * @enum LinkType
+ * @brief Enumeration of the possible types of Global Routing Link Records.
+ *
+ * These values are defined in the OSPF spec. We currently only use
+ * PointToPoint and StubNetwork types.
+ */
+ enum LinkType {
+ Unknown = 0, /**< Uninitialized Link Record */
+ PointToPoint, /**< Record representing a point to point channel */
+ TransitNetwork, /**< Unused -- for future OSPF compatibility */
+ StubNetwork, /**< Record represents a leaf node network */
+ VirtualLink /**< Unused -- for future OSPF compatibility */
+ };
+
+/**
+ * @brief Construct an empty ("uninitialized") Global Routing Link Record.
+ *
+ * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0";
+ * The Link Type is set to Unknown;
+ * The metric is set to 0.
+ */
+ GlobalRoutingLinkRecord ();
+
+/**
+ * Construct an initialized Global Routing Link Record.
+ *
+ * @param linkType The type of link record to construct.
+ * @param linkId The link ID for the record.
+ * @param linkData The link data field for the record.
+ * @param metric The metric field for the record.
+ * @see LinkType
+ * @see SetLinkId
+ * @see SetLinkData
+ */
+ GlobalRoutingLinkRecord (
+ LinkType linkType,
+ Ipv4Address linkId,
+ Ipv4Address linkData,
+ uint32_t metric);
+
+/**
+ * @brief Destroy a Global Routing Link Record.
+ *
+ * Currently does nothing. Here as a placeholder only.
+ */
+ ~GlobalRoutingLinkRecord ();
+
+/**
+ * Get the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent
+ * neighbor's IP address
+ *
+ * @returns The Ipv4Address corresponding to the Link ID field of the record.
+ */
+ Ipv4Address GetLinkId(void) const;
+
+/**
+ * @brief Set the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent
+ * neighbor's IP address
+ *
+ * @param addr An Ipv4Address to store in the Link ID field of the record.
+ */
+ void SetLinkId(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data will be the
+ * network mask
+ *
+ * @returns The Ipv4Address corresponding to the Link Data field of the record.
+ */
+ Ipv4Address GetLinkData(void) const;
+
+/**
+ * @brief Set the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the
+ * network mask
+ *
+ * @param addr An Ipv4Address to store in the Link Data field of the record.
+ */
+ void SetLinkData(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents. The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @returns The LinkType of the current Global Routing Link Record.
+ */
+ LinkType GetLinkType(void) const;
+
+/**
+ * @brief Set the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents. The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @param linkType The new LinkType for the current Global Routing Link Record.
+ */
+ void SetLinkType(LinkType linkType);
+
+/**
+ * @brief Get the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link. A sum of metrics must have a well-defined meaning. That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @returns The metric field of the Global Routing Link Record.
+ */
+ uint32_t GetMetric(void) const;
+
+/**
+ * @brief Set the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link. A sum of metrics must have a well-defined meaning. That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @param metric The new metric for the current Global Routing Link Record.
+ */
+ void SetMetric(uint32_t metric);
+
+private:
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings
+ * depending on the type of link a given link records represents. They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkId to Router ID of
+ * neighboring router.
+ *
+ * For Type 3 link (Stub), set m_linkId to neighbor's IP address
+ */
+ Ipv4Address m_linkId;
+
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings
+ * depending on the type of link a given link records represents. They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkData to local IP address
+ *
+ * For Type 3 link (Stub), set m_linkData to mask
+ */
+ Ipv4Address m_linkData; // for links to RouterLSA,
+
+/**
+ * The type of the Global Routing Link Record. Defined in the OSPF spec.
+ * We currently only use PointToPoint and StubNetwork types.
+ */
+ LinkType m_linkType;
+
+/**
+ * The metric for a given link.
+ *
+ * A metric is abstract cost associated with forwarding a packet across a
+ * link. A sum of metrics must have a well-defined meaning. That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth
+ * of two hops relate to the cost of sending a packet); rather you should
+ * use something like delay.
+ */
+ uint32_t m_metric;
+};
+
+/**
+ * @brief a Link State Advertisement (LSA) for a router, used in global
+ * routing.
+ *
+ * Roughly equivalent to a global incarnation of the OSPF link state header
+ * combined with a list of Link Records. Since it's global, there's
+ * no need for age or sequence number. See RFC 2328, Appendix A.
+ */
+class GlobalRoutingLSA
+{
+public:
+/**
+ * @enum LSType
+ * @brief corresponds to LS type field of RFC 2328 OSPF LSA header
+ */
+ enum LSType {
+ Unknown = 0, /**< Uninitialized Type */
+ RouterLSA,
+ NetworkLSA,
+ SummaryLSA,
+ SummaryLSA_ASBR,
+ ASExternalLSAs
+ };
+/**
+ * @enum SPFStatus
+ * @brief Enumeration of the possible values of the status flag in the Routing
+ * Link State Advertisements.
+ */
+ enum SPFStatus {
+ LSA_SPF_NOT_EXPLORED = 0, /**< New vertex not yet considered */
+ LSA_SPF_CANDIDATE, /**< Vertex is in the SPF candidate queue */
+ LSA_SPF_IN_SPFTREE /**< Vertex is in the SPF tree */
+ };
+/**
+ * @brief Create a blank Global Routing Link State Advertisement.
+ *
+ * On completion Ipv4Address variables initialized to 0.0.0.0 and the
+ * list of Link State Records is empty.
+ */
+ GlobalRoutingLSA();
+
+/**
+ * @brief Create an initialized Global Routing Link State Advertisement.
+ *
+ * On completion the list of Link State Records is empty.
+ *
+ * @param status The status to of the new LSA.
+ * @param linkStateId The Ipv4Address for the link state ID field.
+ * @param advertisingRtr The Ipv4Address for the advertising router field.
+ */
+ GlobalRoutingLSA(SPFStatus status, Ipv4Address linkStateId,
+ Ipv4Address advertisingRtr);
+
+/**
+ * @brief Copy constructor for a Global Routing Link State Advertisement.
+ *
+ * Takes a piece of memory and constructs a semantically identical copy of
+ * the given LSA.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ */
+ GlobalRoutingLSA (GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Destroy an existing Global Routing Link State Advertisement.
+ *
+ * Any Global Routing Link Records present in the list are freed.
+ */
+ ~GlobalRoutingLSA();
+
+/**
+ * @brief Assignment operator for a Global Routing Link State Advertisement.
+ *
+ * Takes an existing Global Routing Link State Advertisement and overwrites
+ * it to make a semantically identical copy of a given prototype LSA.
+ *
+ * If there are any Global Routing Link Records present in the existing
+ * LSA, they are freed before the assignment happens.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ * @returns Reference to the overwritten LSA.
+ */
+ GlobalRoutingLSA& operator= (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Copy any Global Routing Link Records in a given Global Routing Link
+ * State Advertisement to the current LSA.
+ *
+ * Existing Link Records are not deleted -- this is a concatenation of Link
+ * Records.
+ *
+ * @see ClearLinkRecords ()
+ * @param lsa The LSA to copy the Link Records from.
+ */
+ void CopyLinkRecords (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Add a given Global Routing Link Record to the LSA.
+ *
+ * @param lr The Global Routing Link Record to be added.
+ * @returns The number of link records in the list.
+ */
+ uint32_t AddLinkRecord (GlobalRoutingLinkRecord* lr);
+
+/**
+ * @brief Return the number of Global Routing Link Records in the LSA.
+ *
+ * @returns The number of link records in the list.
+ */
+ uint32_t GetNLinkRecords (void) const;
+
+/**
+ * @brief Return a pointer to the specified Global Routing Link Record.
+ *
+ * @param n The LSA number desired.
+ * @returns The number of link records in the list.
+ */
+ GlobalRoutingLinkRecord* GetLinkRecord (uint32_t n) const;
+
+/**
+ * @brief Release all of the Global Routing Link Records present in the Global
+ * Routing Link State Advertisement and make the list of link records empty.
+ */
+ void ClearLinkRecords(void);
+
+/**
+ * @brief Check to see if the list of Global Routing Link Records present in the
+ * Global Routing Link State Advertisement is empty.
+ *
+ * @returns True if the list is empty, false otherwise.
+ */
+ bool IsEmpty(void) const;
+
+/**
+ * @brief Print the contents of the Global Routing Link State Advertisement and
+ * any Global Routing Link Records present in the list. Quite verbose.
+ */
+ void Print (std::ostream &os) const;
+
+/**
+ * @brief Return the LSType field of the LSA
+ */
+ LSType GetLSType (void) const;
+/**
+ * @brief Set the LS type field of the LSA
+ */
+ void SetLSType (LSType typ);
+
+/**
+ * @brief Get the Link State ID as defined by the OSPF spec. We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the link state ID.
+ */
+ Ipv4Address GetLinkStateId (void) const;
+
+/**
+ * @brief Set the Link State ID is defined by the OSPF spec. We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ void SetLinkStateId (Ipv4Address addr);
+
+/**
+ * @brief Get the Advertising Router as defined by the OSPF spec. We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the advetising router.
+ */
+ Ipv4Address GetAdvertisingRouter (void) const;
+
+/**
+ * @brief Set the Advertising Router as defined by the OSPF spec. We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ void SetAdvertisingRouter (Ipv4Address rtr);
+
+/**
+ * @brief For a Network LSA, set the Network Mask field that precedes
+ * the list of attached routers.
+ */
+ void SetNetworkLSANetworkMask (Ipv4Mask mask);
+
+/**
+ * @brief For a Network LSA, get the Network Mask field that precedes
+ * the list of attached routers.
+ *
+ * @returns the NetworkLSANetworkMask
+ */
+ Ipv4Mask GetNetworkLSANetworkMask (void) const;
+
+/**
+ * @brief Add an attached router to the list in the NetworkLSA
+ *
+ * @param addr The Ipv4Address of the interface on the network link
+ * @returns The number of addresses in the list.
+ */
+ uint32_t AddAttachedRouter (Ipv4Address addr);
+
+/**
+ * @brief Return the number of attached routers listed in the NetworkLSA
+ *
+ * @returns The number of attached routers.
+ */
+ uint32_t GetNAttachedRouters (void) const;
+
+/**
+ * @brief Return an Ipv4Address corresponding to the specified attached router
+ *
+ * @param n The attached router number desired (number in the list).
+ * @returns The Ipv4Address of the requested router
+ */
+ Ipv4Address GetAttachedRouter (uint32_t n) const;
+
+/**
+ * @brief Get the SPF status of the advertisement.
+ *
+ * @see SPFStatus
+ * @returns The SPFStatus of the LSA.
+ */
+ SPFStatus GetStatus (void) const;
+
+/**
+ * @brief Set the SPF status of the advertisement
+ *
+ * @see SPFStatus
+ */
+ void SetStatus (SPFStatus status);
+
+private:
+/**
+ * The type of the LSA. Each LSA type has a separate advertisement
+ * format.
+ */
+ LSType m_lsType;
+/**
+ * The Link State ID is defined by the OSPF spec. We always set it to the
+ * router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ Ipv4Address m_linkStateId;
+
+/**
+ * The Advertising Router is defined by the OSPF spec. We always set it to
+ * the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+ Ipv4Address m_advertisingRtr;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+ typedef std::list<GlobalRoutingLinkRecord*> ListOfLinkRecords_t;
+
+/**
+ * Each Link State Advertisement contains a number of Link Records that
+ * describe the kinds of links that are attached to a given node. We
+ * consider PointToPoint and StubNetwork links.
+ *
+ * m_linkRecords is an STL list container to hold the Link Records that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+ ListOfLinkRecords_t m_linkRecords;
+
+/**
+ * Each Network LSA contains the network mask of the attached network
+ */
+ Ipv4Mask m_networkLSANetworkMask;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+ typedef std::list<Ipv4Address> ListOfAttachedRouters_t;
+
+/**
+ * Each Network LSA contains a list of attached routers
+ *
+ * m_attachedRouters is an STL list container to hold the addresses that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+ ListOfAttachedRouters_t m_attachedRouters;
+
+/**
+ * This is a tristate flag used internally in the SPF computation to mark
+ * if an SPFVertex (a data structure representing a vertex in the SPF tree
+ * -- a router) is new, is a candidate for a shortest path, or is in its
+ * proper position in the tree.
+ */
+ SPFStatus m_status;
+};
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa);
+
+/**
+ * @brief An interface aggregated to a node to provide global routing info
+ *
+ * An interface aggregated to a node that provides global routing information
+ * to a global route manager. The presence of the interface indicates that
+ * the node is a router. The interface is the mechanism by which the router
+ * advertises its connections to neighboring routers. We're basically
+ * allowing the route manager to query for link state advertisements.
+ */
+class GlobalRouter : public Object
+{
+public:
+/**
+ * @brief The Interface ID of the Global Router interface.
+ *
+ * @see Object::QueryInterface ()
+ */
+ static const InterfaceId iid;
+
+/**
+ * @brief Create a Global Router class and aggregate its interface onto the
+ * Node provided.
+ *
+ * @param node The existing Node onto which this router will be aggregated.
+ */
+ GlobalRouter (Ptr<Node> node);
+
+/**
+ * @brief Get the Router ID associated with this Global Router.
+ *
+ * The Router IDs are allocated in the RoutingEnvironment -- one per Router,
+ * starting at 0.0.0.1 and incrementing with each instantiation of a router.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @returns The Router ID associated with the Global Router.
+ */
+ Ipv4Address GetRouterId (void) const;
+
+/**
+ * @brief Walk the connected channels, discover the adjacent routers and build
+ * the associated number of Global Routing Link State Advertisements that
+ * this router can export.
+ *
+ * This is a fairly expensive operation in that every time it is called
+ * the current list of LSAs is built by walking connected point-to-point
+ * channels and peeking into adjacent IPV4 stacks to get address information.
+ * This is done to allow for limited dymanics of the Global Routing
+ * environment. By that we mean that you can discover new link state
+ * advertisements after a network topology change by calling DiscoverLSAs
+ * and then by reading those advertisements.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+ uint32_t DiscoverLSAs (void);
+
+/**
+ * @brief Get the Number of Global Routing Link State Advertisements that this
+ * router can export.
+ *
+ * To get meaningful information you must have previously called DiscoverLSAs.
+ * After you know how many LSAs are present in the router, you may call
+ * GetLSA () to retrieve the actual advertisement.
+ *
+ * @see GlobalRouterLSA
+ * @see GlobalRouting::DiscoverLSAs ()
+ * @see GlobalRouting::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+ uint32_t GetNumLSAs (void) const;
+
+/**
+ * @brief Get a Global Routing Link State Advertisements that this router has
+ * said that it can export.
+ *
+ * This is a fairly inexpensive expensive operation in that the hard work
+ * was done in GetNumLSAs. We just copy the indicated Global Routing Link
+ * State Advertisement into the requested GlobalRoutingLSA object.
+ *
+ * You must call GlobalRouter::GetNumLSAs before calling this method in
+ * order to discover the adjacent routers and build the advertisements.
+ * GetNumLSAs will return the number of LSAs this router advertises.
+ * The parameter n (requested LSA number) must be in the range 0 to
+ * GetNumLSAs() - 1.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouting::GetNumLSAs ()
+ * @param n The index number of the LSA you want to read.
+ * @param lsa The GlobalRoutingLSA class to receive the LSA information.
+ * @returns The number of Global Router Link State Advertisements.
+ */
+ bool GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const;
+
+private:
+ virtual ~GlobalRouter ();
+ void ClearLSAs (void);
+
+ Ptr<NetDevice> GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const;
+ uint32_t FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const;
+ Ipv4Address FindDesignatedRouterForLink (Ptr<Node> node,
+ Ptr<NetDevice> ndLocal) const;
+
+ Ptr<Node> m_node;
+
+ typedef std::list<GlobalRoutingLSA*> ListOfLSAs_t;
+ ListOfLSAs_t m_LSAs;
+
+ Ipv4Address m_routerId;
+
+ // inherited from Object
+ virtual void DoDispose (void);
+
+/**
+ * @brief Global Router copy construction is disallowed.
+ */
+ GlobalRouter (GlobalRouter& sr);
+
+/**
+ * @brief Global Router assignment operator is disallowed.
+ */
+ GlobalRouter& operator= (GlobalRouter& sr);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTER_INTERFACE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,17 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+ module = bld.create_ns3_module('global-routing', ['node'])
+ module.source = [
+ 'global-router-interface.cc',
+ 'global-route-manager.cc',
+ 'global-route-manager-impl.cc',
+ 'candidate-queue.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.source = [
+ 'global-router-interface.h',
+ 'global-route-manager.h',
+ 'candidate-queue.h',
+ ]
+
--- a/src/simulator/event-id.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-id.cc Wed Sep 05 18:35:39 2007 +0100
@@ -30,7 +30,7 @@
m_uid (0)
{}
-EventId::EventId (EventImpl *impl, uint64_t ts, uint32_t uid)
+EventId::EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid)
: m_eventImpl (impl),
m_ts (ts),
m_uid (uid)
@@ -38,11 +38,7 @@
void
EventId::Cancel (void)
{
- if (!IsExpired ())
- {
- m_eventImpl->Cancel ();
- m_eventImpl = 0;
- }
+ Simulator::Cancel (*this);
}
bool
EventId::IsExpired (void) const
@@ -55,9 +51,9 @@
return !IsExpired ();
}
EventImpl *
-EventId::GetEventImpl (void) const
+EventId::PeekEventImpl (void) const
{
- return m_eventImpl;
+ return PeekPointer (m_eventImpl);
}
uint64_t
EventId::GetTs (void) const
--- a/src/simulator/event-id.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-id.h Wed Sep 05 18:35:39 2007 +0100
@@ -22,6 +22,8 @@
#define EVENT_ID_H
#include <stdint.h>
+#include "ns3/ptr.h"
+#include "event-impl.h"
namespace ns3 {
@@ -33,7 +35,7 @@
class EventId {
public:
EventId ();
- EventId (EventImpl *impl, uint64_t ts, uint32_t uid);
+ EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid);
/**
* This method is syntactic sugar for the ns3::Simulator::cancel
* method.
@@ -51,12 +53,12 @@
* they are supposed to be invoked only by
* subclasses of the Scheduler base class.
*/
- EventImpl *GetEventImpl (void) const;
+ EventImpl *PeekEventImpl (void) const;
uint64_t GetTs (void) const;
uint32_t GetUid (void) const;
private:
friend bool operator == (const EventId &a, const EventId &b);
- EventImpl *m_eventImpl;
+ Ptr<EventImpl> m_eventImpl;
uint64_t m_ts;
uint32_t m_uid;
};
--- a/src/simulator/event-impl.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-impl.cc Wed Sep 05 18:35:39 2007 +0100
@@ -29,7 +29,8 @@
{}
EventImpl::EventImpl ()
- : m_cancel (false)
+ : m_cancel (false),
+ m_count (1)
{}
void
EventImpl::Invoke (void)
--- a/src/simulator/event-impl.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-impl.h Wed Sep 05 18:35:39 2007 +0100
@@ -28,6 +28,8 @@
class EventImpl {
public:
EventImpl ();
+ inline void Ref (void) const;
+ inline void Unref (void) const;
virtual ~EventImpl () = 0;
void Invoke (void);
void Cancel (void);
@@ -37,8 +39,28 @@
private:
friend class Event;
bool m_cancel;
+ mutable uint32_t m_count;
};
}; // namespace ns3
+namespace ns3 {
+
+void
+EventImpl::Ref (void) const
+{
+ m_count++;
+}
+void
+EventImpl::Unref (void) const
+{
+ m_count--;
+ if (m_count == 0)
+ {
+ delete this;
+ }
+}
+
+} // namespace ns3
+
#endif /* EVENT_IMPL_H */
--- a/src/simulator/high-precision-128.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/high-precision-128.h Wed Sep 05 18:35:39 2007 +0100
@@ -222,7 +222,9 @@
HP128INC (m_nslowcmps);
return SlowCompare (o);
}
-
+ // The below statement is unreachable but necessary for optimized
+ // builds with gcc-4.0.x due to a compiler bug.
+ return 0;
}
HighPrecision
HighPrecision::Zero (void)
--- a/src/simulator/scheduler-heap.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-heap.cc Wed Sep 05 18:35:39 2007 +0100
@@ -170,7 +170,7 @@
}
bool
-SchedulerHeap::RealIsEmpty (void) const
+SchedulerHeap::IsEmpty (void) const
{
return (m_heap.size () == 1)?true:false;
}
@@ -223,9 +223,11 @@
void
-SchedulerHeap::RealInsert (EventId id)
+SchedulerHeap::Insert (const EventId &id)
{
- EventImpl *event = id.GetEventImpl ();
+ // acquire single ref
+ EventImpl *event = id.PeekEventImpl ();
+ event->Ref ();
Scheduler::EventKey key;
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
@@ -234,29 +236,34 @@
}
EventId
-SchedulerHeap::RealPeekNext (void) const
+SchedulerHeap::PeekNext (void) const
{
std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
return EventId (next.first, next.second.m_ts, next.second.m_uid);
}
-void
-SchedulerHeap::RealRemoveNext (void)
+EventId
+SchedulerHeap::RemoveNext (void)
{
+ std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
Exch (Root (), Last ());
m_heap.pop_back ();
TopDown (Root ());
+ return EventId (Ptr<EventImpl> (next.first, false), next.second.m_ts, next.second.m_uid);
}
bool
-SchedulerHeap::RealRemove (EventId id)
+SchedulerHeap::Remove (const EventId &id)
{
uint32_t uid = id.GetUid ();
for (uint32_t i = 1; i < m_heap.size (); i++)
{
if (uid == m_heap[i].second.m_uid)
{
- NS_ASSERT (m_heap[i].first == id.GetEventImpl ());
+ NS_ASSERT (m_heap[i].first == id.PeekEventImpl ());
+ std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[i];
+ // release single ref
+ next.first->Unref ();
Exch (i, Last ());
m_heap.pop_back ();
TopDown (i);
--- a/src/simulator/scheduler-heap.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-heap.h Wed Sep 05 18:35:39 2007 +0100
@@ -35,13 +35,13 @@
SchedulerHeap ();
virtual ~SchedulerHeap ();
+ virtual void Insert (const EventId &id);
+ virtual bool IsEmpty (void) const;
+ virtual EventId PeekNext (void) const;
+ virtual EventId RemoveNext (void);
+ virtual bool Remove (const EventId &ev);
+
private:
- virtual void RealInsert (EventId id);
- virtual bool RealIsEmpty (void) const;
- virtual EventId RealPeekNext (void) const;
- virtual void RealRemoveNext (void);
- virtual bool RealRemove (EventId ev);
-
typedef std::vector<std::pair<EventImpl *, Scheduler::EventKey> > BinaryHeap;
inline uint32_t Parent (uint32_t id) const;
--- a/src/simulator/scheduler-list.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-list.cc Wed Sep 05 18:35:39 2007 +0100
@@ -67,10 +67,12 @@
}
void
-SchedulerList::RealInsert (EventId id)
+SchedulerList::Insert (const EventId &id)
{
Scheduler::EventKey key;
- EventImpl *event = id.GetEventImpl ();
+ // acquire refcount on EventImpl
+ EventImpl *event = id.PeekEventImpl ();
+ event->Ref ();
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
for (EventsI i = m_events.begin (); i != m_events.end (); i++)
@@ -84,31 +86,35 @@
m_events.push_back (std::make_pair (event, key));
}
bool
-SchedulerList::RealIsEmpty (void) const
+SchedulerList::IsEmpty (void) const
{
return m_events.empty ();
}
EventId
-SchedulerList::RealPeekNext (void) const
+SchedulerList::PeekNext (void) const
{
std::pair<EventImpl *, EventKey> next = m_events.front ();
return EventId (next.first, next.second.m_ts, next.second.m_uid);
}
-void
-SchedulerList::RealRemoveNext (void)
+EventId
+SchedulerList::RemoveNext (void)
{
+ std::pair<EventImpl *, EventKey> next = m_events.front ();
m_events.pop_front ();
+ return EventId (Ptr<EventImpl> (next.first,false), next.second.m_ts, next.second.m_uid);
}
bool
-SchedulerList::RealRemove (EventId id)
+SchedulerList::Remove (const EventId &id)
{
for (EventsI i = m_events.begin (); i != m_events.end (); i++)
{
if (i->second.m_uid == id.GetUid ())
{
- NS_ASSERT (id.GetEventImpl () == i->first);
+ NS_ASSERT (id.PeekEventImpl () == i->first);
+ // release single acquire ref.
+ i->first->Unref ();
m_events.erase (i);
return true;
}
--- a/src/simulator/scheduler-list.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-list.h Wed Sep 05 18:35:39 2007 +0100
@@ -37,13 +37,13 @@
SchedulerList ();
virtual ~SchedulerList ();
+ virtual void Insert (const EventId &id);
+ virtual bool IsEmpty (void) const;
+ virtual EventId PeekNext (void) const;
+ virtual EventId RemoveNext (void);
+ virtual bool Remove (const EventId &ev);
+
private:
- virtual void RealInsert (EventId id);
- virtual bool RealIsEmpty (void) const;
- virtual EventId RealPeekNext (void) const;
- virtual void RealRemoveNext (void);
- virtual bool RealRemove (EventId ev);
-
inline bool IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const;
typedef std::list<std::pair<EventImpl*, EventKey> > Events;
--- a/src/simulator/scheduler-map.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-map.cc Wed Sep 05 18:35:39 2007 +0100
@@ -88,9 +88,11 @@
void
-SchedulerMap::RealInsert (EventId id)
+SchedulerMap::Insert (const EventId &id)
{
- EventImpl *event = id.GetEventImpl ();
+ // acquire a single ref
+ EventImpl *event = id.PeekEventImpl ();
+ event->Ref ();
Scheduler::EventKey key;
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
@@ -100,33 +102,38 @@
}
bool
-SchedulerMap::RealIsEmpty (void) const
+SchedulerMap::IsEmpty (void) const
{
return m_list.empty ();
}
EventId
-SchedulerMap::RealPeekNext (void) const
+SchedulerMap::PeekNext (void) const
{
EventMapCI i = m_list.begin ();
NS_ASSERT (i != m_list.end ());
return EventId (i->second, i->first.m_ts, i->first.m_uid);
}
-void
-SchedulerMap::RealRemoveNext (void)
+EventId
+SchedulerMap::RemoveNext (void)
{
- m_list.erase (m_list.begin ());
+ EventMapI i = m_list.begin ();
+ std::pair<Scheduler::EventKey, EventImpl*> next = *i;
+ m_list.erase (i);
+ return EventId (Ptr<EventImpl> (next.second, false), next.first.m_ts, next.first.m_uid);
}
bool
-SchedulerMap::RealRemove (EventId id)
+SchedulerMap::Remove (const EventId &id)
{
Scheduler::EventKey key;
key.m_ts = id.GetTs ();
key.m_uid = id.GetUid ();
EventMapI i = m_list.find (key);
- NS_ASSERT (i->second == id.GetEventImpl ());
+ NS_ASSERT (i->second == id.PeekEventImpl ());
+ // release single ref.
+ i->second->Unref ();
m_list.erase (i);
return true;
}
--- a/src/simulator/scheduler-map.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-map.h Wed Sep 05 18:35:39 2007 +0100
@@ -36,12 +36,12 @@
SchedulerMap ();
virtual ~SchedulerMap ();
+ virtual void Insert (const EventId &id);
+ virtual bool IsEmpty (void) const;
+ virtual EventId PeekNext (void) const;
+ virtual EventId RemoveNext (void);
+ virtual bool Remove (const EventId &ev);
private:
- virtual void RealInsert (EventId id);
- virtual bool RealIsEmpty (void) const;
- virtual EventId RealPeekNext (void) const;
- virtual void RealRemoveNext (void);
- virtual bool RealRemove (EventId ev);
class EventKeyCompare {
public:
--- a/src/simulator/scheduler.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler.cc Wed Sep 05 18:35:39 2007 +0100
@@ -27,33 +27,4 @@
Scheduler::~Scheduler ()
{}
-void
-Scheduler::Insert (EventId id)
-{
- return RealInsert (id);
-}
-bool
-Scheduler::IsEmpty (void) const
-{
- return RealIsEmpty ();
-}
-EventId
-Scheduler::PeekNext (void) const
-{
- NS_ASSERT (!RealIsEmpty ());
- return RealPeekNext ();
-}
-void
-Scheduler::RemoveNext (void)
-{
- NS_ASSERT (!RealIsEmpty ());
- return RealRemoveNext ();
-}
-bool
-Scheduler::Remove (EventId id)
-{
- NS_ASSERT (!RealIsEmpty ());
- return RealRemove (id);
-}
-
}; // namespace ns3
--- a/src/simulator/scheduler.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler.h Wed Sep 05 18:35:39 2007 +0100
@@ -27,21 +27,18 @@
namespace ns3 {
-class EventImpl;
-
/**
* \brief Maintain the event list
*
* This base class specifies the interface used to maintain the
* event list. If you want to provide a new event list scheduler,
* you need to create a subclass of this base class and implement
- * all the private pure virtual methods defined here. Namely:
- * - ns3::Scheduler::realInsert
- * - ns3::Scheduler::realIsEmpty
- * - ns3::Scheduler::realPeekNext
- * - ns3::Scheduler::realPeekNextKey
- * - ns3::Scheduler::realRemoveNext
- * - ns3::Scheduler::realRemove
+ * all the pure virtual methods defined here. Namely:
+ * - ns3::Scheduler::Insert
+ * - ns3::Scheduler::IsEmpty
+ * - ns3::Scheduler::PeekNext
+ * - ns3::Scheduler::RemoveNext
+ * - ns3::Scheduler::Remove
*
* If you need to provide a new event list scheduler without
* editing the main simulator class, you need to also implement
@@ -60,46 +57,36 @@
virtual ~Scheduler () = 0;
- void Insert (EventId id);
- bool IsEmpty (void) const;
- EventId PeekNext (void) const;
- void RemoveNext (void);
- bool Remove (EventId);
-
-private:
/**
- * \param event event to store in the event list
- * \param key timecode associated to this new event
- * \returns an event id which identifies the event inserted
+ * \param id event to store in the event list
*
* This method takes ownership of the event pointer.
*/
- virtual void RealInsert (EventId id) = 0;
+ virtual void Insert (const EventId &id) = 0;
/**
* \returns true if the event list is empty and false otherwise.
*/
- virtual bool RealIsEmpty (void) const = 0;
+ virtual bool IsEmpty (void) const = 0;
/**
* \returns a pointer to the next earliest event. The caller
* takes ownership of the returned pointer.
*
* This method cannot be invoked if the list is empty.
*/
- virtual EventId RealPeekNext (void) const = 0;
+ virtual EventId PeekNext (void) const = 0;
/**
* This method cannot be invoked if the list is empty.
* Remove the next earliest event from the event list.
*/
- virtual void RealRemoveNext (void) = 0;
+ virtual EventId RemoveNext (void) = 0;
/**
* \param id the id of the event to remove
- * \param key the timecode of the event removed
- * \returns a pointer to the event removed. The caller
- * takes ownership of the returned pointer.
+ * \returns true if the id was found and removed
+ * successfully, false otherwise.
*
* This methods cannot be invoked if the list is empty.
*/
- virtual bool RealRemove (EventId id) = 0;
+ virtual bool Remove (const EventId &id) = 0;
};
}; // namespace ns3
--- a/src/simulator/simulator.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/simulator.cc Wed Sep 05 18:35:39 2007 +0100
@@ -23,6 +23,7 @@
#include "scheduler.h"
#include "event-impl.h"
+#include "ns3/ptr.h"
#include "ns3/assert.h"
#include "ns3/default-value.h"
@@ -61,12 +62,12 @@
Time Next (void) const;
void Stop (void);
void StopAt (Time const &time);
- EventId Schedule (Time const &time, EventImpl *event);
- EventId ScheduleNow (EventImpl *event);
- EventId ScheduleDestroy (EventImpl *event);
- void Remove (EventId ev);
- void Cancel (EventId &ev);
- bool IsExpired (EventId ev);
+ EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+ EventId ScheduleNow (const Ptr<EventImpl> &event);
+ EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+ void Remove (const EventId &ev);
+ void Cancel (const EventId &ev);
+ bool IsExpired (const EventId &ev);
void Run (void);
Time Now (void) const;
@@ -114,13 +115,12 @@
{
while (!m_destroyEvents.empty ())
{
- EventImpl *ev = m_destroyEvents.front ().GetEventImpl ();
+ Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
m_destroyEvents.pop_front ();
TRACE ("handle destroy " << ev);
if (!ev->IsCancelled ())
{
ev->Invoke ();
- delete ev;
}
}
delete m_events;
@@ -138,8 +138,7 @@
void
SimulatorPrivate::ProcessOneEvent (void)
{
- EventId next = m_events->PeekNext ();
- m_events->RemoveNext ();
+ EventId next = m_events->RemoveNext ();
NS_ASSERT (next.GetTs () >= m_currentTs);
--m_unscheduledEvents;
@@ -151,9 +150,8 @@
{
m_log << "e "<<next.GetUid () << " " << next.GetTs () << std::endl;
}
- EventImpl *event = next.GetEventImpl ();
+ EventImpl *event = next.PeekEventImpl ();
event->Invoke ();
- delete event;
}
bool
@@ -204,7 +202,7 @@
m_stopAt = at.GetTimeStep ();
}
EventId
-SimulatorPrivate::Schedule (Time const &time, EventImpl *event)
+SimulatorPrivate::Schedule (Time const &time, const Ptr<EventImpl> &event)
{
NS_ASSERT (time.IsPositive ());
NS_ASSERT (time >= TimeStep (m_currentTs));
@@ -221,7 +219,7 @@
return id;
}
EventId
-SimulatorPrivate::ScheduleNow (EventImpl *event)
+SimulatorPrivate::ScheduleNow (const Ptr<EventImpl> &event)
{
EventId id (event, m_currentTs, m_uid);
if (m_logEnable)
@@ -235,7 +233,7 @@
return id;
}
EventId
-SimulatorPrivate::ScheduleDestroy (EventImpl *event)
+SimulatorPrivate::ScheduleDestroy (const Ptr<EventImpl> &event)
{
EventId id (event, m_currentTs, 2);
m_destroyEvents.push_back (id);
@@ -255,7 +253,7 @@
}
void
-SimulatorPrivate::Remove (EventId ev)
+SimulatorPrivate::Remove (const EventId &ev)
{
if (ev.GetUid () == 2)
{
@@ -275,7 +273,7 @@
return;
}
m_events->Remove (ev);
- delete ev.GetEventImpl ();
+ Cancel (ev);
if (m_logEnable)
{
@@ -286,13 +284,16 @@
}
void
-SimulatorPrivate::Cancel (EventId &id)
+SimulatorPrivate::Cancel (const EventId &id)
{
- id.Cancel ();
+ if (!IsExpired (id))
+ {
+ id.PeekEventImpl ()->Cancel ();
+ }
}
bool
-SimulatorPrivate::IsExpired (const EventId ev)
+SimulatorPrivate::IsExpired (const EventId &ev)
{
if (ev.GetUid () == 2)
{
@@ -306,11 +307,11 @@
}
return true;
}
- if (ev.GetEventImpl () == 0 ||
+ if (ev.PeekEventImpl () == 0 ||
ev.GetTs () < m_currentTs ||
(ev.GetTs () == m_currentTs &&
ev.GetUid () <= m_currentUid) ||
- ev.GetEventImpl ()->IsCancelled ())
+ ev.PeekEventImpl ()->IsCancelled ())
{
return true;
}
@@ -336,20 +337,20 @@
void Simulator::SetLinkedList (void)
{
- Bind ("Scheduler", "List");
+ DefaultValue::Bind ("Scheduler", "List");
}
void Simulator::SetBinaryHeap (void)
{
- Bind ("Scheduler", "BinaryHeap");
+ DefaultValue::Bind ("Scheduler", "BinaryHeap");
}
void Simulator::SetStdMap (void)
{
- Bind ("Scheduler", "Map");
+ DefaultValue::Bind ("Scheduler", "Map");
}
void
Simulator::SetExternal (const std::string &external)
{
- Bind ("Scheduler", external);
+ DefaultValue::Bind ("Scheduler", external);
}
void Simulator::EnableLogTo (char const *filename)
{
@@ -411,39 +412,39 @@
return GetPriv ()->Now ();
}
-EventImpl *
+Ptr<EventImpl>
Simulator::MakeEvent (void (*f) (void))
{
// zero arg version
class EventFunctionImpl0 : public EventImpl {
public:
- typedef void (*F)(void);
+ typedef void (*F)(void);
- EventFunctionImpl0 (F function)
- : m_function (function)
- {}
- virtual ~EventFunctionImpl0 () {}
+ EventFunctionImpl0 (F function)
+ : m_function (function)
+ {}
+ virtual ~EventFunctionImpl0 () {}
protected:
- virtual void Notify (void) {
- (*m_function) ();
- }
+ virtual void Notify (void) {
+ (*m_function) ();
+ }
private:
F m_function;
} *ev = new EventFunctionImpl0 (f);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
EventId
-Simulator::Schedule (Time const &time, EventImpl *ev)
+Simulator::Schedule (Time const &time, const Ptr<EventImpl> &ev)
{
return GetPriv ()->Schedule (Now () + time, ev);
}
EventId
-Simulator::ScheduleNow (EventImpl *ev)
+Simulator::ScheduleNow (const Ptr<EventImpl> &ev)
{
return GetPriv ()->ScheduleNow (ev);
}
EventId
-Simulator::ScheduleDestroy (EventImpl *ev)
+Simulator::ScheduleDestroy (const Ptr<EventImpl> &ev)
{
return GetPriv ()->ScheduleDestroy (ev);
}
@@ -465,18 +466,18 @@
void
-Simulator::Remove (EventId ev)
+Simulator::Remove (const EventId &ev)
{
return GetPriv ()->Remove (ev);
}
void
-Simulator::Cancel (EventId &ev)
+Simulator::Cancel (const EventId &ev)
{
return GetPriv ()->Cancel (ev);
}
bool
-Simulator::IsExpired (EventId id)
+Simulator::IsExpired (const EventId &id)
{
return GetPriv ()->IsExpired (id);
}
@@ -538,13 +539,14 @@
public:
SimulatorTests ();
// only here for testing of Ptr<>
- void Ref (void);
- void Unref (void);
+ void Ref (void) const;
+ void Unref (void) const;
virtual ~SimulatorTests ();
virtual bool RunTests (void);
private:
uint64_t NowUs ();
bool RunOneTest (void);
+ void RunTestsConst (void) const;
void A (int a);
void B (int b);
void C (int c);
@@ -565,6 +567,24 @@
void cbaz3 (const int &, const int &, const int &);
void cbaz4 (const int &, const int &, const int &, const int &);
void cbaz5 (const int &, const int &, const int &, const int &, const int &);
+
+ void bar0c (void) const;
+ void bar1c (int) const;
+ void bar2c (int, int) const;
+ void bar3c (int, int, int) const;
+ void bar4c (int, int, int, int) const;
+ void bar5c (int, int, int, int, int) const;
+ void baz1c (int &) const;
+ void baz2c (int &, int &) const;
+ void baz3c (int &, int &, int &) const;
+ void baz4c (int &, int &, int &, int &) const;
+ void baz5c (int &, int &, int &, int &, int &) const;
+ void cbaz1c (const int &) const;
+ void cbaz2c (const int &, const int &) const;
+ void cbaz3c (const int &, const int &, const int &) const;
+ void cbaz4c (const int &, const int &, const int &, const int &) const;
+ void cbaz5c (const int &, const int &, const int &, const int &, const int &) const;
+
void destroy (void);
bool m_b;
@@ -582,10 +602,10 @@
SimulatorTests::~SimulatorTests ()
{}
void
-SimulatorTests::Ref (void)
+SimulatorTests::Ref (void) const
{}
void
-SimulatorTests::Unref (void)
+SimulatorTests::Unref (void) const
{}
uint64_t
SimulatorTests::NowUs (void)
@@ -688,6 +708,57 @@
SimulatorTests::cbaz5 (const int &, const int &, const int &, const int &, const int &)
{}
+void
+SimulatorTests::bar0c (void) const
+{}
+void
+SimulatorTests::bar1c (int) const
+{}
+void
+SimulatorTests::bar2c (int, int) const
+{}
+void
+SimulatorTests::bar3c (int, int, int) const
+{}
+void
+SimulatorTests::bar4c (int, int, int, int) const
+{}
+void
+SimulatorTests::bar5c (int, int, int, int, int) const
+{}
+
+void
+SimulatorTests::baz1c (int &) const
+{}
+void
+SimulatorTests::baz2c (int &, int &) const
+{}
+void
+SimulatorTests::baz3c (int &, int &, int &) const
+{}
+void
+SimulatorTests::baz4c (int &, int &, int &, int &) const
+{}
+void
+SimulatorTests::baz5c (int &, int &, int &, int &, int &) const
+{}
+
+void
+SimulatorTests::cbaz1c (const int &) const
+{}
+void
+SimulatorTests::cbaz2c (const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz3c (const int &, const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz4c (const int &, const int &, const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz5c (const int &, const int &, const int &, const int &, const int &) const
+{}
+
bool
SimulatorTests::RunOneTest (void)
{
@@ -722,6 +793,80 @@
}
return ok;
}
+void
+SimulatorTests::RunTestsConst (void) const
+{
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, this);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1c, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2c, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3c, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar0c, this);
+ Simulator::ScheduleNow (&SimulatorTests::bar1c, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar2c, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar3c, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz1c, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz2c, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+ Simulator::ScheduleNow (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar0c, this);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar1c, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar2c, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar3c, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz1c, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz2c, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+ Simulator::ScheduleDestroy (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1c, this, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2c, this, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3c, this, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz4c, this, 0, 0, 0, 0);
+ Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz1c, this, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz2c, this, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz3c, this, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleNow (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz1c, this, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz2c, this, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz3c, this, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+ Simulator::ScheduleDestroy (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+}
+
bool
SimulatorTests::RunTests (void)
{
@@ -869,6 +1014,8 @@
Simulator::ScheduleDestroy (&SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
#endif
+ RunTestsConst ();
+
EventId nowId = Simulator::ScheduleNow (&foo0);
m_destroyId = Simulator::ScheduleDestroy (&SimulatorTests::destroy, this);
if (m_destroyId.IsExpired ())
@@ -884,6 +1031,22 @@
ok = false;
}
+ EventId anId = Simulator::ScheduleNow (&foo0);
+ EventId anotherId = anId;
+ if (anId.IsExpired () || anotherId.IsExpired ())
+ {
+ ok = false;
+ }
+ Simulator::Remove (anId);
+ if (!anId.IsExpired () || !anotherId.IsExpired ())
+ {
+ ok = false;
+ }
+
+ Simulator::Run ();
+ Simulator::Destroy ();
+
+
return ok;
}
--- a/src/simulator/simulator.h Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/simulator.h Wed Sep 05 18:35:39 2007 +0100
@@ -163,8 +163,8 @@
* @param obj the object on which to invoke the member method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj);
+ template <typename MEM, typename OBJ>
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -172,8 +172,8 @@
* @param a1 the first argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ, typename U1, typename T1>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
+ template <typename MEM, typename OBJ, typename T1>
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -182,8 +182,8 @@
* @param a2 the second argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ, typename U1, typename U2, typename T1, typename T2>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
+ template <typename MEM, typename OBJ, typename T1, typename T2>
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -193,10 +193,9 @@
* @param a3 the third argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -207,10 +206,9 @@
* @param a4 the fourth argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
/**
* @param time the relative expiration time of the event.
* @param mem_ptr member method pointer to invoke
@@ -222,10 +220,9 @@
* @param a5 the fifth argument to pass to the invoked method
* @returns an id for the scheduled event.
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
+ static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj,
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
/**
* @param time the relative expiration time of the event.
@@ -295,27 +292,25 @@
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
*/
- template <typename T, typename OBJ>
- static EventId ScheduleNow (void (T::*mem_ptr) (void), OBJ obj);
+ template <typename MEM, typename OBJ>
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1,
+ template <typename MEM, typename OBJ,
typename T1>
- static EventId ScheduleNow (void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
* @param a2 the second argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2,
+ template <typename MEM, typename OBJ,
typename T1, typename T2>
- static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -323,10 +318,9 @@
* @param a2 the second argument to pass to the invoked method
* @param a3 the third argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
- static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -335,11 +329,10 @@
* @param a3 the third argument to pass to the invoked method
* @param a4 the fourth argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
- static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4);
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -349,11 +342,10 @@
* @param a4 the fourth argument to pass to the invoked method
* @param a5 the fifth argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ static EventId ScheduleNow (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
/**
* @param f the function to invoke
*/
@@ -414,27 +406,25 @@
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
*/
- template <typename T, typename OBJ>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj);
+ template <typename MEM, typename OBJ>
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1,
+ template <typename MEM, typename OBJ,
typename T1>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
* @param a1 the first argument to pass to the invoked method
* @param a2 the second argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2,
+ template <typename MEM, typename OBJ,
typename T1, typename T2>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -442,10 +432,9 @@
* @param a2 the second argument to pass to the invoked method
* @param a3 the third argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -454,11 +443,10 @@
* @param a3 the third argument to pass to the invoked method
* @param a4 the fourth argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4);
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4);
/**
* @param mem_ptr member method pointer to invoke
* @param obj the object on which to invoke the member method
@@ -468,11 +456,10 @@
* @param a4 the fourth argument to pass to the invoked method
* @param a5 the fifth argument to pass to the invoked method
*/
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
/**
* @param f the function to invoke
*/
@@ -534,7 +521,7 @@
*
* @param id the event to remove from the list of scheduled events.
*/
- static void Remove (EventId id);
+ static void Remove (const EventId &id);
/**
* Set the cancel bit on this event: the event's associated function
* will not be invoked when it expires.
@@ -547,7 +534,7 @@
*
* @param id the event to cancel
*/
- static void Cancel (EventId &id);
+ static void Cancel (const EventId &id);
/**
* This method has O(1) complexity.
* Note that it is not possible to test for the expiration of
@@ -560,7 +547,7 @@
* @param id the event to test for expiration
* @returns true if the event has expired, false otherwise.
*/
- static bool IsExpired (const EventId id);
+ static bool IsExpired (const EventId &id);
/**
* Return the "current simulation time".
*/
@@ -569,50 +556,45 @@
Simulator ();
~Simulator ();
- template <typename T, typename OBJ>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj);
- template <typename T, typename OBJ,
- typename U1,
+ template <typename MEM, typename OBJ>
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj);
+ template <typename MEM, typename OBJ,
typename T1>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
- template <typename T, typename OBJ,
- typename U1, typename U2,
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1);
+ template <typename MEM, typename OBJ,
typename T1, typename T2>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
- template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+ template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
- static EventImpl *MakeEvent (void (*f) (void));
+ static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ static Ptr<EventImpl> MakeEvent (void (*f) (void));
template <typename U1,
typename T1>
- static EventImpl *MakeEvent (void (*f) (U1), T1 a1);
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1), T1 a1);
template <typename U1, typename U2,
typename T1, typename T2>
- static EventImpl *MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2);
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2);
template <typename U1, typename U2, typename U3,
typename T1, typename T2, typename T3>
- static EventImpl *MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
template <typename U1, typename U2, typename U3, typename U4,
typename T1, typename T2, typename T3, typename T4>
- static EventImpl *MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
template <typename U1, typename U2, typename U3, typename U4, typename U5,
typename T1, typename T2, typename T3, typename T4, typename T5>
- static EventImpl *MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+ static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
static SimulatorPrivate *GetPriv (void);
- static EventId Schedule (Time const &time, EventImpl *event);
- static EventId ScheduleDestroy (EventImpl *event);
- static EventId ScheduleNow (EventImpl *event);
+ static EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+ static EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+ static EventId ScheduleNow (const Ptr<EventImpl> &event);
static SimulatorPrivate *m_priv;
};
@@ -649,14 +631,13 @@
}
};
-template <typename T, typename OBJ>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj)
+template <typename MEM, typename OBJ>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj)
{
// zero argument version
class EventMemberImpl0 : public EventImpl {
public:
- typedef void (T::*F)(void);
- EventMemberImpl0 (OBJ obj, F function)
+ EventMemberImpl0 (OBJ obj, MEM function)
: m_obj (obj),
m_function (function)
{}
@@ -666,22 +647,20 @@
(EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) ();
}
OBJ m_obj;
- F m_function;
- } *ev = new EventMemberImpl0 (obj, mem_ptr);
- return ev;
+ MEM m_function;
+ } * ev = new EventMemberImpl0 (obj, mem_ptr);
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ,
- typename U1,
+template <typename MEM, typename OBJ,
typename T1>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1)
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1)
{
// one argument version
class EventMemberImpl1 : public EventImpl {
public:
- typedef void (T::*F)(U1);
- EventMemberImpl1 (OBJ obj, F function, T1 a1)
+ EventMemberImpl1 (OBJ obj, MEM function, T1 a1)
: m_obj (obj),
m_function (function),
m_a1 (a1)
@@ -693,23 +672,20 @@
(EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
}
OBJ m_obj;
- F m_function;
+ MEM m_function;
typename TypeTraits<T1>::ReferencedType m_a1;
} *ev = new EventMemberImpl1 (obj, mem_ptr, a1);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ,
- typename U1, typename U2,
+template <typename MEM, typename OBJ,
typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2)
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
// two argument version
class EventMemberImpl2 : public EventImpl {
public:
- typedef void (T::*F)(U1, U2);
-
- EventMemberImpl2 (OBJ obj, F function, T1 a1, T2 a2)
+ EventMemberImpl2 (OBJ obj, MEM function, T1 a1, T2 a2)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -722,24 +698,21 @@
(EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2);
}
OBJ m_obj;
- F m_function;
+ MEM m_function;
typename TypeTraits<T1>::ReferencedType m_a1;
typename TypeTraits<T2>::ReferencedType m_a2;
} *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3)
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
// three argument version
class EventMemberImpl3 : public EventImpl {
public:
- typedef void (T::*F)(U1,U2,U3);
-
- EventMemberImpl3 (OBJ obj, F function, T1 a1, T2 a2, T3 a3)
+ EventMemberImpl3 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -753,25 +726,22 @@
(EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3);
}
OBJ m_obj;
- F m_function;
+ MEM m_function;
typename TypeTraits<T1>::ReferencedType m_a1;
typename TypeTraits<T2>::ReferencedType m_a2;
typename TypeTraits<T3>::ReferencedType m_a3;
} *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
// four argument version
class EventMemberImpl4 : public EventImpl {
public:
- typedef void (T::*F)(U1, U2, U3, U4);
-
- EventMemberImpl4 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4)
+ EventMemberImpl4 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -786,27 +756,24 @@
(EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4);
}
OBJ m_obj;
- F m_function;
+ MEM m_function;
typename TypeTraits<T1>::ReferencedType m_a1;
typename TypeTraits<T2>::ReferencedType m_a2;
typename TypeTraits<T3>::ReferencedType m_a3;
typename TypeTraits<T4>::ReferencedType m_a4;
} *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
// five argument version
class EventMemberImpl5 : public EventImpl {
public:
- typedef void (T::*F)(U1, U2, U3, U4, U5);
-
- EventMemberImpl5 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+ EventMemberImpl5 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
: m_obj (obj),
m_function (function),
m_a1 (a1),
@@ -822,18 +789,18 @@
(EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
}
OBJ m_obj;
- F m_function;
+ MEM m_function;
typename TypeTraits<T1>::ReferencedType m_a1;
typename TypeTraits<T2>::ReferencedType m_a2;
typename TypeTraits<T3>::ReferencedType m_a3;
typename TypeTraits<T4>::ReferencedType m_a4;
typename TypeTraits<T5>::ReferencedType m_a5;
} *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
template <typename U1, typename T1>
-EventImpl *Simulator::MakeEvent (void (*f) (U1), T1 a1)
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1), T1 a1)
{
// one arg version
class EventFunctionImpl1 : public EventImpl {
@@ -852,12 +819,12 @@
}
F m_function;
typename TypeTraits<T1>::ReferencedType m_a1;
- } *ev = new EventFunctionImpl1(f, a1);
- return ev;
+ } *ev = new EventFunctionImpl1 (f, a1);
+ return Ptr<EventImpl> (ev, false);
}
template <typename U1, typename U2, typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2)
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2)
{
// two arg version
class EventFunctionImpl2 : public EventImpl {
@@ -879,12 +846,12 @@
typename TypeTraits<T1>::ReferencedType m_a1;
typename TypeTraits<T2>::ReferencedType m_a2;
} *ev = new EventFunctionImpl2 (f, a1, a2);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
template <typename U1, typename U2, typename U3,
typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
{
// three arg version
class EventFunctionImpl3 : public EventImpl {
@@ -908,12 +875,12 @@
typename TypeTraits<T2>::ReferencedType m_a2;
typename TypeTraits<T3>::ReferencedType m_a3;
} *ev = new EventFunctionImpl3 (f, a1, a2, a3);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
template <typename U1, typename U2, typename U3, typename U4,
typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4)
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4)
{
// four arg version
class EventFunctionImpl4 : public EventImpl {
@@ -939,12 +906,12 @@
typename TypeTraits<T3>::ReferencedType m_a3;
typename TypeTraits<T4>::ReferencedType m_a4;
} *ev = new EventFunctionImpl4 (f, a1, a2, a3, a4);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
template <typename U1, typename U2, typename U3, typename U4, typename U5,
typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
// five arg version
class EventFunctionImpl5 : public EventImpl {
@@ -972,53 +939,48 @@
typename TypeTraits<T4>::ReferencedType m_a4;
typename TypeTraits<T5>::ReferencedType m_a5;
} *ev = new EventFunctionImpl5 (f, a1, a2, a3, a4, a5);
- return ev;
+ return Ptr<EventImpl> (ev, false);
}
-template <typename T, typename OBJ>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj)
+template <typename MEM, typename OBJ>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj)
{
return Schedule (time, MakeEvent (mem_ptr, obj));
}
-template <typename T, typename OBJ,
- typename U1,
+template <typename MEM, typename OBJ,
typename T1>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1), OBJ obj, T1 a1)
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1));
}
-template <typename T, typename OBJ,
- typename U1, typename U2,
+template <typename MEM, typename OBJ,
typename T1, typename T2>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2)
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3)
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
- T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj,
+ T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
}
@@ -1060,55 +1022,50 @@
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (void), OBJ obj)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj)
{
return ScheduleNow (MakeEvent (mem_ptr, obj));
}
-template <typename T, typename OBJ,
- typename U1,
+template <typename MEM, typename OBJ,
typename T1>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1), OBJ obj, T1 a1)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1));
}
-template <typename T, typename OBJ,
- typename U1, typename U2,
+template <typename MEM, typename OBJ,
typename T1, typename T2>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj,
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
@@ -1156,55 +1113,50 @@
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj));
}
-template <typename T, typename OBJ,
- typename U1,
+template <typename MEM, typename OBJ,
typename T1>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1), OBJ obj, T1 a1)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1));
}
-template <typename T, typename OBJ,
- typename U1, typename U2,
+template <typename MEM, typename OBJ,
typename T1, typename T2>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
}
-template <typename T, typename OBJ,
- typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ,
typename T1, typename T2, typename T3, typename T4, typename T5>
EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj,
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj,
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
--- a/src/simulator/time.cc Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/time.cc Wed Sep 05 18:35:39 2007 +0100
@@ -414,12 +414,12 @@
TimeStepPrecision::Set (TimeStepPrecision::NS);
- Bind ("TimeStepPrecision", "S");
- Bind ("TimeStepPrecision", "MS");
- Bind ("TimeStepPrecision", "US");
- Bind ("TimeStepPrecision", "NS");
- Bind ("TimeStepPrecision", "PS");
- Bind ("TimeStepPrecision", "FS");
+ DefaultValue::Bind ("TimeStepPrecision", "S");
+ DefaultValue::Bind ("TimeStepPrecision", "MS");
+ DefaultValue::Bind ("TimeStepPrecision", "US");
+ DefaultValue::Bind ("TimeStepPrecision", "NS");
+ DefaultValue::Bind ("TimeStepPrecision", "PS");
+ DefaultValue::Bind ("TimeStepPrecision", "FS");
return ok;
}
--- a/src/simulator/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -47,11 +47,7 @@
def build(bld):
- sim = bld.create_obj('cpp', 'shlib')
- sim.name = 'ns3-simulator'
- sim.target = sim.name
- sim.uselib_local = ['ns3-core']
-
+ sim = bld.create_ns3_module('simulator', ['core'])
sim.source = [
'high-precision.cc',
'time.cc',
--- a/src/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/src/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -2,6 +2,7 @@
import os, os.path
import shutil
+import types
import Action
import Common
@@ -16,12 +17,12 @@
'node',
'internet-node',
'devices/point-to-point',
- 'devices/csma-cd',
+ 'devices/csma',
'applications',
+ 'routing/global-routing',
'mobility',
)
-
def set_options(opt):
opt.sub_options('simulator')
@@ -38,23 +39,30 @@
conf.sub_config('simulator')
blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant()))
- for module in all_modules:
- module_path = os.path.join(blddir, 'src', module)
- conf.env.append_value('NS3_MODULE_PATH', module_path)
- if Params.g_options.enable_rpath:
- conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (module_path,))
+ conf.env['NS3_MODULE_PATH'] = [os.path.join(blddir)]
+ if Params.g_options.enable_rpath:
+ conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),))
## Used to link the 'run-tests' program with all of ns-3 code
conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
-
+def create_ns3_module(bld, name, dependencies=()):
+ module = bld.create_obj('cpp', 'objects')
+ module.name = 'ns3-' + name
+ module.target = module.name
+ module.add_objects = ['ns3-' + dep for dep in dependencies]
+ module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
+ return module
+
def build(bld):
Object.register('ns3header', Ns3Header)
Action.Action('ns3header', func=_ns3_headers_inst, color='BLUE')
+ bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
bld.add_subdirs(list(all_modules))
+
class Ns3Header(Object.genobj):
"""A set of NS-3 header files"""
def __init__(self, env=None):
--- a/utils/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/utils/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -4,23 +4,15 @@
def build(bld):
env = bld.env_of_name('default')
- def create_ns_prog(name, source):
- obj = bld.create_obj('cpp', 'program')
- obj.target = name
- obj.source = source
- return obj
-
- unit_tests = create_ns_prog('run-tests', 'run-tests.cc')
+ unit_tests = bld.create_ns3_program('run-tests')
unit_tests.install_var = 0 # do not install
unit_tests.unit_test = 1 # runs on 'waf check'
+ unit_tests.source = 'run-tests.cc'
## link unit test program with all ns3 modules
- unit_tests.uselib_local = env['NS3_MODULES']
+ unit_tests.uselib_local = 'ns3'
- obj = create_ns_prog('bench-simulator', 'bench-simulator.cc')
- obj.uselib_local = "ns3-core ns3-common ns3-simulator"
+ obj = bld.create_ns3_program('bench-simulator', ['simulator'])
+ obj.source = 'bench-simulator.cc'
- obj = create_ns_prog('replay-simulation', 'replay-simulation.cc')
- obj.uselib_local = "ns3-core ns3-common ns3-simulator"
-
- obj = create_ns_prog('bench-event-collector', 'bench-event-collector.cc')
- obj.uselib_local = "ns3-simulator"
+ obj = bld.create_ns3_program('replay-simulation', ['simulator'])
+ obj.source = 'replay-simulation.cc'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,338 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005 (ita)
+
+import os, sys
+if 'PSYCOWAF' in os.environ:
+ try:
+ import psyco
+ psyco.full()
+ except:
+ pass
+
+VERSION="1.1.1"
+REVISION="1420549696"
+INSTALL=sys.platform=='win32' and 'c:/temp' or '/usr/local'
+cwd = os.getcwd()
+
+def decodeAscii85(s):
+ out=[]
+ app=out.append
+ s=''.join(s.split()).replace('z','!!!!!')
+ p1,p2=divmod(len(s), 5)
+ stop=5*p1
+ p3,p4=s[0:stop],s[stop:]
+ for i in range(p1):
+ off=i*5
+ a=ord(p3[off])-33
+ b=ord(p3[off+1])-33
+ c=ord(p3[off+2])-33
+ d=ord(p3[off+3])-33
+ e=ord(p3[off+4])-33
+ num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+ x,p=divmod(num,256)
+ x,o=divmod(x,256)
+ m,n=divmod(x,256)
+ app(chr(m)+chr(n)+chr(o)+chr(p))
+ if p2:
+ while len(p4)<5: p4=p4+'!'
+ a=ord(p4[0])-33
+ b=ord(p4[1])-33
+ c=ord(p4[2])-33
+ d=ord(p4[3])-33
+ e=ord(p4[4])-33
+ num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+ x,p=divmod(num,256)
+ x,o=divmod(x,256)
+ m,n=divmod(x, 256)
+ if p2==2: app(chr(m))
+ elif p2==3: app(chr(m)+chr(n))
+ elif p2==4: app(chr(m)+chr(n)+chr(o))
+ return ''.join(out)
+
+# wafdir is needed to parse the command-line arguments or print the version number
+wafdir=None # SPECIAL LINE
+
+def uncompress_wafdir(newdir):
+ file = open(sys.argv[0], 'rb')
+ while 1:
+ line = file.readline()
+ if not line:
+ print "This is a stripped-down waf, there is no wafadmin directory available"
+ print "Please set WAFDIR to a directory containing a directory named wafadmin"
+ print "Or use the full waf version available freely at http://freehackers.org/~tnagy/bksys.html"
+ print "\033[91mNo wafadmin: cannot execute anything (error)\033[0m"
+ sys.exit(1)
+ line=line.rstrip()
+ if line=='# ===>BEGIN WOOF<===':
+ cnt = file.readline()
+ if not cnt:
+ print "Corrupted waf (1)"
+ sys.exit(1)
+
+ line = file.readline().rstrip()
+ if line!='# ===>END WOOF<===':
+ print "Corrupted waf (2)"
+ sys.exit(1)
+ break
+ if not cnt:
+ print "Corrupted waf (3)"
+ sys.exit(1)
+
+ cnt = decodeAscii85(cnt[1:])
+
+ # create wafadmin
+ import shutil
+ try: shutil.rmtree(newdir)
+ except OSError: pass
+ try: os.makedirs(newdir)
+ except OSError:
+ print "Could uncompress waf-local into %s"%newdir
+ print "Please install waf system-wide or move waf in a writeable directory"
+ sys.exit(1)
+
+ os.chdir(newdir)
+ file = open('wafadmin.tar.bz2', 'wb')
+ file.write(cnt)
+ file.close()
+
+ # now we have the tar file to open
+ import tarfile
+ tar = tarfile.open('wafadmin.tar.bz2')
+ for tarinfo in tar:
+ tar.extract(tarinfo)
+ tar.close()
+
+ # cleanup the tarfile and chdir to the previous directory
+ os.chmod('wafadmin', 0755)
+ os.chmod('wafadmin'+os.sep+'Tools', 0755)
+ os.unlink('wafadmin.tar.bz2')
+ os.chdir(cwd)
+
+ global wafdir
+ wafdir = newdir
+
+def try_wafdir(dir):
+ global wafdir
+ if wafdir: return
+ try:
+ os.stat(os.path.join(dir, 'wafadmin'))
+ wafdir = os.path.abspath(dir)
+ except OSError:
+ pass
+
+def find_wafadmin():
+ global wafdir
+ name = sys.argv[0]
+
+ # wafadmin may be in $WAFDIR (developers)
+ if 'WAFDIR' in os.environ:
+ try_wafdir(os.environ['WAFDIR'])
+ if wafdir: return
+
+ # waf-light is a special beast
+ if name[-5:] == 'light':
+ try_wafdir(os.path.dirname(os.path.abspath(name)))
+ if wafdir: return
+ print "\033[91mwaf-light in use, wafadmin not found -> export WAFDIR=/folder\033[0m"
+ sys.exit(1)
+
+ if not wafdir:
+ dir = "/lib/waf-%s-%s/" % (VERSION, REVISION)
+ for i in [INSTALL, '/usr', '/usr/local', '/opt']:
+ try_wafdir(i+dir)
+ if wafdir: return
+
+ # remove $HOME/.waf-version if asked to
+ if wafdir:
+ if "--nocache" in sys.argv:
+ import shutil
+ print "removing the local wafdir", wafdir
+ try: shutil.rmtree(wafdir)
+ except OSError: pass
+ try: os.stat(wafdir)
+ except OSError: wafdir=None
+
+ if wafdir: return
+
+ # look in the directory containing waf
+ if sys.platform == 'win32': s='waf-%s-%s'
+ else: s='.waf-%s-%s'
+ dir = os.path.join(os.path.dirname(os.path.abspath(name)), s % (VERSION, REVISION))
+ try_wafdir(dir)
+ if wafdir: return
+
+ # not found, uncompress
+ wafdir = dir
+ uncompress_wafdir(dir)
+
+# run the test
+find_wafadmin()
+if "-vv" in sys.argv: print "wafdir is ", wafdir
+
+# Update sys.path and import our modules
+wafadmindir = os.path.join(wafdir, 'wafadmin')
+tooldir = os.path.join(wafadmindir, 'Tools')
+sys.path = [wafadmindir, tooldir] + sys.path
+
+import Options, Params, Utils
+from Params import fatal, warning
+
+# Set the directory containing the tools
+Params.g_tooldir = [tooldir]
+Params.g_cwd_launch = cwd
+
+if Params.g_version != VERSION:
+ fatal('version mismatch waf %s <-> wafadmin %s (wafdir %s)' % (VERSION, Params.g_version, wafdir))
+
+# some command-line options can be processed immediately
+if '--version' in sys.argv:
+ opt_obj = Options.Handler()
+ opt_obj.parse_args()
+ sys.exit(0)
+
+# now find the wscript file
+msg1 = 'Waf: *** Nothing to do! Please run waf from a directory containing a file named "wscript"'
+
+# Some people want to configure their projects gcc-style:
+# mkdir build && cd build && ../waf configure && ../waf
+# check that this is really what is wanted
+build_dir_override = None
+candidate = None
+
+lst = os.listdir(cwd)
+xml = 0
+#check if a wscript or a wscript_xml file is in current directory
+if (not 'wscript' in lst) and (not 'wscript_xml' in lst):
+ if 'configure' in sys.argv:
+ #set the build directory with the current directory
+ build_dir_override = cwd
+ if 'wscript_build' in lst:
+ #try to find the wscript root
+ candidate = cwd
+else:
+ #wscript or wscript_xml is in current directory, use this directory as candidate
+ candidate = cwd
+
+try:
+ #check the following dirs for wscript or wscript_xml
+ search_for_candidate = True
+ if not candidate:
+ #check first the calldir if there is wscript or wscript_xml
+ #for example: /usr/src/configure the calldir would be /usr/src
+ calldir = os.path.abspath(os.path.dirname(sys.argv[0]))
+ lst_calldir = os.listdir(calldir)
+ if 'wscript' in lst_calldir:
+ candidate = calldir
+ search_for_candidate = False
+ if 'wscript_xml' in lst_calldir:
+ candidate = calldir
+ xml = 1
+ search_for_candidate = False
+ if "--make-waf" in sys.argv and candidate:
+ search_for_candidate = False
+
+ #check all directories above current dir for wscript or wscript_xml if still not found
+ while search_for_candidate:
+ if len(cwd) <= 3:
+ break # stop at / or c:
+ dirlst = os.listdir(cwd)
+ if 'wscript' in dirlst:
+ candidate = cwd
+ xml = 0
+ if 'wscript_xml' in dirlst:
+ candidate = cwd
+ xml = 1
+ break
+ if 'configure' in sys.argv and candidate:
+ break
+ if Params.g_lockfile in dirlst:
+ break
+ cwd = cwd[:cwd.rfind(os.sep)] # climb up
+except:
+ fatal(msg1)
+
+if not candidate:
+ # check if the user only wanted to display the help
+ if '-h' in sys.argv or '--help' in sys.argv:
+ warning('No wscript file found: the help message may be incomplete')
+ opt_obj = Options.Handler()
+ opt_obj.parse_args()
+ sys.exit(0)
+ else:
+ fatal(msg1)
+
+# We have found wscript, but there is no guarantee that it is valid
+os.chdir(candidate)
+
+# xml -> jump to the parser
+if xml:
+ from XMLScripting import compile
+ compile(candidate+os.sep+'wscript_xml')
+else:
+ # define the main module containing the functions init, shutdown, ..
+ Utils.set_main_module(os.path.join(candidate, 'wscript'))
+
+if build_dir_override:
+ try:
+ # test if user has set the blddir in wscript.
+ blddir = Utils.g_module.blddir
+ msg = 'Overriding build directory %s with %s' % (blddir, build_dir_override)
+ Params.niceprint(msg, 'WARNING', 'waf')
+ except:
+ pass
+ Utils.g_module.blddir = build_dir_override
+
+# fetch the custom command-line options recursively and in a procedural way
+opt_obj = Options.Handler()
+opt_obj.sub_options('') # will look in wscript
+opt_obj.parse_args()
+
+# use the parser results
+if Params.g_commands['dist']:
+ # try to use the user-defined dist function first, fallback to the waf scheme
+ try:
+ Utils.g_module.dist()
+ sys.exit(0)
+ except AttributeError:
+ pass
+ try: appname = Utils.g_module.APPNAME
+ except: appname = 'noname'
+
+ try:
+ get_version = Utils.g_module.get_version
+ except AttributeError:
+ try:
+ version = Utils.g_module.VERSION
+ except AttributeError:
+ version = '1.0'
+ else:
+ version = get_version()
+
+ from Scripting import Dist
+ Dist(appname, version)
+ sys.exit(0)
+elif Params.g_commands['distclean']:
+ # try to use the user-defined distclean first, fallback to the waf scheme
+ try:
+ Utils.g_module.distclean()
+ sys.exit(0)
+ except AttributeError:
+ pass
+ from Scripting import DistClean
+ DistClean()
+ sys.exit(0)
+
+try: Utils.g_module.init()
+except AttributeError: pass
+
+import Scripting
+try: Scripting.Main()
+except KeyboardInterrupt: Params.fatal('build interrupted')
+#import hotshot
+#prof=hotshot.Profile("/tmp/proftest.txt")
+#prof.runcall(Scripting.Main)
+#prof.close()
+# ===>BEGIN WOOF<===
+#6<\%_0gSqh;d#""QRi4MNW9%Ys8;Tjs8W-!s8W-!s8W*A!!!?/+s:iT#QPE@+:JNalM^0u7E&7,zzU5BWbz!oq"M1#9$/UR'Q@h2E0$HX4Xf:2NWkAtYU?>A0Z5XLk)fl$_aFmsXWhU_,Lb16eF=;LtY_;4@7:GM-3XH_G<FH]L6)A#/tII6?F=n!f<;Dmo*/EZ8k06d=rcDllJO.=Kk,'Vu-N>C2j>#5d`0]WUYfGLm@uTQ\8/5QGJZ:^!al1hiXX4Z1]3!!bahTQJ6W5j?(>6<:;j),Tb;_rq(S"]4Tp^n;;I($KLb"*XME*kPRs*a8a2mA3[.1[C%gSaknoQEB!KJ-V"e78sKLqQ7f<[g/oQpRq#,Vr%IVd/!*kI"26_!32kCX@/ja$DLgq@fQK/-iaSS!!!!";/3L+=0I&?f7!+ek.8]W)APb35bL",pV+k_pMdk@?Ld<Y]670LFZJF2mr[DB?KZ6.4blath7_MfLYfaNgfMf\^@#1iBpE`'[U9nS"GEe>FY3?)DUUjT#DH7:>M`,<SnH%`#(?(umV$WHA_1emlV*c(Y+AeLXkm@X]tPQVS*bPYeRe1Ac1U,NqYGWCql]g;mpCFs]XG!/n$gVSDI-Z:jmG:??2)%ll,r\jH+LV)o71Ie]=$)heun>MT5>M/qVQ)JWr&9p34.AoCg76^f"/EJ?[LOSc!G2QpN!kMlQ5PB>Qe9%Xo[YKlb;dNP`]gkf@ssK;9s,dbO;"NT3MhD^$AIlhY2:7flm,"G4"[>Y<&9$D@`gThd^jnZ_MkF;8&MfhT_KQmgJI5!mpgHlFYZOZqC'b^!'!4K5Y]WkSeBG<@%rN>Lj:QF;+aoG>u01g@k+Y`YU:#VlpC;Vn7Acp27T:*mH>2S\UodkG^QSWW;eD-_iLEpYGS9D;0"0)e=XTS%GZeH+R"qG6Vro=)?^%<8/(-0o!<.!:A;%gu=t9pWoEpgV1/+h`#2J>>)ZQbs<_*Sb@9_n8e[!qoO3!";6&f\`o3cnr@F4mWY5$95Q*D:)19M*#1*/qjW`(cF0ohH"Sbcj?;r*gO8fKJ^K*SY2=G/[tW[F]b3d#aR,7p%`R)?hV@.e\_[;n;U_NV[bIcYT6Hej%op:XeGJR,RIVId78h^iJ?PM]q?Dl)pH7hk*r!DC]u.OU?Z#Pf^%]/-]_@H?DVG!CXk<*KmsE[D2n-r&Z1j9lpNOa;T\4qGD4TF@T(]d&k69`8a5+JD-#2Z4^"r*:3\V7INr!(i71t/D!e`=D!/W),8%`Cj]6isn]cM<u]s)edCt<#nC4!Y-%ZToRcVE6;_X"87j0a'b^"sJ#mV>^NFjX2S"V3l^mpg\RYT3@:>!Dht^,jl`_Y8=.c(64<o7=Rc%W+A649^H-]Beo'oOT\RFdWr%>"dKXeQn`/[l`pC0`([UDk<"N=94JdUXD?tIB\s`!.]Sb+:)W`d$OrL)?aTBR8Mp5ksK.e7R<"V!!!.T+p``HN<'#R!hZ;9rDPPH]i3T2RSQjX;ot`-%0K</JB.]j!!5JTJHJ.?dg3n5d*SAJ7[c1t1t9Y2RP=t/9Za9A4W9rk6R,*p)J$e-4[BB'&I;)L+dC*KIYjufUX:ps'Z`L-4fW4oO9pLn$mPt,-CC/+!&6;9;F1tg9`QN/QkLg+9f*R_<;_EAW:D=44Z905<:rC/:J_-YB\IuM!!!.jLk5a11)^/nWVTCaOm4dMWVU0nr@2X+Rjl$I!!!!.!!!!@;ucM4qZ.IO6soj1TF)7(ckJ3ijs&)FEtN5EWf!dL8YBIBNs#_"[$Zr=9?#ud3rGOl]6C@/;mOQie"[q5C0Zs*^!rN_?LmLG?MDe@%YTARr@(WV5NpRud166n<=Y`Vr.6Agoe"WT2TP"0d'E*qpEaQTk-%`FP](F)B(0G2[Mh&@QUPe3=&N@h``onhCNYu30!oHB@M7_B5O4.O-nccRK*7!]_9XW8,,dqq%g`J;J4&H!ne='J-j?E?)A&_`'I[!"ndl4%O),t,91_\&Lp8)\<'85#0VJ0*I3Ha5E%)QU&)R`)-p]$f&YL99&:d+r;@3:]9M`dg,4jp1PT`NO*T5>>!$%8JQ,isPJ`I(_*2iqB_BAV?,)f%m'T+R?Tj/]O&cNVHHmAUBFJ)M[a@.lm9LU2t3gM1h8cL-RdLdWh<<GTVe.Dcq'ho,^8CGH'"V=N3&;4"\5n$[@6561`,#AFc6k(9`'2:8[;&%GI77fmH8J'-D784J\;*`N&bXb9P'nO1p"&ME?<=G!X1^,&mS4um9;%Y3E'LbEP,qtT]$jBQ10ml_?=]o2@R@tsrQ9knH-qY[%.Zf5rWX4t0RUTuE$<jEd<iUh1A;LMJLdk!O6A:7?+d**\$7%&K$AO6_7\V)9VFDt&KN]^sWFcK8,%QO@MHGZY#bi2.VFcMo@Us2KU/CujL6<`m#sqg-TVe/(+Fo3DMI;UGMBiO$@ORt-.O$9M#cK-i-<a"CRRSE_6BWLLR$N9"@&@CeL5;d[$4>NV%3lH^70+kPbWurM"Ubm[_%@s3!@.eH,m6RM"VVRa^dO;B$l)I@,sagc'i`+J`=Pu]:dHonP`-:j;\9^#6Ua?t6:1ke6pUhb`(<<^&Oa^J6U=+,&JA%GKG$]V;$96["9hK+PT^Tk'ZEL0:t%,Bd"KV2727LS9T9TK<#$[p6ps?V1pg.SYZ4)U'N!1G,r66gKMtRd&i?DG_[I6t<E')l5Y/^hbXiN\7'd$<;*tpn`CrZ3!>@aV8J*f0;^;oNPXJ,8$OmeH`.LTS$PQFW'*S[TPS$lG1GVNq92)0U5tOCB&/<M[71h*a8MqrjaWuu\&Houa0f)dj<7&u\,Z'RjdRck9:b4:T86$'l0iJcS1CHIS&440':f,@m7$0&/5m9Og&r]Zs:f&E:ZkT=S0h=PtOGq@_'GXUK5seL9&/@i(1)/(=/Hl;D'TiJ"$q*BM<"V\76kfq28CC*cd_doc,f!C`#)t#s1pI]%"JGrQ/3uTrWBsNP"YD5r9aX^V,=G(f"Am'''L3@p+U#%a<<1JZ&4&(i1dNt"'29oQ,YCp."9_+Y0[rc.;aj+Y'SR\A;ai2O<D?I:6NKSH"]2!`"J[(B`(_LV&BrB*&qVtS+@smI%89/_;%-"6Te`i@6Oc<,=Wo,ZTn9:r81?k<$AOCH$<h2#Pc5iPUnWu".0?6?-43@9RSlbXRJ(,b6pr*SVZ]C!5uS38C`3>S(*oi7$%aW>)(HP\#`'glVCAL=Lo*WZL`g5_!\.rR$5S/DTI(jJR3Dqe8j]CgTS??rPaW^cP(K?nq*K'M784CL1BLQ5'L9T09b`^(9%>XAN=,k69/6Z&#f+U15nGda*A@dR3T,"&fGR\_J>alb5_=\9TdlM*#RDb'Qt`9#,bc-=Q4aHM#RQb>A-N@?)G-f7M1UuV!Z<jN&Hrm]">`n*%5B:c1C410"Xt]*`"Fb'OAmr4&P5fPN>4-=1/ftp:st:g'bF3`9%-*].7l!cK#7Wn1lWma5SOIN.tp8U!(\m["%a4>4cCp)`'I5)+\PN[,qpVh:_=Br#n2do8u!l`&OeDg70Oo&_$lM@0bh!Jb;,.hKeP8=,SJIWb"DfW<Cml]YmC_2'Z=]Z:dl*i3J>f`6V'l_!>8(&YfTiV6j45Y#gB+Q6Hl+@!DQCq+B(iu[$7C3:f,)!1DEeU8PE)0;)1g5d8`an:t&E:9LCTIb(Tsh;cQ7";af![<'jKI`6cq16NES)/4hBd&d9]mZk5"AZOp2;";*CeYYtfAV(E!A;O%BI"N7QB6kGP.'b]"-;_T@\&O?Cb`!e%.'NHA(&-RYT<Da&k8OTm-;c$"Q!mi)_!<aqW1djbA.7lm$&QLC#_Sn4W`DfbF)^^GO$'qGsMP6\FQlqY#M&)5*:hZPYB`t4;#RG0S,&(X--AX*_"pp*Z$>BR-JLDjpK*FW;8kKekTV@R9-A"Q.+:;M<TS[*MW)TLGBnRCdU*`3[U7*M\R$iPhP(;o0d`0,$(<)TF8O63-PZ1LV_J*9YKTdt3/.j.d%+;Ls>XUhRJYZPnOX2E=9M6!19#/p[&@0Nt<00BY`.V)`_6=-:W>[+\@:C(J-kqMo-n6*$JV#'q6:=-W'SZ`U.7?e$U4SgX-N<Ej9LMhg5s[h)9gHo*aZr`=0I8G)b>SQW&HY?H,r#uf.8rYZ0b6m5Q!t)d;Q-<t+s:QpBVH,SO6\bFKRjh75mX_a'G@2b+L4=%PQVPV"Um^c"@,:E;%Q.$eO9Wu&s/AF7+0;a0G)Hl#nk]"d%q"J/49Vp/L;W1#ssjZ8e=m@P^Da1@dYsL8t0gs1^E4Tc]ljf\U+7!=L]tPBd`fXLmG]mJSHen&b$HgqChY;,&eD1ao$@pa#I+N/5hk&`_r82L/>t>s-j*d<Z1]K$0P9H4[oQiD#_%6:Z\d;,<0V4;[esVV8mPLJ%k.)7KL8`=r;!<"RBk548G4'BgV8eT-RaESY`%IM1=O&D]/#^V"BZO.)a-8*Okk5`TDE^Mb4s,-t[4O)YmA!ZtZ"E>Ws,EdI]%Cr(m4d>e0kLPcTrcnGMfkMIt2d@80uNa&N5E/mY[Y2cPmY^KAApchTGs,*%kFc2X$UU,l\(FVC$6&p?t[,3<q((%g#7-S.$TpqoL,ltnaGN6d7dYWS)Y;()Vu$*ssOOI!l"k*96o="g(Z8tpB!7=iS?jY4V^fAW]f+q,MAOZcC6DMh*j"q3G$As8X[(7)he;'M$h:$N7E(QSa%IM9DbUV8)PF,:aQN0o'.].N$M#2<Yccg-%kL-\:MB^H]_gG<nE(E5h[Ej#8ZIKJjtU/\*@ltOPn2TG]BTVsg\bS3R6^*a'1Ht+<oIYg569c'3]5()IQM)QXs\5,YqVidU8]D(=o_4n\?MD+rQEQ#mfQk>r=>mbD$@qt)SQh<X7B;QA6]FZ=r,O$>RbC8\U2["2n>ia:T<6)6H\9_%A<;W*o6.j_H>H$U++PXZ<W^!dXWN$6Z8pY@hdspBR9-+&rqLISGbU*HrF^K(9ks:'<ppf`E7Va.$PG<4UE@[pk2WuFneD8VV5CGopfIq/tDG;X==M:g^EC#c)LP(Tr*jj4?lI_N)&s7JLK2=Q"UC:!HhS0n.:W)JqHi'VVk;Q%-$EiBO@tJrn!0eSuIQ9=,+m+]VH-SB_l$B&<_bE_Sleug'<noD]RY[Y/9K?lYlL^YFP]KP9)@kJ+:os&`omN_8=sT]'FW0"OEr3F>*lD;&Gm4dQPuVA;ap3,k@Fh8'`led1@no?to3''K0\[i@#_)("eY9d).6dmEWFZUA-n&]8pH/)rP:S^McNds_PS9gslAVP%@r!r4/Nj>T.<D7foBn*i=J?ha?0a9^ZIP;;b,@HZpA8-n@Jl+"Jor/8GG5j7Tn*RYVVS>T$;d6DZL#122"e$EZh\m)[1PrHDp?=E7-lps8;>TGnJ[Wn,hQC"7;Fup<LE&IbmDsV&O=@[A%J?i6nOu`lFEuQqFn5P)8gK";pq^o'gcW"M3UN_D-*d1\L(QRX?Yji'D=EG7:DimU4kL:$N3"q-;uZE'^VQ^&78MYPiV<if%;D\g3Yro/n"GMYG,PJ=C8)A7I:';TY`1s-ENn%2I/U)61-@YIJBPsk;`aFThSpja![sm_IL25)>4f-9;m:c=^iS-g^"nA+4TN9k]B>+;h:mbT1Dern<)TjE2tMkMN6FSFp?FUX<N$8bGcW3KMZ)0#rZZnL!h26,Z0?/PsUKZU7@5b#&rsd>P,Oi'blRY;Pr*FG9N_5#c7X7K3!a.10c:$q<IN15rr]?V_Nd9Z1cSe#Jj[]'5%t5-9<P,#]oRa61+!<[n\t/%Fe8#+Z)X1S_p].Za1o[<lG:m-M7_*/de!=ZVpb(KdB5,R%Ye?[P2::`/#aoBd-dO0RjQP/p+@L^)DSRD[cL6O+L!gT'O1#PAeB+Vbki%4!prUoVm_@VF:sfTWt#TLNLoNmA%?&iDm:5`.a%.Dc5"<$'mhI1([_#9SR^L-ntXX`!W'2!@1eddJ1?09?r4*@nqsm[-+P`7@d+8Ct1^&*V"G&ZAUNjnE[b<9#=[R03a)#OW:2c,n*=dA^/>H]4`TcKcY3^\$a>W@apXq5K)]/Yq>h\7Lcos_R&ES?Gu)UG&1P,Pua+r$;-EOWWCDcB]V;!@/-eF?MjK;^@2(k8R5U0JsbsjdqQrm7.E4UBap7PipE&\MlAk`TpX!=M.]U3*;WX`KW.PI*RBs_$l.D?2Ru*<W1@fe@q;&h,jXOU&a#hb-E(!6)WiQCKsoB&nLNm+kMjKG(WQF2Y]@Z!Ct0f6:s]a+9r-M8k<A9Xng*q]_"&o@^Gg#\:B)<)Q'W&")kj;CoJ#_nB&gap:<HaK(!!\`2p&Y^j0@k$Z,)oHoEtHOEUtF?=-KYrZSX.%U(5Q\[i-U[*AJpjpaeG?B!i,h%eu]0Z@`3^MK8eW/1h93CM6iYpL;pa+sX`F]cGg1(@DpCF_?qK3H/@#c?#_C/6J6*=F'_OX1VL>?Zut73*Z!R=$uq+;^g4Fq.flXjcb_C:NBJJ%O"SWZ_2ra:ZCOX26]pEG(UZ-jAmC%I,@3?I]0+8b:IQ8"VPinq+oFEB&:W#a8J!CAeQq.E0J+]jQ'/NlIe9P_Iobr9@rP3][1+mXd\ro%lE=(,Ge,sBi7KpOJUhV)cI5K<*@R`fDI&KlISf?'g&F([mdHjS8-6f#OOLIQ1q,N0sDWW_e5Ia[AW?ajb$>n$bl?0V"Ves4qEp?WQ-M^e&4_hG+W<B?cL%He+ZF1qIe>qg>)">&%pVrZ7,mR=\\N=i@;:.c271V*-KB911'qp"b%\S9Xla^b*F4bBTARI2CUDD&;\62U/Gs;om+GIc=b%.T%/p8B-p2Io5P[=U*^Nd6`98;Eq[qY@p/b11o$L;j;j.7i=dq_i"[pB?)5Rg=*4GbpIbc?>J\An0g<*'jucP.`T<;?SHRI]9d]n8rS@!9]B8rUiHI+*2h-SJh`:Ja1L+RKLc"'5ZtDM>WKoEX-f2r<qG3gLgM6jrPZ_j#&#IoieSu*7CPTa7>unUHIr;Mj>``QkAa6>:2qhp_/ku-*6`e);E7SsqA?F6,(*>B+H[a\LOrjEoPATdEcsp0!n+&H>0_d&<+k]^(#_`NnenMEr"7^.Zm]s6=Yi_,qrDa?12SG!4-AGc[0^r$\+/u!E[tLpfM5QElOD`7CZT_0EU+gER`6n8*X\Z+D.a:)?<S"gGd)5hnfg'h3cP(=n\C+*rYYmF?5pq6M=eO]Q6d=)B&]CqP1ujHRon_^`C8CrH_rKc)^7u@]_De?]0L<->@Q&oG+Cs[$1s(n<7s3E[D-Ej$^@ROB8LE;6%ghsB\l*geF/IsQZ5MhAEoY1l:H@7WXPt:l_[T/CLMcRG3dU?i=!N_MNY[u#D0Itrd#of4S<pj79I:748L1ae[PXrg%1K2eU3CKM3](njc6ZYj'9ht@@_1kE=1JVT,*SG5pJQrp["fe$p*JF:[:"c-C(:[rc^_<-oq%Vd`]]A2T7t\WoB1CYrja&ZE+5PqQ/B0:l,rX6'>!PC,l.Aj,:%9J%Qu3Xb7Nd,fj?a<.`M&E_a9_C)?^J;j2toZs7psO,.0iFY9I3:4h,9A54MOu&#.;*:)%E%F"69,E4NgNf7e;!/J3!Cp"YXrQ;tEkj^b;_bB_7=G\SC$Oj510U8<-)\ii&L]?6NKZ;,+iM5J$>.6=/#M.l'Y\ojV][<.jQk=$XiiTaAoBs]/LdD8>i,djHX]^GVqdnKMN*=6BE22P"PUm6;`^kmIsP(p+XP!k(k+1aoh.*^Y3DWo+ICLYXfYG8nJ,i:Ur*MWM)#d\3EkuJqdm9rjk:HNM`\5DKV-d"6PM:2$N>G`bg,ipeO'M#cgWTG)e.he[;rD0;ZG'%B;(lK68?nmVno-"Mc&(=\.@N(iu;4Y"C0Hi@f$q;0%$5eL#7Nr+I3N?g.,(qY0&EE?GDP[4^G3Mr1ZkB!Jmf^%TFR'=jhr2=ae&D6+UD*"cUpK/Tm0*4Kd%(L?r@=>,bIaWpEYjB+N+9&PPVHKkcNLKQ''Fq_-;V3_&St\$>%)@>B`%cV%/=VWo=9OFa'jd=31[5`gRLNMP.FCab0#'p*%3M,^tCge$<dhDj0&Q4E_emQ/IFgl&Gt/ZIpGTBr0/23=._[D6u]3nIDB$b[;=+>9`6)=MPim4Yn'm@f#:YSXa(3qYmgeFBO`Q)(*Uj94uf6h,]F`U\F,](F]g^%:W>f:)BA&omm"e2opoIR,pj.7#T:jmpo&c6#6PJTjdd_]l;AcSPfHU`+GPA)RX!*5nqa2)=`uL]FaAuD^)ej4QpW_g-s$9j6DJ`mHfWJ:NCWgAiV[@b-OZf3N]I]#dn7"VU*ge8)=ubX4'.l8Dh>)5?g3CgcWak-+N4ut0\'5F\n[n;=rLCt.Bj:Q)R3r"pqFsL[jpSPM]qC@:oF;Nh:G%VfO^T$;[lQlI6CZijeOj^*hDFCHm-QAKP,0O]Vcb=@shiAjH];;VLN22Ylf)$N>"c&8Ia&/OFPe"^X8,$H-[lKq>&'qHQi?.G"isQHmEVWNj)63HS_"emH1^V!Ff0O3U'G#LIold=)nh+.+e%7;Z#D`"G`o(oG"Y&mX%_er#o?.>]Ps)&j`t]OPSco>!4W%Y4O0%e:pRE?s73D(-N;+;E`j*'i\>MG'nVYOj]$1B@/`G6:CdV'##ch6=t:Q6ZpLDiI'l75)VD*JtA7dgt#iPH+nAdOm747O+''ffiRQr?,G5/>te>m``6`hS)8\k'Ih/_<%>-]ic*+,D&U?&r=XUr+eHCT.t\%'jf]C>Oac1P([3_Q2,`f3"ON<&OQLP%l92em?nS^8kH@TaHn))0Iu5o^Qfj?^]19/>d]n04?dl&+\3[@k,YN)?4HRORrtSU`Qh"7UDNg;)WWJ2%,k@3P?hcXY.0NNl/1t9P1BIQLbaY.AXWC=[dLN<Yh=jT?'$#ZMbhYQ[6?kY.qXU+rD!;G#DoBS^8]@$Ea<mH?`bR[B!]n<AircU\8h?7bkb_!&I*ca[,-enT#a)e^-plM+E/Nm^Dk9mkq/G=+o<h;[3hed/5-C-@]6($<<N,jDd.c'NO6X9!n((*&cc,LXcnLm9^#O2,39jd;<),1E8:#\3aOY[jh`PSc"+N@/LTQfWVL3"mc>AH4%qttMUTr(XG7WLPhtch"0i"D)SWp#t3:(u0(X`'aW#'(3/Wg[A28ilg9@(=o1Fbg+,)U2!rAl;UI,WG%IiO9S_b8rAM\O.^(WUD^kZF1K4OIkAO*B7Hpq.\9Tq5F;jc0fmJbf^BK+VW=*$5:16sF)PTuq9#CXfnt-6$R<a.R)b'GQE2W29uo+'*=r;CFSYh8hJa%TTN:fa7caL!fmF-!8J5H7OM$:lPnu"`.=B1d=]I!ZN/o[(hRq1R$6/FSY@=N5ka0odl7@+SF_.$uK4%%9Eul^rRO)Su;=%\JN\MNP,gtN@$&LA>LNi)St`i646-sJD`eX&W/bdVC0p5]:<M#$R--mmShO,Ii6D\CHs1gXM6slMpb:0ASVV_+2u%I0m];pO6iedNFOm-i>-hRG>ja'][NK#FP#7f-%^[X^4(JKWO9_<7J2m$k!-W',Z=8INZ2ViiiJ\nL9*M!l7mT,["#r(9@[=:\[QEPh0et1MrT26]*6G#Ai7P=h':M\.beY@#SK]5Gs&>]dTe5G.VA7<kDeO_^#-FXXA^B+7%mK8D]0W1m7M(NN4m!378^s(WTa)04rubVo?d#nf/eWRJ"b)eIVYjp<@`-LV!)NnF)e$*&HoN$@V#9bfd]^c,SM_jq]&pCfpW&;2,Ia;lRd;Kf"4gJA0MJFZ@n=%9H(j5CU:8AiW>$\iZ[u>30uKJgbAOV*Y3oBUI7;K)h^B>6krqe>N.cX&^[_'7pVnCZ?EP,97k;9NKMq;imN[iJk8@rYgDjW?"Vo&WFt_,k^aUeSeOmtgGrR'TZYre:2Se.MNZ_IGNV!iK[&[_)13fpP.&c6SO,&$c!k<&4BFNUMre7X3-b>[TY"t$_T^Qd1"Y*L1S#)ejVH;mX@OV4+QTuG>KP97g]J&,+^lHJA%MM,E])g#1lm%`,?gi\A*t#XMW:>D=7Ql-af%)(FRXUY2FGttFNQ^CQSPehEEja97>,oAG!j[+-4O#koI?ZG`*\^(7@G99n>;82RpJ8QUrqN>Vkdqfd<V#SWj(JPPs:n41Xjf>nJjNK&k[!QgefJcohejJU9jE88;1#QDE:>JX(M[D]'6))KV`O&,5YPgV%*@^RH1,bngg]6egQhZPIqp^8+3"rN3)/B4&%VZ:L'@6rVPlt>Is^!l:J17Ng63b+]Ymj_d3q7/4?+;Y2o96jq0)@3,%JDUu-*+N+@[i>o,n;B\FIQXJSXcKbI<B<Tt6Y.&pn8)U@oC[+nEGSW9579g8Pb*U1]hEiITOP4)@AEKcbq()87V4_k?:E^IF6/;UXBB`)st10_I9mc8P?#f.pDK6olc8XbL;MBbi&]k&q9_(ieK,[<0HW0/q?`D[NAW]Jh_Cf8N3FehlPqdRj+);Y[mSDDX6';`kT0mOr/iLhj_Pi)[Y&Q2p5-U.r[Pdmb;.%5WkU*R7OX-tGp.:\X"'t-+jP,l?t;>q*ie,%T,D3TqcBD&8?Q-6AS:%[`:iFs=`mYW2tV@#[Zjo+lN]?^,i>]LPNKB!3;]+A\>I%+r0,+GN-W=IJ"[-9TQ^XDZ/j^tcF6q/`h?V0G\Eo^.Er%7(_Q<rb07trkk[.'[Tcao>tk=E2[CNS%b7VX-8S&J$V7J(-Jk]K\Yhqh0OPKb"eF1R^6SMh03S%6O3M?I*V=WCE"as&8(HT)X,X%-l0h+:1QZeL0nXe]d*2/OFNCCSO'Tfln1pua`,QJ4K7WZdsH*rf#qr#-3,%lDQ;6:m[19`DM8ceic+h`/TIKjIsJU;Oo6"Yp#@B?AK9JWGV(+*8Su1p\Lc,Bs!2[@o%l$7/Oga4QGb:We]tX1QGsP%5b$/EZ$T2G:%o+-U'IWqs`EAqo^m:X$fd0N1:B=K^3*qU8J\SP0!cb[4<-N&#@HP]2Ad/6&OL_iCb`[7(#:.C$+U&Z]WPpXE0>ReV#:9Hp24R'00t@"T,7fp?D$VN>7bNN+b2+m&KBs3%kB`J%&h>Y!uf2RHZ<.HG.l&rJsPq7rPa?O87$rL758Pcto+d2mttZE:HPH.^>QT)/D6h`_a2b?ZG6g^NAgkM&LOfem1eapThZTasqu<gBbd>#,p.PsQd#7&rL.Q8F?l-1=?EQbbC<&V5U'\YB#OOt=PVgKC%3,uJ2?i#:gpM.sWu8G]7DBB=W_g[+-@DsZ?JXKSt,VDM9uOFKNG4hj_Uk)qm/)?(^1^O@-2gZ)3m=ms:NK9=2NSZXBACE;cFaUM9c>,XPX*N"t1opE!>-j]EQj4ebbU7m;U_b7.AFg*HQk<$Mm!OV;C":=`mW&BBoGCD3*7TG;fTJGM%6luj3@U-/arFEJU%2;K9(4P[,R7Y_+,#^]H\>V:(i^)68+GADr9jJLi`[eK\N9Y/..D^p(cjs"^)cY+i6.JR4]%>i;j486-H-Rm=S._@RofVTTR(j0\468Z3)_Bk8cJsLcMKb8%\Sg?S9K.gMg@o]D7?a=J%OR>5i\$76F1F,f]sb2h/&>-*P9H5,S_:%r(><:N"o7hVjU_(#>]5D5!JJ5s$5r+%I;fH,h8.Wu]0tU$S.no2[_e=b]\]M^;/QNA`0kajBS3=)*Cu;FPEI1E/h[K%e#=F_":?Z7`mdik+V+%J=n5o8)a-+G?#3q,JSU7PJNodk.3LhTe^03eM^bM8<BnKK(oj6_j;\&]YWY0^4:*Hi\e/#CVSGiB%/Pg"9[+899(593jl>Iq?'q6li0g!q^B?LiESl+XN1K'lIQ!sOdWq9Oe`TEpe_LI8DK$'_#^u#5>T6F5$uVFU)to&B'+J1MbK0KsWsmG4_5l[oe\\[i05js0MV)J%P",rddSe['+>Acn3pMZ10i6LS1o1pX1t";5b53PFfeNf$Jf\$snpbU@Fgq\uXj[>,G$o6e9^!<"GdAE)c%0oE",>RY:V2^4,kLAGVfD<(WR"S.0\OHAgl4+\)Oe3.9-$+i#Dr9fUZ(%cR?(KE]d8BAP7?URE,j8lE.l2?S.\)^MZC0W)6-m@LYppGau?8TBE8fiJh,YG7!G^R-8R-YbSNVF(Ijh-1!o]7F1%VDO%DRhrQ!\8=-L&lSUCBqj62*.I!NdYO'sMkL9\G(`-r\qRq;sV^fS%HNC"(W\gFCe,Im4N*Stu:;\jqu9G$tog<SFP]oGSX>b>^hgI*HP5P=hl7X/T1Tqe*8\5tq7A-_*X>tUI\r`P#cNUrQD-W9__O6VrFlJlaCE1eZ[c[T:r0qp.I_]n!WPoDPn.@g]%;oFY7#Y!B`WH<kY9bTql*Rm\Wm8n1mbrHb@CkPu8`5L1.;@Fcq5s:8EeP!u`W24-g8"][`q<,j_H59o<;ms*0SadYt1_pNSC1R\CnU[D_Y<hm@C;p%rIXh/4mItq(0<FjQgrm7$W%'EdirOISV"$>h6!@pQH5)3>qr@N-$*l6=A>t<m7,MC!6YlrbD6fI??hb.%8,OAh]]7!2NZZ7G$"(\R,f366qA`c]J'3F7^hG\3]84*9/W=eP]k0<8BrBm'?dn?lkV1$JS10aJ-mY[aMO8'dI=u7A0aLs?4noj^hbGM_LlYZq(rXCXWiC`J1/n,*4TWS.E8W#\R[=@oL2]MSJe"LX-M+E\/^GkLUbj.LLDb.pTHZ:r%f`3U<kpkubCHO[H#N/AqKA(gkKAF;oH/7's&Z>GRt\[J`t\QQ7,D,7a$(JC!f;pF(gN_M)-]*mWVgjH`P-uk+S?$+TKUlVlLXXr%EJLNo#\/2FE%s4VCq"nlqMCMTCco)3;^R<c)'%(VadQ\"??,'oP)IGiVKWnWd@f2&ihu@O+RbRGJh)lY2HtAK'?'uIUW",@-G*841ILRDh/""aW8GdoJ$CVVn(0ubY"!TfZjmXMk=8P[l6Ha@;ofs]?2F#Jq[AP:l$1D2[UF2'4);eF)9?@29516VbkT,;,oP/W[uX>01TJ-5jb$YL\B"%7C4,2N;af;fuU(\EKO\aM_$?0Qne_<jFYMY$R]_cD$(>WFsCWip`!7%Lpk7RG'<:][*P6Z+TZfl@50W9d.Eb.Bct/KpkPNiKS-UeTdXTK,nKoZkFOnnB^B/]M)Jj\T<7i(5[rSd5Za%r(4a=C5X@Zq<2+Zb8jf%d5e'6(R=p\R7j:WoH?;!4P?W<:+)qcG#+@@R,__pPk1I01beu(?'r3[jMfKhpkZ]P`1dKLpR2HNQ4Q(;NS63/r9aU9t=J;A%+-14,CG_foPc8Q,Y/8#^.t$-`C6;RiKC"1G+?P^9g.3d1Kk#u",o9g3S8F,[7VJT`8=6#M5bDEW9]H72kh'`:/W<5.*Cc;k&i'P-<e>QZH4:E]/AS8V."WQGfu"LFj\h)Lh,Q1(a>"3S]NL5480+deOHZL.-QXGM%OJ#KmFq4\;qTl$Uf@i<2>8hUXVapGq4XaaD7c@9E6$pS.m#gU)97>>&F]+<.;Y;5l>4BRR:.&R$8ha.rHt-SMVs9)p7K70X=W^Fj-*qn)Q224_X6HDO*;X*?Bg!can<pi?":5;dgE+V@^-Y<\V8ti:-/:IL(<r*D&T6-S$pUgmrF!.T6t9peVm^M)MK@OHBPHjZnR"h/)tpT,n&k+Y8N;V_C_/Q-!%!OT$dhb%,@-s5+e+c;uJUeo:$5W=60NuMS*9&L*htjY)lednKB"HWCZ`Da6stXeKu>s-A4n2kmimZeG#+KQbrSk7R%.NU1g)>Wjs8Ji\eJt2^d+oTs&+VF*$'1@s6lmC3'Ip8V7V23N6W>jE0bXN[QbK:_,0K%-&NR9ao9AR&b[)OnOK)U<b"46VM7<LPgn&n6P@9oX!4Z"q."173>PCLJ:i43mjsL1YQPe$,kMjOJfEh?hfHH>&0?8(dg%NGc'YWkMjR=gfs97VK)AJa!.>MSGQgZ;p]I4G4]d+T&/b&LrmB,(HI\LQi1:+*Vsf6H,oZI8TU$hjWg1kZ6l>$3h()lY'SUGhp/)D5_l_":J+8,L&<+YQ)-PY4*c9uZ;:371=8MZT\JlKSZE:XE,n)`VoK$D^ol(Qa2;6_StCbg?On-:a6jLt=1K=E5JST8%th3+S)O8+mqd1g+8,-slt%mPRN&*b3k/%J2u5D0m$I&4)4gl#FMA-Rm+Qn:`/LEO8X02fi6b.Ul$os\9j/RHTbAJFoMHu59#3n6HWkg,<9O(3)6`A0oSbSN1D2rO92JUcCe6*M"@Q*Z9iOYL'+mK,5nHRb&A;Lo+)eKu_?$<lTmsAEFJ,FP.3UJGo3]p2]0[3"dZIHo#XHm-;,pIj<>:'"rbXkmYMjF17cIM*+U4cWETObfNso?k5rYOaF<6_a@bsDX,i$*4E+b3)Gqnue'&lc?P)5[)XTkGZ1]c!#VFY_oBok2C-ECa(Hm39tCW"qQr;+D[d(@qd5GoT(Q=NY5!^1e>1-lc!6u6hn8sk7_fD-Moq`>;FX7K=&6!.GrIme0[_LRdCHp$llo@PkcG7t7GLT7+tSc503pX>>[oT;*g)Sj#D&YHNY%boC!K2F<$=*ac@HT7D^i]i/;SP5E"$BtW>dS*3!'*E6NEfd=2@Mo/oQkb`5$*f?IX3r^'#YlPc4CVL9_EL2Y;'LjmdP>F*d7L=;-SHs?r?B4<V,@eEf=%Vb:DI*;*YgM@n9D0"?t\qIB!!7hYSWTeR8;KGouX!nYMi`aKWbGhNGZpQG_9&:!s8Z'';OXJZeKK&7M[sf&.TCd6-cW.<2SCAmbWo5Z.k-7XEDD'9;8p\Xn^=c="hmN)/uR.E@K/;,G*B&nDhjdBr'3j^-Q(NdRQIX4kC'4c[I_/Da2:E@I;6%oedB<#$a/rK2cd4,CqI*?3K!J,oCfJ2QZ39jLA6KI3fb'D9dC"ZN!*RBj.Q,N'pH/Vs%I^j4qIIdBU\OK$,'3NYU8J($n:ALhK0*M$0@=Mc*jo`KsfX"3Qo4j]KfV934gtni.L'n&AMl7p3tk`0!YeY"=dg]^!#[_-@<"ke<9b&[6&d&%9p#R9d4@--rEDDGG)*^"iUje*j0"GA^*69Z'-Z;iY_7(e_WiUI%:bJ#AF6d!nZ1Ah,A[jYBtq["V7N7^HVVpm`kQME^hG$Qo4mUdt/9P8Y)?L=,C_/$4BG27Id8"FXVWYpKZmdV@)tcGHa%?u0Ds2>&h=VL!fZc,_WE[;7%.:r02MV#'s>G*]Y,`iC]_7>::%2g8,?55o\^cC*gm=l6?]An*F?78^a+[(O:Jpm+gdFWlGk#2Nas/!@_[6D!"(n.`2`Uq?J"1)F$d2)8Q-ok(sF1?+cKE*;Q(23Wa<G8nVqK@UCL>1Z??jl6B#a0gbk'>u%`7jZOG!S$`jK5Lh$i)Skk1*gqS.4%"@T>ik1><V`++\:OB\NHX(_fn+f27+hQOUfOMBcN!e*aQ_ESOt`OGj!6`1T^<m.CPs:X9Ng?kXTnBl:JNA/hYgI98/gq;RMHa[s**VF&C#O];$QgNhb=Q_4e"C@[o0T)S$XPS$BD5[j#t$\s^L$)VmG#3Pmb$l_u=1TrPZnR:k<?h4<oqS#"8?iotQ+Nn;.D?MXMo)3rL[T#@D;62[;hNa6pj7&H2<AeRjc[;J^F<P6knnA,Pc%(0d52keKq+uC8`%0`Q!TpE:-8;pVkJApQ`#Zf5DXBN/&puW,t)uB2BQDgQ9[!]M-aHXa)<Je\]0&.Qi!N>*=Q\e$F!`K-+b0E)pAo8FUVcA^`"raY\O[)rj2&$N<]0<qP,Wil\mD5Ctp$Ske22.Oo;Mu3&'qEfjnBY1I2nXJKj[U=/*dZHq'cZhH*="`:"Fu"sk.#51nrl)$l;N!cRf4An'NeH[XKFX^jqPgIjOfZsD;d(&air=;@.<hN(S0#b,!-;@Pe)0^d,LI:kmG.l%q'3lTZm!'qltA<Au!*>F<5J,N8TQTrTaKiQJSt6g=^,+M;,`GEC&U*BZ]V%<-`\?1J+%3:Jf^N[G^Ct]JauD)E1]biG$mdIDeCWd'WS5Q?&/M3sk-tT/cJDi+k/e4(`Qk4NWA1,dgN\7JUVCPjhXmMe*i!&De:C#qgd+pXP;b0O5,L+!TC\dn9Lg)FOrak3q6doFHnuVqC:5`!AaXF%%KDJ6*ul;jS2\md/?!STCn*N=#CL\QOiOC7I'%Z]X@+_*sc.W(uEGIQ]>ICSj2e":<;L`EPg%(,NloR7Z]H3GW?j#3RRRP%QI^N#>,YXR+,AHR1]LrIJYZL2]D/aC29>S0qGn>&1:32-s`gQecjF,)fGpYpVGgWTQ&tcDji:Mo8P[-$*7FSg`#;aLntt?)j?N9@>.p3aUHI^BJq<nRt@"P8fK?EfjdI00l53,YGqR-hh1QD15Sr<q'h#j:(CkGo?lTID+A,TTbfO$>9Qs&n.!:fr^Z;Pr7W>*-H@d7RJY,/G:DeRdho3VZTn'm`LTU#IUA9FA0%/`niq)9LCZjoX>0DdM6dta`eYo-#^G?$65IZ*Jrn6?3Ap.RTDZeI=E?91&Qp$[A65g&/I.<a7]-8cS\Ren,?8XCIq9hRB`?Dr8$\r\$1`*EE1&3SZsl%H_j>eXPifFL2.GmomV*!^tBD>WJdVf!e:)'Li6C`T8#H[`P(AC/gd"c#B<XJ%Vn_'ESJ):I[UF90lR"l[Cd[qigWt9'596YN-H&$CHP0Cf(jcQl\o<3M9U_P!^r5tG-_cbCCXnMCX=#RNJ'Tu[CNEW.7uic?YlC;JXW%HSj#A6O$i+!gd`DfZut.q#E*qa,4M&@Z(^GW5p/u,8MCiOZl#/C;Apkm+1I+ElpCs?i2s4c.h%#EWX9#f.%4HUK>XR0*(We_cr)ShVR%uEh!5O0Hj=-*[kS_"(.\/mGB<b1HFE,!-pAo,aq7$15X=m$K&d$pd4^O8kD5PqEQ9coEob\J$DG`+crf<qD8"GpRgrVSW;o/.7Y2IB=Z(q!dLFUnIjLY!fk#!BqX)0mUu-dJ5D!]$*MK(8<aTK`n6=L3LZdQu+Ee1"C8PQ>I6c12kd0Ql:%8L\i_tYK57ma6iM(fCDG1N+6YNbOm%]-!`aFC3nO.RrK\(.'r6Z9[gNB:YDj7DDpcYm5%$9\kA3+h'k@X[CoB:8(Gp?;i'K32bc!%Ktf``gd3bG]S9stE/YtENOYHQ))fsf@fAb5PnA[tEG^=B$_l&^_`-paf([W7DCQ4lV2Os%7k!Y\m2:dH22r-)ZH",H'sC7f7b5G=hU"NXR2!]Bgq?.]ADpkB@M,tgFnG^rt*]\@[G_I.b/G8K-*.W&,>..HJg+S4r@E_GD=VkcK%M;6VmAd0m*8.c'"h\WkScM5#O-<iV_H/P?cfQ;4DnT^Mq(d_,R+,YP4`e5SkSc5$kjhoA$djpZ'd4t#<,*L\pD=FV0Wa=H,\[8ZPkSu5of_Ogc4-)I3onRC+kOY"<F02J'Rod]d10[CC<pF;*M^<ZZChr^q'.Zn5.6OrR0;PH\Xgc6AY(]5:):@mI]EWV[_;f/SmI<#7.IXUrVN7i.5oO8P&=o6Wlr6[,ABi"fj8,nNgVUnBN&MDK7e^l`/pf)=;3r-ERo@X,7nM*MD0nItaSDIeYl#85e7LZ2bbjXtVj8-uNX0?;BbL=*m+d-pKc*!d26mr>ES85mSUp>KLb+;6QmhNerAH#T#.\Ig[DA[kCFmN$c\7[)(+3;M1i#E+e.AY6fF=YM)#Q13;d>)_lg`Z$o.RS%ZHd>-CFnHWM@C\\4fo&\T.]Qo,`Xt`%C=7Q56l$gVrQ"*E,@H`>Mo:p_Hn(QIX-4,<l<R:W[QecEcMS5B8\dZm''$h?a&:XY8g3sSMKAn%L2F`C5eGDaLf8N:kT0:<dcN%@.,K7b9@]Hf!36eDr#2JiD7'\*ZqTUGO=XdQ4S3N7Zm)1/gVjVWoB/sVnJ,GDeKV=G%NnY$&E4'K.lpT:^bM%PJ"@<+U2hTS\9%0b&F64_q^Mj:VA&M6TCKGcA87E29_qu>/d(3;mp4n'ldmDNUbA(?q+oj71?9pTPH@Fl$R:*Oa_>]i'0s%H@7&W%kh1(dL`4JbJWb<no%\?M0-_;F+/*.=D3I:B/;%qCT_^04%;s?Iqhs74Neg\Y>[e7k\ja=ad21F&&H3K'$2nd`i;G3cf4Y8CfG;C#^*bIQ'YR;/`Y$bA@WX.Q4E8eeN9tDb3bE^:@g!,6eUUS7fL@8f+-)mXm[b8AGj2DM8n@-mDlAoH-cdhc_UJV:ig9M@2%qsO]YSAX:<a)2[W1,ES8!3^V6#\)[%C.Z=-,*W]?q1[S;%V(dkj";^P$dX2saHE0b)Cha&3ARq-QrV>m[qeQ%`#L/"t-!i4ksZQFBI&](2W?5FjsM?r(h@`E1<7X<--\[`QbPI(G!3"?5WZd#Rob_FFc7h1ZE2)]MTgdu4mB15l!qiU4c[4(%qB9$9)i_;aWb^q2pZKXQC[[kcA0bngD1.F$k&RN4PATb8tKV6R^C/^c?T0ZXlX6=]"oKQ)RirrP[EgAQfkgV+G"f3'%B/#or9t8/NYE;/jaZ$Np?DF6SCb+T].S,/9ouM,T\"'afDhYB-&&aofplep8TOa]u`r)a8$]>og`rm#bM,Tp/=#+Bu.MX<cKQ&<c&<b"02F;JHs/M,r.,TI:nY&sG,(Gb.aAggC;K)-<d3@@TLoC-rI1JtT8"]!j#W>Z([4a.6Qo6s;8Ws1DYH/A\mW,@scs7<$RRss]S8skg@e[=^[S#uYN?0:EC1fi(.(A8a%:<oXBSgU:m.N<\R9q%h,Rn?H:,ldQQIfsF/ZZdr]FD9Uph8ODd?*BH#%t&)$*t%n+XG'_?uQs6"&bU![4,n8aaRlm'"nb^I5c3[I%'tTBf8n`PbR=Kbo+F,&QDSUkW%Smq.Z0XUa)oIoA8iJ+.1jZB_+a2h/VK)AHDu0I5kkY)NF6h>W'X6Lt6[cKU^Ur^^J^VRstld?c5J#?;,.cY9fs&f]CULa[lfcl.fgjBO-sD2Ui^6%WXm[#>F8>/7'XOjCW.F9:^c3Z`GqTpPc[7KT&8mqQ<L^WTb5"fO>:)iq:XlY/<oTi=,7$;JC]n>hh.[Y"sa,bEXNUMhpIS^SqslQZ307-Yd!Ydah$t9PVderp%SHZ=^ei'-tK'K,ltj^7=Hn9XF*:TgiOhHFpi788*D?AWZAA_^;@@D%^=.7`bt"9hrAGWfE^mW7>"^%[]8_H<KDl*$.So2DPOZ0f(o/k@WR%<.PZiLNV]F`\QSM'0T5ra?_B["fg\g-0OVTfNQtI9)_b\;?CPa%5K:oE-0DcH2BJ,'4!rd]C<mdNZ";?KZq)9>%!?t'd-)=Y`jF(E:kU&lO^URaq89em@QANFUlnDQDqpLpi=TV)9R(W@T9nd.#q<KdB7=1Kh]^X#dEe:8X1[_ngA<J\X_!]\6#ESN(/^<]h(@(6CLCX,eo4@-o9DoHD8ja2iCE&%&8&W9CpTD>0uF)G[A(P`0NM3H@r%a-p'V)p,M4ph9&e)cD-elb=l]"6!jHONpkl6T?[eEegg#eH':/<9)>PR%)Y$=lQc>,^deJO`Hr[^'b*U3op]ouQ#'OV[S;nkVK94YZWM$u!2P8X*SEt8Xd@UpP<`:Z7jBIOjm^jpF.fboW^uEG(c;N7l]&7CC*,Iq<k^9ck`AYIn75]h(s3-t3G"3h`ChF?<_\.6CeS6VH%]ggp2Ya7M+0*LR6f5b:pDA;,TH/Onf7=m3S-C^VX:,jUKR/"[5+_I`_!+/1rZdTqE#X43=/=+L^jHNh_RlCUA7kEc8>KmB,geP.8J+c>kTZ>6AK&;m1]fXaG=hU0:3JkWuPG7)d5^TG%HC>`%hZf.\)@`]krAGVBom(/DHaI71=L/Wq,Ve9OXj+)mCJ?,gG$u0/QhK]]IZ+]q2sq*,stAh2_BCI+]]lH>qVdbA<u%-[9AIf/^:?<#5im>^pr&Mqkiid+^U9;pY,>V58Jme*p)JAX<#$1"$QV(d34*FU7ma<j!#VKdjHMMNE-T(-`/Pd:WkQl.MLgNI):N&>!k[p=kJt@+.Z%Nuo96[CoUg*[b:I;]"cJ??C?MVU[E5luV#oOSrJ=<9'P4IWAo<Niq*>AHRbn^f4$E[ikZWkgH29a\&'@`==#B0a;egIM8(4be'>\7g\lI$5Ic/iS,UVGLgePmCEd4r\X6G>;^ZKGs%SlRuVr4Mn_>ZlEaW1pWW;AY)l9"Zt9.Hh83bSdYGc(4W@;dhY]d^P>ug+12IP4Q'[j"^)cQc30leUrp#?0G,EaO9\&NC76OS"jeVkL2r<;bD="u*].`4hS+5Ntc_m(UD5d82JPH)amkr^rNTm*UB+>X^QYg^XiXbU8lR:`1SFN26`0RO5Via4d].rnXSLW_];!sMR3gUQWCj9$Iq53+S(Qf/ic5F\(4^&a0B-6kQNYI<MbHRc_(k#;aLLlT<a'7"KRtagfCEaJ[3@.E+.69TcTXN0Af?7FuIAn`"-05]SA.?Yc*rWEm3]>T8ENK7#B>!>Sgf)Chl'g^?3qqV&dVFsTY"5+k712GaG/1.[SVMmiLcYrA.F=1ejU]jbOU.@VC5uJ+Ec*?lY?3;!E=opG5s4bL.eQuh2T]!eoI5cH\pCu7_oG>j6Cl"7C).8Y5&_Ep5NnALc"LUAJXSd&e%/;61/WE=j#T(cC5]r#-)Vr?AR&h-Vs.C.&Q:Q:.Z\jug!`XM-:oJGTqKi6T8`$bc@5(=9oYS02\*@OU:YG`4ref=Vi^+/>koQp'7n8o&!l<RX].kj3[9"]..3I)Mu.'sR"'+6A+JW,pNB\u2mMTt2TJj.PB#Qsqfk!2bSfrZS.pjq);TqA\XMhX'0:E-&lZ!qe@+*jC:MW.d/'KKq/nahR+T37]&1,aJMkc/+U*ILDCa7<*X'<DiK9+Q_a^HCqlKJLg%"a*NYd'&MZG9CioD6hod:?(LcO7eq6]nng/6=4X$F)Tn0FMa.=:rk:<#$HnI26OJ8)s:R@ncrV[Y4QRZtm]aNM/5@;bRp+3MJkS`FuR,ha20Bo)lN5I[EHmJ%5fo4DUm,+jp]B/Vg:S[J,hlIDpEQfgL)&$&j&XoD2\DIaFVNuW:hf"VC:Fm6cLH5pKp^/G2r*69?0;I!bGV6OWTN)\0qVb(d>U@e>4Oj,oPR(Qoa%L8;*9jEh&V(ghbp97diCl,2?Q7;4_MNV:04CR[FOrGb>l-UqkKtts>1c[aC)LO&RG@Xs^?B)KKUue$#h1"deL'P?+lYN-@UQl;>7GGA<,B*;);LR\N*1'd@3jh?fUF0fk(Y6Uk`qU%!QJ#1f[OcM39WOCO-?1?Np`VrODJ>EUI*d%,,21oFdmh?Ch/96]ig_1u_mQ\nCh1[u.`V3d]Yl<[ggQ&cL@R*[>EdIXBskiVOrE&+hpXQVQ&,k6Zq)i*E]$NRT,D>J>?.N<L4lRjjcf)SL5.!%CR@<k<Q32U-68Zoe8+TJ\8"^3'Dh])OX?ti$$],''jK2:i@=.Sl:uJc@*Fh<NASnlPtGB.),88:8AggGoUASgCLp04b>i:#kVH=<Zg!a=NV]c,`HS$3jXt]0%V5BNmruq0RRmt,CC-HXVDO%ECJ-e6[jc2sQBZe9>0$9d;-(BPHAn?#h%L4K9HI.5jYs=Fn9rc+o9u@%8g1"q,!4]2Arg1"W$/$8gdZ-.hF(gTotS5*+fc<<1UuLX8rADh8!/d8Uo?4oIbbts/hBps`QEt?c0`IZ0@]+0d@W)R2kt#XI8(VYo/sZnViH"c>Y-b^KW?t#KQc21k;d>lBY:sI]EG8`ohDV&qX.pd+/96iQaG#.nEp-n[SunsGN`"W_<?3]8<Z#`8=JR30%8*:j#A/>"o3%6AI!A$UiY+#0:[Af_<DAfl(mA5r`n.sgM"[!im45i=\3_6%q[+.1Z>p>Z(Cg6-6@$%83[Y#d3?1<fp:-W]e_<.jI+O+QE!,p(u2=D/'ha9"_VML(o:Dgk.a/f,EY;o/KK%(5$(8/4;:Fa41Ec\D\)$V.#5J4Dou%9_rZJ?e="u7lCt?l-IXp-F\EX9<4:pYlWdLM4'Sa&UU(iig;3PXh2ZdIh:Z0aLLj9>g1OS'jcZJ$dh'sY)e#SX+(L&*bO+2PBuQ=!G]IML"eD4Kb3_e\ZVXPnRhc1J#7OZ$+L#:W'bQ5hr>[HC>(oq@TqeNWIAbGsWBI_&ULlic4)h'F,@*+>j[REVF/)K_,W:&C1Rbn0lA4[n^h0<82aOb%d&At)G^5RTK2*Cr47ghUc`[fI9rn]>5C,#k@qhBf7TMK[3UD^fEH]"P;KjjMathq<15/U]5/toJ>r/G2M3G<+g\XctYGaM`LII$g_JFbB,t#nuV=Vk_cr1D^NOY^KBsOtN(Wk)04&EK7cR3HcpGd;48ss5e/h*[5A7@:;b$=+CB\c>'Yr^/el>+^PgpPSSI]>=2,X2I;mAS&T#;0qZgC/2]4uK$#rS#PLT+:3D,$#9C?%u<g1\5e<7i_*7@M\p$kgM]<Es*drN,bGKiLA?9Ai;W:K`b5X5-sE-PV4s0lL0U%%_9<`@K@M_ZVW8b7A)5*bo%Q?ht0i!Ed/6JX+SsYUE)=:SoqgiXKYGi06@t;i46Am1-ZafZeo*X^MdPm*\*mGqM(EkJrQ::E).0jm=p'R&,A<bWD8=(>f(CTRd2p@<'tPM^5H6piIs<QC__"(N`7-38`=F@jpB5k7^<'8d@I&_0W6WRH.Ao01&PqEoZJkF7\=OWoj_N@)l+egVZd@qR-dkmJiAgT?F^2Eg#a/4*$lYYP#-!D\i"nNc$sa\;W'lb#WmmY_jj;(-uA$oI#h^0V=KN?V:=GkOdhd:A\d+@cA[AXje*%r>q0i>B%K^C,A6JXPiU"=B+m"p]d'>bLc!$1<-78.7bf,;`.m;C@RB0/`6L<OZt=+7i&(jY!q&E:V"C4t*l9cH<n$g4@!6C<&rhe>K5r5/eoP:pdKslE-CIH[L@/r1.P@7$7>XY!FdD2Ok8*Kl9f$"%,QsO)4JW'NRgG"Q>'1d/0-6XOJYJkb7('(h,fZsC3*cg16F[BO;hM1![RgeX_t,`m=AD^]Lf9_l0;lJ^S`ohGhkH-7%[[lDPAuDA#ZT8d,t_i"L5UiqIlnDa=>,g\N'VkhG-Bu!'Hn;I8&3&K&OD^(IT.V'6af1X#6jOK@%SGqJJQUCrR9oCo=Is?i2/C!SG'!S<k8iQ:q/q@c#jHK]S@K/,oI:Yq-'pmP,t<rFQE]**SO_;_bU=@c*/FaK9io,I&W-=45O1L=00][31Q"plq<%saI\tuGemM(4?J@'/%h^`])1Kb5*N$@B>#'+eW[#]b_Zr%CK`&rdbAJL[V7qmYh?Vt!=>orEa\<tP&Q'.dojo@5:\\cdYO^2i6S;uFVq>#k5EIG975[Z-UaP"]?p,U5)N<=VNEpjLIR+N1JhCLioCc.A1;-oFYrNCA$g#(0m#n0:-%W#lSk>erj;ih2%@kk'HSpS28JPl9o\Ur`CO\hP<eor$,f1+,0T@r7>%^V5[\.$hQ:G'TjcFEL-LuP",<1`ptjGEjd-g%=6WYY/mJn>c@4S\b37!$fC0_XK%nK#>Z35!:B$]#mHXUpGOaftY_rc<p3R1N6p,h=N<)knkVQ69\0-EBNW.(]Q?.$_NJ(g]%l+i<9o>oB_#"6D=BZPP!D"14Hrq!b;;3.o%b]h%WCsX7_dC1GqX>:Od!__gc^RLJ-!?r+)gp?N,T^2N)/%ZjK:L^sB.l[nrL6da0,CR/kAKlL+V\On>fO4FS[>H>Tho2>'q^\j1mP_[_XEbP7c;rV0q1lS#m5_iFf`t2?5dr4pJ34WK/*4K=RO1o/ogJ,WOD!4848qC<6/qp*FNqYEH&m.oM\'\>i<n$mCp=N;@#tMVOSCJS)lo!=-?NHR9&cEd"_O;E8C)_Hg-iD]0;J21XDr(X&CVU$#EW,<n^VJ<.T)4/agVYDfsurVKnH8C\H4%O:UB:(H]qeC2^c=kfuN5<D7XDCA5!g6o9[0r2k7L3h);fP7K+q8kn+=q+<VaWYT!.kCr6Bf<[BLhCr:Y?u[D\QRCEBbLPb:a)dNQJ#,t1^ba;jZTI89?DM6G8K>Vs%aHVoDE7ELmk(Us\=860HT<#"Ol<jNi#'k0S^IR+QHd<(:VS42Dire2[R0/X2(RJ_66g4%B"XasWk"J"W],T:rg!b+4Uh*;qEiFuj(cRRQEK\BL\@\&aZ]gmV6c/*d(H^"59am#lkr8tARdcd>%W.fGII65.dNA8U<YVVbLgU`Q-/T-knc+H-r4.:C#GPegO4'$Sl(I3cl%gGHmLqUXc1TC[BlG`6+4?C99b%@?:"l6-]\`,Zg`9BZp!D(k%.[rQ(;QS^rWmhF%.je+8$jODPrdV@R"MkHaZ@VSb%#H8mHM88X0.`]P#sn3hfp'*VRt"e<R>qb=UNh0'8In#=sDcXMdB=YZ\l6,'>3h^1!Eq9J4GgEncUPVp@Qm'?JV$gidZ_c60sE;eK8DV#YYh`mU,<,>9:@0.#AN9k8hI@2&S&,je0X6>aII*4la'X_mB.(E=:A'.G`!5Y*!*a3:!o21ngq<d@A]RB1Wh`"pbj<6OeLHJjtW\N"9iEK2WY$2i7[D0^K/.l,"0D"N<I*XmM_PY,SZ&\7_A3aoHGBQtfGj?V;&k-l>6%;?P'Vb#%NoN!9TGt"tXjY$EN.+P&Cp^Q&X?+<)4'Zl"uT*H4.+!2+==8BW9-@mo!)%W(10?D^A`<Ls4>'=+YF^uDQ%MBaa7B<gR2uDefk%Os'-pf\XrD.%amd[Q=SkWMKcT4nB7_V\HPA.8h]$8N=8heok)\ke@C%3`R;YWd+LYH;\Q_+/ZZZj3.S5,[,<T9]Tdn)gCOJGPXggSLm4sDp)+;]]6ojoTu)c;Yr*E/^Y#,C*a`[]/Q/cuGn"u(rl.AiR=2U>p"V%=n^2gK12&DeXLT9_o[SL/;]f.Da4+#'7&<Vu<^2H_5nNZ8rbAV="b(,YZk=(TsB'$*%5?"=p15_R:SS1UT:KnQm.$4RGH;^I3/&_dn+HE,Wn&P,bb1ONlEJV\'Y3NOcg9+"o5,d=%DO&43%@fhd3Ubn7_JMcL670T#t_GgeuVUZiDRXr>dBDN3A(XEn@QRL;kBfQ4/=#G)7b=.GkXs2LV/]&[)VNYolesf);=tkN-938O@TJK5\B':WsD*\Fm3@[^IUs1b>kl_<jNJ?^25r_F_A>^'E6&0VX]l=H8m+,3T-SgV]93)OB^:Ctm[mqc$;eEP.eiZ9G=j[2F4E):"S]14#(:*iHn\fJrT'WdfPW'/b#6I^^"AORt/5>T\fPZ0;4_:^!.:FiZrUHj.`,=,\+gP_<U_u)_bWF&m\1%4a;9L?/h>?iXq!%SK6"?NN=u,>Il\X"]RIA7s6Ap&,r_0n6dTW72+48*IFZceH<mHZj3Qn2V;JbdudE,0e'Xd4<XJL5/02dTd##tiS3A<-Fc;(.%/[LI&pW%F`jg_lUF$j[ST\"t(3!s;7`3'Z,^$E9e/jI7j^*]f+cS6?cRW(>Ef,D*j4Cpl\HSsLB+A`3"[m^ZGn%OFI\$8<`c.XeM'ZQ!h"8)A3?t,7kG,U9tCB\q?jUD?$WQsh"a.^JsZ,E?<gEp,:[Sk1'XR-Ul<(XTJ]1'$1_&J&F8nQW&1Hoc*di,)(jdpPM-)ED0iA)+LHc\>p%hihs9INO0m,BYD5,La44W`JKdsl;uWF%6,%50LnU.V&rJ1K1F*hFb*bH#@A^-"N8+3?Id/-T-*MSFP*5+Q85_1Dm>S+"nn\L87b_f>+C0M!B?>4e?QYcg+5fQinriFb.dETXVI,$35XDES6[IeoT-fHm#.W&N=059gojM!51C%=2*gp`FK"_*dima804qTj!']eO"s4`&^7Q"Ga>ZiVd\[1o,8sgNdGIR;U>dh`"_$*Z7GY?_HQga^q?i)u!Q>l7b[#M!phcUQ*APQ3N_58Er_o>ucJ1mYpPZBsPgFelc`L0c?0f1/-<Ek-bg``1W-+I7A6-@M6-tk>G8b`GNHQY)QRm'ea'$f`OUm:9<$>W)Zg"QIM1s>.t*t@W#5:X@UV,S[3W9b9p3.GqJG-b8TO*lT3C6<6Mt%Q0GA,hY%:V&odf+Wd3/?&sg#NP%n)uC$TK7'TMlgHEA$D(&$$D0M$UB/K[Y)hLMERCh/L1QNBIIq)N_>H((TP1Kr'@f3JK@EQtScK2a'XXWlPE\3_c6ZE<SLRhI"<E./Ur[+Q!`'YR/N\?gptAVuN&=K&Wfh5<tE9^R8)>pe8oQ<&n#32L(;H:?@H7qmY-2;si?F?Qt2L0@"?:))@CRW(FQA7CcD2J.-V;OF=K\^&\C85m4q[Tja#Z7DtC.QpXU6+1"a=)D3o".CX.<#\o,VBP>!1q6^tB$iGLpm9(mRN]S,W/ci*7p@dt/c)%'pRM$K_0RV\01K*6d:T;80:!R]k,a"SC#/4JMijMc32iARj2L[h^#Q;"AW`8Miu]SV%:\AcrAU.bKr`Kse@sI2D!*mKkt=W`7<uPLdoC#@f[4EVHtf]2r#OlRGCmq8)a;mD`[p^>#:h^.:BCro.\]ir^IXW5#A;3ji!QdCQ0uP)&lXUMc#Z*4,'uNhA;a9[&8:St;O*gN=klq\qr=LCJZAm3V'GH0\)5/+fmC1cPHn3JiK^,jjiL`L)k?&B"b\79[n>ae'HF,TEQBn_5phT\0)O"mHJ$VAk1?u'(4&)Oo$TkLM,#g^-a%ARk!=>XF5c<;g_aR)/<&LrZ;9tKFiq:1mVt)YZ<f,TM6XmkS/O]/PI<L'3$*1dE)#Aj91u[oHRC[H(iiJr4VW?W*_1&Z-AXM`/qgsP*T+5=Te0TQk5-E8VL./s,=2mo%3qW\F>I-8_A@\h%2'UQgkVm@0nX>5"7trS-q>?_!Y",!URjBAWnc6,10X4N2sWT%HT:.,SKKeliqN&1VV'G'0'SkeLOTa`@tn:A0C?r4lnZ_811muKl#ZKeh2"O0R>m/Z,8-$%.%.2ReW<qtM"fb'+YlVG5";jLV7%;Bg;0YE7XNp)U,lhO=*rL?Vt54PhKcC(GRHZb9>VL!%n+)&M^!#JD%1S]-7YJrB@E@g3+tKL9N%]h7IS.7P>R^_GTMp?%*>c2j?^blPifb3=t7l\U:a?pEI'eVO;`p@FsJCgde$<;!M\"AW:-GFU"blFQ)ra-og<?Zo&3*%ofY(dqas?UTH0@#6Ximgc6cn.28W7\Yg*NZn@`b68p.MkrR5dH,2V;7bF-NOXC`Gmhrp^*oerK@70\/1g@Ej^g@9H[31jt&.5B;2<mZ0;S&>SUUug*OY+nF,kr>06D^('d4L\L+rqhf%]/@6Bb837oLE+CS@apX@-D%5KB0"\RrWHG?[Ce(d7VpuFMr3TbMc'9F6qcF==V;f>B6?g;108:<G?I]d^15,rcQ/c3kG8Hqg@M]:XQ1YT-LuF#%%,jWg$'^J3OpC\1g#q;Z@<L*?5L9&k"nY1o(jY;MiMFa9MN`X7X0&OX)a?^/ZSdSI0j=F[RJ=(I(_t;kf?&P../I7)$Hj3hj0X4B*Se>9[>:Hc;L`m&Y>kPBr.R4:a2qH."=Uf:@(X&?d&#Q3fc1!*LpcQ4c)8UoU#^=2AcSLrHl1cqVo6pn@e*p@@8/<qG6PLE]Yg'Ue<gM]c>>";Wo!dr28J_DW3AC^4Xh<I/H$Z/,+?KoC)%(A`ph%i1SZM_<ohm?CXf_#bl=NhNH'PW-!%UEn*4*2oPONk&3B4Y\A!][*#6B;"U*iY#&%,e]GUI5C<:([@\hGF^G;<,MrGt``>d`4Ir5X<>1<'[,:.Boi-12aSFk!n=G(MKG.6c=O7SWDVV5_hV>/q,iUT&SP%\RPdZu$%j<fnr]D-L^D-7,q6\jf=sH"PhGSi.j"mJ9J(X:8V]5A#4R,g=]q`I%/^EW]"d(bh2_n3(9hAN/oFR4n.0>rDWe$YC`.?n[):6FPqJ^hDRtu\M\Ea\Qrh[aX[QR'PP;rK%#n[*11=Jf*h.a"Wh2Ga*jtijd:4=W(OK-tD8N&u3=YSS%VTc.!c>tW*'M0S+:R5Oe;1(;dQ+s/?oC'SXd2g!DRksSsTQ4Ki(5bqcB)\Z9%K5HPcW;2.UJ9LsT?)2T2Y"_1qd2b9+_;.+s0BOI]X5'*4L:]q:3U[MM8U8@8c<HS?n!9<(+%IZLXW$^,]O!n3L;N"/u$'I-rDiiPS\<=CHUYb2E"2G+Yb1C$LKS#,SN;(E;4A^B"ZI@X7e^6_W?RAYMDDb\o$BTr\sjLJRA8K,?Ibde4reQG+TIu*`3Hah_fRBpH0\Bjm+qYfCSY0He1AAg@uTBrK+<C(9-e_-(&CF(Q3;>oHn'Z[,U614!u`,4Y))#Iatf""n/>S3WG?DVo>7bdpL;Ug@)KQFD2U>JD'^I%mJr5#)%>!r6RCa`bRcnH,u:6"C1t"\%r)5ED=8JBnS1tH9LHBK8L&mIQIlPGW,*-R++q=!]uhAqCp-&o!/_0\FDKUe4=G&^?:;-*R/50VR1J"-e.F<=O#Cc3uTPsXiS-rm.;kMD;s-,LB=;ERj)[IN$&bp;l[?(b&!@Xdp`6X<S8-5bq\!sg6/AkQ'UdXCBg:Z,.mfK0rK8'$bOklQGTe2ehFWu(e-)E\AAphD"$e#j>fE-bD1Flh[`?qe*GPT\.1-Raq>^7gj+O6Sf&,,U.&&2:ZgAWEOs^o7K9'n7D2<2;P>m`>M3_N<]`L_!tAM=qGJn,-uIFq`oqd"$Q41p..O*(=Qh5k.S='n`AC]]"B'^VeesRIAM>AYPSG/`Ck?(#+]M;+WkRT52.jIdfJLU:[O7m52e&UL[hV:0&7mAR[`C-W<LikB]=H6V9^(q&gfF]mmIB+KVDW)'LR9H(f_#Y$%(dB^AQ>Hl'@oqhfsMqYItnZ#rK0C(L1l[3E`/"7Bh\m*Ba(A#^uH.66X=)-Z5E06(aIeP;;2XkfDd8@bRhsG?1Ds5%Z8WuSi!D864'-+d\^_]UqOd2fn`9iJtA(HKTpemKRHXXSU-(4jIHD"nodoA(r9Db@_>V0"is@`PmTd?MIO8B2\@F!*_YHo_ItW>T&a*YA3l,MEp>MUDV@_<(tjlL3]C08.o`r2Y,LRp[.L?<@mqV.`$U3(Y6\(V/rriCV%#6Hf6R5`BK[RS[PR45H:<Gt>Glhc)0f+Ggj%>%$=[hP2VU^s\[0Zeiu/bZ9n:?aR#p/tL&ktpHYEp5X9+"7D-?m#@<TJoLrT$&f9p2]4"^NePl_C=N(^uEf^sJ(p3d>b0hY\,rMQo\j#0Sr5[lR((<[YA5l.M6]@mNRXRRG7YGb8k%ABp$&[3,!Qs=U+WLDQB;_q6I"Ai(>&Id1pfpKP4=9c'/W[5_52Orlh0smW@14R'"OWsHAG*,*_4@h^XcCXY(O6M##$]=(2S_H1ZMlkMhcLnD!(c(IVYX\+HSXSMn->%OQB"](c3&5=_@cCfEQ.FsW'e5(`*/%!$+iJ3Z._Lsp+dMZ:c9d`B!VhVY!&[--+F/FCD>G4[j&-R"JZRSmhT*:c@N5^ck9s!d8)-cA\MLQ9MF_Ru\7Ta[K-.0d5)J*',bR8`$a@rdJ2i1Q7i1a$a1UJI3`."k"ja4Ci)\eF_,@>T?f9fd;#+([1,KNsJ#m>i6P)&C&&d/8c3Ftq?MXBk8\A)GprNK!0BMLqjubLVP,o,()CbUIm,2(C]p*;+[!IZp',utdY>`]'Y[A=c./g4[n?gjM4#1]I!tL&.E_:6,FB(9gf8fDcWZSQB'X-NqhI#*(._MJNBDU`g*IkP&fD<(fY5d1Uk/k6JDT(iq]L.5:<8U%A8I%M9"<YW'r>[U'UOjF0_"kW\HdFe.+rQpT,,K#@;Es<uq06B!)n\ERY7VO1*HNi+[0sC7?\\).rP(7p/G7iV4qs1Slg!=rU"rg\WRukg'MA[\H5N66Yr17cAIgoRe93KY\2NI*h#)Gon^%/;Er?]40?HQP7e5M02q-Ws^1Zoch_%.\s'5$m?_;rMKXKLF.1X@B&hrSESmU7KBMXG?T8e=dF&?E47.uX/d0q,[6%soh1JZX]qL?Q#W7HUYr2A*'K?5!;J8$f&C==?_&B$NFN(l.^^:IaK(/B9r.J>TXJ<;5T3]ss[:NQ[OI2#[.fZ[dg[[+(O/j0,oh;S5qO4fZNHh5itEGnY%B]8:TJj(Kpq>B+b0?NY\?fT5Wk1rG/Ms3HUXPiD-#JZ5NcSRj5#Cg.%ar6ZFIh,qqpii<tf7jKsrS,U73nO>e#P!8J@RLhN!@]>nAR-FXI_D;F$;uNfn!Ur[k8FarrWlt1TJ1fSL[Y23E-TF85p/No7BqB&s*Ltu$lVpG5\,N4@hB"[dZf^p!>#hl6Bots.7FC@'JMgNIl_R^@45$G_C3qH+!c>bDE>3+dR-)*(b$bo5gcE\(_==i1%6*78Zp9("Q<EoSE0tQ2Z(6Oc_J::T]]W&O]qbh1B%#E+.r=tbLPe;8U11!rZ%i^o_&5*mU%aHf#<BilCZDQ'e[hfp>sFZTm2]<lhp4t`:U\FO40WsbrbR$TB=t(fa5h4&9HgN/JHH)rd535nGM-UG#Ri-)66/XJ&<d'&F#WdqKs[ek>Uo>>Gdr;GhnGRI]"&FVfitb@"%qbhdgO"qL#o5"bZb^5B!-OVTYcp1pm8uBCYTV2Ys9GRK&SX55skt?hRY]/+[8i$fh.Lg%<L[SuVR0rh"Y.PNVE3Q?kLA?b:VC7"'Ddk*,b_A(jZ?qP>F_1:=4>gJTN+?aofag@sXs1XF7ke)JBt]sMVVX[Cse]Q*B1ei1%>k]H":^J-ihfKM5qp'4oRJ'4*iBRUQN&o=<4_f$$/[Vs+Ih:5#^QOhc15B4TnI/f>k`dSmZq0l>9I=-34V[f0oSmQ^/r[WDANIGg:J"Pj"2%4s]rgEd6O5DTPHK_Ik^UNoas#*BD/b8(*`cJ`=i\*BA1:<`14KY5tM-KOrdCtq?'Ddc"pFs@SbI+F:c/%W`1kS\?AqpCi3dJr@1Os"H)/G"#%YbjhfIse2^TVucCO`M]e)AltIG;:\jRm>$ja$Ys=29G*O+XnB[)&=4=;8CQ,,0g#^I6q`Hsg4oi5P%_U]Df_U3&Z:$f#ef60N84S,/BZUZUS;r?[Z5+mt`q5DH?'[7E*cmHMhS`a9OprEiX0e]FTQn+]'J*CWbU6.&TEBt:^TQZ2[Vm$YA.pG)TD:TEpIGM?K%o;C*`H#duumG%*El$`Q'c@%fNdp*tbiHNjMTrM)p0_"[]8DX)#H?/qQ)r^>mSJf^\h[DA:[=/R1U,AM;:%?lR5hrp#DEMFV`K(N`HG^Qgq@AAGH@\B;_h6.>T$]oYAu<.h?_cA*8(H\p^5na*`RUZqX7p9h@lmK$juTdDp36NX;pY;9h>7,:@ma$fkPgS(EB[`e]1JTgS9pn#E?n=)NuH=ZnA>Yb_Ju%m0oYSuSIP2ACY<k,ir+&PUCVX?>+Z#0>>k=lFtrj+1<-c^iVN-p")8]A"[d-HbBtL,L3\.kEo$='<'CIt*JSO9_HS(OR6;K'Bl#H>;WQ]kd*86%[9?<$4mga2UK@?jnb[_(`;3%1G\VKt[CGRNh@e;Oh^\;:LLXK3^Oqh5rlt\Qnt07Xc+S;IOjH2iFtrZ$;=*+`5n1"ue*3lUp)f5UcAT;__5bc:Ia's..@OunA:ordh&[Y&A,-#[nE^"7mEG3pp=%Xl>(CVWl=7fG)(ojrn#re;mnZcQ^P%$%4jiBQS-`c0_7P$-N@hj,r.bQ`/fMQ!LUn>9	"cL>tj[h/mP4e+]K0IgrB(IrBl/X6'*HVNRI`cW?-jqRe%>>'#%>B)569esGH;%LJK7ng)'(K:-@2\O;qWqY8`LSFtVIbGP5nl@5/3CC\c<s&dX17O;.5"?;iA*[F;(J^u)$s+`_Q_1:1_(aT+qcZ,9u.1K8o+Wu<T,\,&qNm\+gFppVWd(JBA&,:U[jl*Le$'*CK@pZLK(@H1Um4;%(GiMt&k,YDikoDH7G)3mjaga5dXrH;m;c9-KW>ol**_u)5K"jn*5%="9[r\IZVFD/Kl1=U4=+blL^)`5iW\.gN36u8a*lOjMN/8]W&3rP18%C?sL*NG&@'M>AA0&4(^SgZu?cZ`c#P%X3g)nG.hO^/8DrI:UT"jnLHdAV]G^h[8olg6s;&]IV&4H5er?mB2s!3)pV5o[@r'+5S0"rFT\'OQG^Ba)rlg$NE,P<%+(\:%eY<;87I5l7r>5:TgjM@?)@K.n>ns$kXCVEo:\XnQrbl>d9HN%^@*+^@Q@,1DrY3iT!Z`1XtlM:=l5Bf#,Qks3)=odPr*Mt'RZf:[sk.8an[1seYkNC%C'@2u-^Kj$,`?KDqR#*:sZ;[+bpJ#2+rf!AUn+L*/FQ^,&YB*ni?["-35"G,;1&EgiH[Ha'*lh:Y>$4&(*;r(H]'%PqhsC$K8c8;ZO0@624O:72h`nI=3BtK4e!op@gYMMJfBJ:@Y'8GC%YL[W+M@$KcVM:aH*d!U>k-pIL(Ib6a>f\f$=5-E"7Q.\N41DW@blSB`EkU^*^1VidLj.J`2IKj#Rm4m7)m;tRg[PnJ2Du?l`hr-3UD!6%aT?<?dQBa)"T9:4U."@3^MOA\uM^/kMX>A34/QBbNSB`U8gslFL_[WJb#uSjE05#,BBg;^*!:OC125iFI;m@ps`JW15+Z."poAP17"(/!sh7>To)Z5AUfrDc4nYoW^LRd!A,#\)g@fkFW8VN*:4t:4cK)/R)P&Z/Z>mg.Z29Va.=8pXQ^CYjMU;q]Rd?-j]f4KhG,<>P^88F-!,r^@khTgLp83BUD+:g7H$q6JP>N`6j);q%`@WL\;`j!'d-s:_*OsFg-0u5pKl72P2?K,SQk(NC]&[1ICH,No>1A=B'K/nIp5f^[;_2lqEC#;blf6ogtY8+=k"Ug&$472K,oRG+.VY=)K7F%=UDD5U\!aHrt\tdhkneV/0P;[\)2c85','2\FgBq$(7B52K$#%SRq%Kooea_7V<hh(9q>$S`Qq5Y_op1^;6aoN.mDhC[S/T.[obi.CaX`X`q6-Y9@]Nn]O=8rDj`PLFi,D>dnWaO0X0ud-\Jq`O5TQ0C/*$d?ej#^V8DPcc5r(^TGH=qaS`]Bb>mTg7of&%-Rt,9ahj[k;[A,kVEdF2kQ/RK;LRN&SstP]M"HRaNrCb<XT(D!uU8:Q\kt4SXKm2@7:rqBj*q0=@=m8[K`j%a'f2%<6Ehi'I"Au.*^SVa>2pO9RuS%!=b+lE8Po[1,-ODc.7]?,;Kd\0%)k[?!K@/0IKLa^eL9/6o;q1\JHY'^eA$;c3LQ3;I7Sle=0"hL2!;Gi9]2PcofJp/V&,P3<Y,cHV,Z`*o1MbFM<]8k0S]SoJ>"2Re+i#pX&,CcS7>;hhuP]GhC)YYGna&5,S1df[p"GB%,MIM"rogYPPs`T=6R8c5j71Rd3bQlD/QNYK[=FGLC/;n`j+S<F;%PQT[D"jIZrYGsUQ<?[m!McEkP5Djs=IhEJ@nejP!HeN/OE29J]:\bpTmEW0[?oKC?=h%0!ELt7J`As7Z<A(I%7iuQYDC=T:5?$U@4k1'DAo2`@!/P#@KL\'D5L1g+Tb:KmJ<f9ACXB(m9*Tr9lnCg*lS9/0<9)#jcK/-rf38tq'#SJ3=f7E7X8J86<W3DBgR":X;lp\`Yaq.,FHAiDF7>Qe3Ja(dVN_(@V?,k9LitsELSrO,P4%V9a)DL[^_;o@jf8Ohm22[ANC-jEff8S`q#D#'3df5B`%j@,.*-pT&5tsaFHT(P3M24=h*rIiCHBSJ+EKg.<kCZe'4C@sF1t1M&eVt,O[PQibK>$\$ROd@)5,#p.3+#SA>)"+/cNJQd:j=,X(lPhqlsZfbPEUqF*%4@#<Wd)nZoI8/-Vjj/)&Qc&A.'S@X(a0raGLlq#oUQiIMJPK5tQ&C+Zu^GY8*>f>\]k_fu^#``XYNhBHm,AV]4)EWefZPd>V%f)oLO.naI\aK<)J4/OYjdo?Q^&ULOL,6FW6aHTdSPB?Bc+UHd"anC[D\BAi\K(p&/a/R$j(B@4'9>lGIoAGLI.9uY021&#[f]bB<;%O]5]&Ui$ur)4sF+2$cQ;6;_`B'`EA%SCuHroH^c!nPAW\X-@XE`[)3oB?u5obX5P[a'-41/#n,):Ccs+@!<'eXSk!HY:HQK4e[lj7'<oYRnRS"?*.ZA;.)_DV\,]UTBFjOt=+Cg9q9WRM&C_MH"I*mAAT]W.N`a0gnk.VAPgB$[sZqajE[iA%4d\_dk0gCm_IK=D.%-^9ug[IUUVVJdJ-H71s"\ag9p/Icm\6m`,fQXUs]#@+`IHPg2]Id-([9eg!5ckqh+6jVO.cJI!fs&mGK=%%%8[[G`r4+u]kH/#S'0?eNNJVFj/#-XL7naX@B-.gFFQ[]LL&$uJTC@S@nhkCV((RsV!J7Mg5e,\j^Jkpe7#%.%i;&Af,,eJdAl:<"9/>Zp;pH<O1GYg+R0YZP\3gmPq\i2Na'd<?5]W8"El<H5M-V.n8@gL],];8a6ZL9?Kpo52VZF`L76BUBi!/b$Y7o_2?3&gDt&W-NTklA_:cjH[t("m:SYdg^e(<I8T42c6ii8NZ!7@n`Z"G%jZb]t!>se21IelucGiB+1YVfuEG_XX5o:7V_Btj!q8Q]ja"R)r58q\a@e`s,?if(*1]@inaL5Zqb1u&KfkA1LB7Ykh\2`p\u_eGI*1)U(0l;FWV5JBgIPj7in61_K/27r^$*`U74Y(E/m)GVJkQHdHaB6Wjo[D,d6lfN6DVdnmO!6i9r7>cbABtCS!MmrdAu9Na?ZP9kZD2?;6O73E'f2iML4t46nE??#Nmm3WucmcPdNH@^i-N>.N;.,n6p5d;:X2DZ5fUNEP!u[q5lD*^bo;::Pshh6-PF\X\D9CQlSm,Y_?5OduY2,au!@;pAXPr;45kSpBCeI,7Z.Tm,;D<_uMZilq(J_i2fLB2qA[X\'YV)X"7D?'=FbNSAdGI(VqDf,PZR>Vi7)Ra!g7<4sqiL2,;M;kJt;K/^WShQhc8X9s&;*HZGIg[S:XCFN*@='W1U=aO]/.u_c6D-#;9qE?uBLFmZ*61Sek>1'91G@tQ7f[0^=#%rg^Jq2/UPpQcf,U6!9l\Hc=.?:-]Gt1VE?`pl=B3eEZRkt\/NL"0[%Q\%=g-^1N3or!?ouJG+1un#&Cnth0[5%Z%*^:fq:HlHN@jXhR8,ac&'%b?W?68509j;WUo[[sOV&O$BictCfYiH-Xn3-L39r:NU[o4IgUo+HT$DPn9.k.#+RJr+%KZ-P0\89&H$e2HI-uA-6K3AK:j"n=AnY9fi6]e>7AA7:-9(];3qmbL8\6]Y;lH1dYR:1hh3&a?sUWN7K9k+U2YP!ikruq((SajP92-0Wj;Ej`$CsA)Z#95U4Um&rgKDT5mMnh1oeiVT77tWNGO.D+/"AmDHRhp6^GHF'=:nqA>l-%fb/gM4uJU5S9Ys-.L4VM.eUO2Jo?HT(SpUoOt:MS-5$f(pnVBJu10XZJ+_$Di<rpf<NnEl")$W'IAE_hb%NhK1;\TXBj[[!1I2e5%.AVm/f[L*p^@&R^]7,K*k20>3Kr+N?FJAS9S\gAQe.Fj9AaHU6d:Lqdi=^s7jZWKC`,J5mh!gSMbmA;aE4H9lt8K^2K7j@;G#IgX!\eS:*cES#&`f&qIUT7bD`plK>FOUQ9'"dG`4ZLU5Pm4*#RHLFS=@I8a;b\c*-mOCZ#YcHE0rC/?OYg<>4%'tU&b]DP:iap[XYSf#I$pGIJqiC3.:b%lc[ZZ8US`]<i7^i=,)n#bZm]o)"q@i/PbUoe1hGWKIVj.8>J^ukkV`:*B["TEa%"WSHNo(Rl?`te-#7i_2+*eHcP+L>BTb0XOsNYA_eIKE@k6EQLLrhTX?#t,B(S$JZXo^F/5>(,jJ;4+8Y;!FQOk_F^7;A2i^VR](V3)IU^=;2+6Hm5!k0:6`Dd)U$l"^:QDZ^a`po"JA(e!t2Tl`K>&fj!ELWCSL<]mGdkn8&W=J:9<UcT>O:NL0Kh41u4QdbbL<hdL6r?plL1bradUATb`UM-aQV-LXO9ukZH_5.*.u-9tl#E85_&&&7.)lpVVkcO+3,hh57gg`pUdf=pJVD9V=`e#loNGVK"%G*=%6um4S"&=_3(l[J>7baos&H;._]ija=t_VE:/@7[:/QhKo:+!HY"^jf.HXE:W+S5H.U+)uMQ7*[Y[\ET,)S!7g=?'M`ELJ"<2_:ldaGA(-^en`m`hq*+0JcuN*?cA>*Wdd5sVi5efT7q(mLqIRB#fBH.DWbj+cZY:?J,924.p8=.;2%G3>d8/?_H&71?EibfbsCRonC>2MLlI&XL_Sk><jQ<r@='=:Cbn>Z,=J^%2nTj(ASj\'B2+W(a;;'O=A2S:W7-PuUblMa4ccq<.4e]30$m2W`-:aON(NEQ;;'4e*eOnh'TYhD*uSgVYD;2GWY82>]Nghc;7)`2/`SB88!QYX$o%_.+7h`h@pqlH]r>nQM#`YKt%?D#991PF#_TCg;cFFSXoQ1tr$-%]KZi?H#=(iG'jT>4Qtqf7>uiW63&[Xc1?%^VV\\S[bWJ4R]F#"I,qD6X].%dVI$?$btFo[qK[JWPr1S,ClhM%jVRBejXm9ej$(1P-[9Kk%\n]A_QH5BD9DGi>4(O8p<ZT2YuU]L%Pt<g&rVr>/qc,<3#sWoB:[kW*L.(/4MuTb%*W2Z\l*>\LLA%e#oM*MmuDQ*[cJ8*)Z39H16@SjPs-1%2Ia))\'[/:?o8q=Nh#)4<a3D-B57WSaWuCO$37gWq<]8Uc6]CDO-%5Xt[_:qQFbC</.i*:(hoZ'q'lsQrdkc86)%$gkuK-e'$=aeDuJG#99qn5E-jfEAu/4GjM'LEs-P.Laat'hb-jF6HXf$*N%-;k1\l\Y;h2'RL,EFkn!.@PYcIL1R1Nc6QV0]:fdOh$Vn8/@#!K?(%^:KU0.iB9Fj^)lcs)n:sI]df_"JPmsc0ls6[W>W9#f$7XQ]B''8c6,Kl:^@3ahq)B#hGe2:BS]m<@'h(@g,OA/rW7jWH1p2H8o]F)i\St%NRU6=CJl+ScB7#IIWkBU+]%R3B'G&rWQSM(YBQ]dCIor;7FWe;RB0;T^QB4PUXKQG8rW7cqVc)oC6C-@'42GePQ[?c"](=]0]b:)O?;2!YgE?4jqf&RNK1YrUS@PbG\c:)F!>1h#Pm9<Q6ZrS[e;NPBp':%YcaB#]*.mC<'@.fc6XW%4\LBLHjp/F#mm7j+(Da]5@n%h=<c,WQ7+B\,NEq2!8MsJe0+58djOkO?FVJi*=F/dp;,AYNX1-%baAZ(S]6#Jd*XRmo6\t+[6:79G?C_]XFmqf1G<@O(P`Z`f.CTU<&)Wd^G3-NIhDl\)60$+E.';#Rj9t-R:<bm"u8nh3q;%n^p<'[PR1?Ul/-V0==BK])Oc6oFu1T$<`nhmNTM@pXU1VE$0c]LqB\Ud=dBZQD__R\,ZV2alq<U+4nF/\D'CNI0a:1DJhg*GB#2LblZ<s6!kY9VFT/a^LnV!5dEp>_fXX!I5Y3,Y%)hd!MA[,IJn>:pHBQM792Dmi"$::jM:\!3$b'6V4_QQqcgR^LXu=glKdn$J?@:TA!4cU@Dh.8P@@>.X2]=-:Zj,*d#'rp*-&Mt)X'>tF9Q0f?&Wkp0-g]*P@>:>1kj'D@h3-R?U2D]HkUq\"I=@U$q"[:iK2&t#&s@aGdT#tArYJPip6Tap'M)nhJu5LV1uL.uP'\[HVO=Cm]2$Uc/9hq>"Zoh=X-oG1&1lCA$'nMTV#kfng]jd@1>T!H+8=+eqGG3HLB?;&bF-8X[!)L'B<aX/rgosXu)0&Ch7qUd-qqINE-e'VoVrDbR,kSb8$6EcVupXuXPE&qV_[,jY,BgOnG\Z&K9=l5fh\Ve?UpEbp0L@%+6prQ._b+^OR<1G+V_e3U5:GXf1Bh<[#4l64Q=>p!>_([n_A;3YG9N\3b\&*8`h4darq()AnH&Q=dAu+.0&_`djh6R4!j^SC2j3nK*nPu@ZrbK6SG)E-5HVh(AE]i73rKDP/Y$=+XNn,229T9DQUi>1;ogJ\jfgOM1[cSb%S=`33+VPEI8.dhi\ND^]X3to?aSV`H)Bj+Nc<'uom1jLf[&Be<jg=-]ei>2X4;r;GR\6[Jp%cn+dQBMF\EKo!/VgV[9V]L2]5`#Q3NtkP\<5'81eg<dmupW]PfU<`&2$VJ?g+XQ_j_IODNE"@o]=6.[&k,BT0%4W0;ZtmH^/Q(c(J#GrX[FQh+o[KLEj?38Q_u1^*]VWL[n`_Yhcfg`C/>;ooDd\=^nd;n<;5.`RgAhEABXjho\^%Q$&E30:jUR72;&,bak6m6g:`8W\%oQl64QDAt*mG\h9Par0P=Q(TaT@\9^rq)J+8m`_L:5l<rd>#hNW[hD2P>KmW?qUp-g:8#m.o*9#C9B:1N>q7J6/H<PR-ns<[%@niLde!;18j#?"#g$/1uP=ZTDBfO>E-&J'#iFHZ)i^fq%B[IJtF09^hTW.N!dBYK$V4J^9amWp_B.>^78qNY>himBfmI]i0T.LG@AERW=Js"?BA@L&85rNGj?sYt+aINo/(:&>e76RrO\9+5)[[3913n=$T/KM$Zr&^fUPAYomHYojD3S;Ku`7NBa%D1D4\_k!rGZK_A56T@pO%p);.8CpG06+Vdp9VCQ;jq$@eGA`olPATmBtepmN?Lh`P>4m\hr?dBPAU)=fZ*3JpZ.B7W>GmcL7Sht$,_IMqeInMgQT(/D)At87@%jr9pJD"r,<['h660HL0!%[WCA6)d]qt&.MdVl@jG,_81hgC@<Zj[@c]RQAa?/WqOA'_%CG4`H1S][UKOY2'J4@c`_a(0L7P5rk-tLOb>%/s<RJqYc/3g'^(PXQq/>5i%!_C(O"A1^=-TQ71q7[2.d7]+Ra?)mXCF:tB<JC1@LTehVR,buH5PIT>>B7"hH6[2RJ6=8e.^^S*m6k@e";@qY6&"%n@>(3pdg@?(jT[lpSGK!/J7Q/Eu2ls[kUZC_]0GeefigbY!o27HZG_^-EEJh;/t^\_A:8Zf>]>=CM[c[;0//%22?MFW;a>I_k.$&8#ql'28Nk4g)\A[ka#q&s,.=bhB;.N9Q?,)WJ)ZEqtKQSagVS_Il],%\I@[ah8ZWZ=nL2A>UA3t=5AhL*`Va[hOh^7..,OUPFK&7be+2#N?cVr*WOI3V_)hErLXrcV*1-/N`.UnP&C8`WD:i=7nu9Z@bc>.?Q@a9>g0UD0?B[(XDl`[LZca8[dei7e].Rc*_!9s=ba4)8j'KASpf)N=[b*Ao=_3S^0%hlL(7O#`NI^?k^OXW7A#asSL6iRaBtX-*^0ONRr6RB_k"Pu_Zk;2Tc[_K6PH7#RHs;#<7e2COa>qIiP0tKfAl#ll,dRpX\*FLNo=k#Np]HV92j\JHrnre=DCj1,0Q9?S^(-7jV!Q!]Vdn<WhjHGORgg>ZUh@<q%gAc,.!KBQ`h6jpq!3FK$c0\3@cFdmgSKlD(qd+4C3!t:f3l'HHm2\JnYsb.f7SK4ZQ"RKWcr,E3Y8@j4Zr"8D5@.pH9BcmmXPL28UK5Ym@D0Nqu@Kl!1c?Xd3*iYG;W!ZZ#S[]fKt:Rs]"Xg=":q%37`%^F#KSmq\O7%@R]j!q1<gV:X\8*9M/-e@UGEg$3XH\":.eJkM+Y_<&qccTEpA9pd>M,F6VH]ME,s[-t&<7u&<q(S0r,.`k"(?U5"Z/?$3SN^70Uek%;MM6]F01Gj@!\OnW',MJ31l>56>mb]L.i!+>b4jNl7(.`I>SYNnfY&(`^FiX%4:=BP+!`Hsa&KnlLLsAn>h_3'`.@a7<@(V/t["=3s7ick%h\R*.jCn4"`Z/F;9Z^a4;VgLgpj+r:G0#tsbm*qXUK.s#*[]KF-Ts8Cd+>5aYAY]_\MP)pD"@:%d7]]D,i8asQ?AZf6TRBOM6tS`HbrXi7Dk=)-2sFsTt*A,)"?//c1/gQX'J;6f/)+X\"]M-5+b%SRMq0,+3H"s4Fp/g@eR[bZg%"q?UUD/D!"(Nq,J:9$_9$$]8!b7,D6<]k3Y"E:rSHTh-u$nBqJi=k-%R):'Nh@S9PqAd)e;tT5,aeH;^JGQsndIKG!Ijn;^Hh2`b8V;8hn/ZlF<P(`V"1r)NAfYnt]rfM68Fn)$U\I8D+9CXT_3,VfoV9l_BiJ4^EC\R$7"b!O]`YnKL<j"k4=h8/@S:,dc#Y+*(7^E4k/T/sj#o!e<r*St<XlrV*J[1(MY.[r'GEM!51VY@b)]0?Z^3^1t2:Sc(\GJAUS_#hq]`<q;.SC3ojDZ+,/.\8>NDo[Oqj#nZ$9-+qWpiO/mh;a'Ai7LD?f"1+JA2:TYM,mP0,@&>1R%6gsq.u^))'^O[,j[Q@GDn`m>?h-Ak7<#d3phb=;\Y9a_PHB\I=$u?9b/:-r]E>jG@dl;Rm)-[Q"T:noX+i9Z%93gR/UO07u"^k=4r^lcMZ'fPGcXlSNdTOA+5KL"ZI+*1m;oqS7CcnQCm,nC^K43KT3D;>+9fN1HO?PR4B2I%.(g4d>F^__q)q]#_o>$C`/&B7*'r-Zlki6F&H&!$`@GA5aGFij.Sk7UddcdrNroGD2es@X[MAe=)^(7G9%>MYE)2*L[L7gbV:Tc"VX91rdL^NTSJ!B:-h)DASLQB:5D)C6Q]*Kn0[rRMRu)>=(_/=PC5+69qqnT%4VV4L+fjD++L<*PiX9-#o+2*m8Y/o[HMjb&(jF"'D^^H,sdD3(cs_sI#PRPnXV>dj\S/^F-G,!RXIgG>&+b<5.$OTn7*i`V]!6k\!1RRY7.-$GD?<aCb@+TYO,GEk>:(n[m,iFYV908ZVd0aH?J=]Bbj*:bPA[A=#"n"%"bIHUX\75b$e!P]ZYu]LaX(SM(K@W1(;k[&pJJ*>O2$5aR,'FI_Z.ub]+>%/)!K<M(6tl(h+u=7O6"kSCP6V]jgedX^K94n+o+(&.u?<JDI<%"%4UV!L>OOeN1&F+L_i_%s.M]p\FR=-;K7[S#<[MO:Hg70HoM"^U1Kqh4BD2>k1Z#PQn:\Z"+@*4tB>pUgP8K`#B1G1a[bYONEodK>r<uOE3]lpuOBYLB@nFTgc4(6!UGQl0b53G'o$]3<&e8@P=2[nKlA$\<l%?n&b<3VlVqNU/ZNrY?6j*4)m0Ce(RVF.W2.NVRSa)c&gHV:;;''Q:1Y;"O3C*m`B]h3>,MQ]dI/>*INfMfOs3?efX/C#nhs`Y0eoHT@No\3;Vd^e4Bqrr0ta<VOc"00L[nO9:aGfKpgZUe3Nh$4FOuNrGQi>OS!$8E[=YM4HRUHAp8staQe='D0CZcj8RBTelMHLdMU@K9fb&"O6B_\-W%Y$0QBODod2!Y@]X)sjQ;n1AhRmuZ,EIY>=EUPm[4U3a-Nto#oaBBT4YAZ8:DNLTdr9/:1f`J9X:bU9bAAA.*f0RnZ?P10opArYFIJI0:I+`]Ok>ZrJiYl5Fu?9\\!RX.IIIO`ok8lNpi<<9G'JD.W2<+K.tZ:;RV[E,[=EHS_o>#RSu4p1Ld/=gk<dp4u\rKqY3p9'Z%VP].03N@/FeDpM5@a[ni[9N6?@-2`d0C9"2IRFQoXSjD=Z?Nuk[e^8iA^="#A!:k<"u&0sGh7ls>U4eCtP]/*KgQCiF@f>gW<f#:QD6hJ`W'_HDX'P6FTK<pT#7!9f0U1-UP+b`DI2c#];EWJ<?.W<mYPsYQ=5,Wsn(mt&@E\@Yr7P`u^Ar?E/rl]CR%\/,1PBSq>Vb6!O>ZG46@;Q;_,cdZfApEKqhn<jDmeF[Y.F:KlbnE"#6OMU"ri>3UdkYjJ@'`d?T'JBF%ZK%8U8l=fN*)aI2:.lbIY<%5i>ef\I3Y#0RH<\m8]hM)N]l1.[te-W$r7C+.Qoj+iC@0%o]t`hb#5@2$m]"jS%E]IAlSFD$+9n]_`rdC9KQc>5it?Z4&sMu_+o]E7a6$2R!AOU`]%Yr=5@'UDsR,VO>aL'NQZ)_A.g1U,H4M),]g:iHdYo5_.Cp?+gmm5c`T(R^&ae37EB>A`S"Y?Y`XV6obcUo-uH2.,1M"rnlhX5=q`b=&"@c_#OcWJ#0+69>&bC',b.fR-;Rn]@WY@+p&X4:OWg*.:Hona)A)OK9:c&B;Vp"ak:D'SE=(#RfQljgK?._Mn,8Yc7\XAIbtg+Z$cL8DL4..:A80%\+npAs?DY<+;Ud@ECS82Ua6HbH3+lCtjpi^M6&<McdIDQpaKM5+j4NqOL+fqQa>0fKZaRasW&n`WU/fokP*_6UnGJI1;8h-*lBa[le'<.jhLiB["*<Dl@nDg1Zms`e-CU^6m5oF-ba])$#h%.4V.N2G$[q[4@&b+Mb\O=W)tZ1N2OT\!"uFe/)SL2j;N!scT+dOgE$e/T8HIWo+cDVEb@A/EZ"(MmUlN)*aZFJt\3,eMdYd`=)/j90DEMlmjPOJWE4RFhB4IP*9NJ_`Bm18r9mDG7\#paI#Yhc1T]W-153!gI*86Lq(Cahgc+3oJU5=fP(/#Ed(gL=fL=Ak)"0P"6D.I:D8C,YGbm68DYB.5Yl@R3G-uFq^IIiT:laX?B&5+fC)0:ZEP2-O_M?74mBkP%VFr`IN398ZJ7lsJm94!8e[?^#jCuk:Mc^rZ%\p_P@B<^oMHUgXRnJeQ`b2m_VEpZ7L3RU<uFO*q.,[X:sj%&WUEHZ/,l-D!,NQ++N5<g]#Td/A576U4/4,.F"a7'\uDiG5"PX0@R7KhQ2?@MYDBm&=LP;16Y@ndE8?@!XaTlreJWEs,rp\5gjhru_93S#u8JX>hQ@GVZ40OH%3)Q!bjd!Y3s?ob/sc(>pW-meV1r(_JsTg1j2+gO!]9GmR"nD*;sLbq"0P/M4EgDin$VT84ZNA8q5h4iS:Fc,&k=SaM#I7LY&>SV2N6]Tc4N@(u^HPd$5J2r"]r7jZ'OU/k\bHpd3al"Y$5AL^YA;Vp7pRs"3:K;uCdM<5md"hHrW70ha$qS-W5j[;lZ#CU&<F`#!es3Or27rguee8<Z=(LGjMr^Zl9]%h;oFGg6eFmfmCUOG7`NZLm/hZ`d<F]BK!6p/R^p6ua*1O>,fe(d-d[UX3'(qSU28$:[EM4Fi&FX2\o`9I#_F<%_3YY]&,N!c6IoP?q$N"i^@$s9a7$nRi^)/EX),u[PAU,q1-Bti[_1+"6e*@H@c(%BDjFK1D]Q=GOCf[)9DQ((erJuueL-&gm8e3ghpm0M\8S4-e,kmoW.ca11\,,]bn%I5@LMR3>ZKIQ5FWSTT&%^!V=W'm!\]phZrVMJMNdf:n+j2a0CgFnHJAG%nmH=/Xs+B)'Dt;J(8[^SE\e-??]g^K>[Jg6k4@jG27Oc\e]s86Ir4b#The9f]_IJPUcao7ANP-o@9A.q'asf(Dh\*'Leh/MA36!MnhkD*#j@u?'M[q'ccm=KMaqg-/T,(,ZJ0AK5`BEOj67sAk_n-`OoU6j2$O7h0H5IV%*Uc8`["t,\3?S=-#7gl2jEq&\1-a2CXY:[CYXo^KDRf0jq#5OOqTbd:UW.I2",#,&$\OBl0FC><e&sk\ibnqgEd'4^_am\W/HpKS.B^G8RA_.mJmd$b@/nZ:f7k`E;Mu6@l`FF=3RC[HBfI#->JUSkO<\V@Gk#l5*O1WbiSBZ];2or@)Q7%R]b5>$in<65>FV,_%Z.$#jf),i$f.qkPX5q:lp$C_5E[.8Z#mGt*)Jo_ht5Uo^mm1"jDpU=XEst6q%;9;(umH"rV\]O+-XlAjFGQU$?MD%jqJZ;<5g@['J@5Y%O6QM:WGq5b9)H1VNU4kom#8a,,J8:pTiVrfme%mcNmh7d*E!2Rb;(&ed<-MDBJ8qloM@G[7P"24N-$=WTC@BULt%M%efC)`,:%%m5g]"om/O`%p0CVd!>ah7"l'Z0;Kab&J/&9Q]d:N_2ha##2.nh4Y_mtRLNrS:RQfQ%9sa#p.NPBB];/<WP0g$l65R'%mV+)WAl2n!CYqO@0*?f]LO-bB<Y/p-PPn=/1/CmJEoN''L5K%ENg9=i(RBIO2nNNL[MMm8!Dm^dR4e(+VR.-,TmlE.3s[(5^GTj?&`7X6OemTfh:F2Id)7eTN^NmJWtFOLb,d&3^a.e_lGk;<D?Dh"cG9j"WP!5m*E#4Xdb5rBsbEF-H0k\ZAIq:67S/_isI'\7Xd;kr`.+Mp%PoCl4P>N(LMs@hY(\DTZCp!Z:20a?7%=(Z]]>o(a0,1m=@VpLgY9(PYPF,(i`>&qOp(k1VaFTf]q'tibXf"JR^iYV+UtXlj$b)[WI7e@8L`"B`XWp$&X#t$l!)3q57\r&n)#h9mgt!oZ;Yc/sOdaL[g9>^'m/3(WGPF'U2aa)t_.3b]@[R:!\G.ABc92Su63EE]H!2ap9dY'Z//X:]X!aJ\)lQ(bIi^)n>.=[%c@iJ]b@X%3Q0m]WlY"Q"O]>19eYISB@=3<'ub__.Zh*'GQ/?gL%VmIh"OM'>W35e(LrE\DVBU_MI1gBLqfKM"!47,ouj0T*c@n#B$RAThfKW[\V5IBs:mrmPsPNTqE[k+sl-UCZk1(*pV?]kMt]HTaTA=46U,jd*S/5d>ftn*KR6nM'u^ilnl//@PUSN8DjhE@]K,6X;`\J7'ol(cj;.qioG$DfI!MKV?u`M1E#=Wl3qeO(.BB8p";9hK[E^.=@WdJE1&>35([6>Dl%t%j36YC0BgDFSG\10l?aT54nON.D`$9qfKe\Sft%M09\A>"f'88jb,ZEL"IOfG%5a;C*^Fgh8mdJaFEE*DM0q-4$O/FBT]6c1:G]U$Z0-G[nkQ=KZGAt<TrmPOFf_;U&rncR%2W3*@?q5!@O&H)7ccXj;$dC[H3jk>3_RPLF)qPj%AF]=fX-^f+/&j!E?ZS<_HYB"WX#Q*.rTiB-[^_E".@Lf->"R_fFf%OTu!N\q4;Sh0Oai%MP+dmkVg^Di0hnlL,EQSJ_D:9A!p4.E_jO]d"YpenM%ljblDfpT-S$"O!-1r8rRKVA.dO>pcA)<GY%M\I&4qPM1!4M(T`0NQu3]0O(K(IWB?8(1;GT0<=[^q'M#Z(NChg]4X^\)8)1M'AA4)dS\p(=%5^edL(4FDq4&n'^bu:]F1NAZ%88J<k,oVFe?9C;Rf6"U6e8^9k??/D\b#@)U7#&rr`%pEQ<Rq;OW,$m.F*<!dSe7o?_(&^IW3CS+aBbK@"]Rc))q<ZS\*W$h'p8MV'3FC%,hMLe<$\VG-MW[V3UScPLo#3HR$jm@uR)#ZU6T<IGGJJCC$6"gfp6?pjo)'fDR<2blIf^RE4/4l=Q@0Qb(DQ3N_,fPhl9Q,nVD?G<j8s0-go.bl+*2]Ri5_K>eiU9`ndSTOV!$BaGJT8i6tONd=GY?:.p+8XMh@HSMLJnXN"%nA#d,o\iVafFufkZbu2_f4U!-[.EL)ERAN2E_#-r]`#>3ehR.>m_@j4\V<RC4:_ko,m_CE$()K=kiX$NfYeV5lkgR[nErE"<B/[#L3#A<0IN;]M':"j*DT(mb[*@eh(M-j5$>fb%)h`6NY"'PTs3aeJ69.2cY<o2@5ERh`>s%/Z*58ce04NS'S8`!Ij]4:F]@>!:r&/F_`[ERV0a:pR^8_]3M\YU"/3nW8\"Tg3Xulb#5K5P%%1d`/)oY%A89pI4>KG70/#BS*cS)E4JY$F7*o@s!9Odp$B0R.cc=ng,ic[&%h7]RGB&dtG,h>f+I2#(AA4g)TMhP%)EBPXSECELYMSWpr$ermI1/'aNQZUK8DCsNPfL%7@85IM&;PT<Paf?B%kIS4cXi76qJcgD'*k6GN(#*tHdZ+CF;=_5r"Jq4(grh1=@`[9b>@6mF\O[Tm^)BUOHY/9@[Z`+]U.c3fa$*Q1Q8t(TU6Uuq005Q,kW9dV^f7B;f.pbU1f('B%\l8<gd(#Gt@^*"5''VU5HA(N5f4aj%;BbYOQ#umbT#]FBgPP1ul`)KX`:pndpt4-G!Nu2GZ.d]3WT7+ks8o(b`D:2@6:*#[V8R(mTi^@ckTP/Gji:8`;uKTugY^YNrmK7HCCk6eY1l_ub?@T@?DFh[%*cbtnOb1-Eeg0m^_C,B:\\i4*Nh]YCi>e[Om7ir6%u?Dc=bX0[7H`5lu=A?0371lVu\C=F(i=aYU:[t3eWPV]a,=T[X:Q6UZqh#\54Pc01q+YQ@5q7ggNZi+Oeqq(iIk.:N`Y"9KuQS0bY=&Z6V[O(h4rnLKc3+(?Pe+U*tJ*7JU&#p=N5U-&Q?FX#6s"4F]Vqe</`P!OK1kU<F>RBP)N]9FLG$"%cQn/1b'mF>;@[da!FYFm0S2-0Fb"+:i#Up^,IUk/ZWrcqt\=rj[,%GJX-f&ep[_qfQcLr'&o;!t6fNg`g+=,TkKI$M1*I6H1?=`[gG0O]A2Lt"Ts!50JVtRq>CJKLRV\O.2_k:1IFFSU[#,ita?aP-H]oATj/#qJ,cW1_%RI>:ckno>4ZH$R?MZO%*(8AC4KD1.VM&bI!X_3M/22bMKWO"SsC/49g1`sQj76>g;>h=Sr;aWCCZW&FQ4fSFihr+D`o`%Fe/1g?2ch/-CkY1W80UkqPMq/K\OlrGiG$gL)<k8'RffJZ7#:PCJWO:)Us#P`2FZcL+(!)JbMukhto^@k/:(23=&_o$Wj:q"t]PEF_m+;-j6ViJigY'V'/t+.b)JDQ%HQhj_=><!H%32XHW:e"b-'n1),aY77[a`.Q[K(ubbI<O_CJBZR_<jDXWJk*m>a>(q]2B\!'RR'+-bqkm'uRtlVX"oCP*%_0<<SUT3%7>9h00]EVDK1Be]XFpH+i%9k8P=7F7=YbK]Iot+Bgi)]d'3j,GF^/]SEV*=rN05^/`:4i[APT/MaRMFujJ/de?HXk+OTg#/fIS&db8/!]<3C<'MJdKdYkr`6mu=PcHiPm%jURresdBgI`LlK@-ao27<ebCBq9GdII!QJL7n8o`q]WDMe1qfPC'O'>khrPNfH-ike(J^VX^XQmqQIO4gCP]e*sL<NMYH;nT#S#BS$<HeOc3H]pJ7+qYVc7.4>Kiim!(j65I>X1-Tlb#$ts0/dG8LJjHP=b7]+g_drQ1Y7sCN+(Y!].8fS$eZ$18\d_*gGR$OB0\(QjQ3uHN*M+g+"/<-8<Qr!6=Uc(T-#]Bo@rb-8#9&gRI>?F'uAFi!bM'-OInWnJ_k`4k;2uuc[N=0"7]2a_6lR\Vac]%8ZB[LkJ;FAp1*CR!Dqf?SL.&i1aJ4>XKK!tZ^0%/5G'bco;-97j7T'PlAlBdgp):i'sVi.b)?kq2*2:\MQ8\+3j/0Y;Wal\bU2cLK!T\LTM^nYkc8GQU2RO)qG;jl"KhtiqLNm9Y^2ZXPA"DZSd5n_:9Hb4^8uNkYkWG&>S*)Wfhp^j%LNS3U6/Yk<;nV965T:/lhi4-AB.ZpR&WXM&8<*\FnT#fG&?\q@@Qfh9?LN;lP9WU<@=U<UV(`MhICB=Z^NZRVAEJ_P2c5S>T1"s8sb<Kb"_D1b1n<-B'eTMT"st8>O3\ac-=LVa_((?'MW82MGe?$IAi`monPD*!WTA<VgP64kfTlZ`_8)2>V%CHL2@Yp5\W8@r:u_.E:ol^7%Cfa-/_d'=!NupM9PVr=2,KffITR6'MSsY[j#!G's/]arq0pWlB0[Nq<*.Lf!E&6]X]Jm[7Nh5];jWKS\@9n@(>NT;BsLF9<'LsjQ].sb#M(@G>t-e<M+7aqLg0%;9@EN(%A0K\OPRK[&r""/W&=ImdJoff3Ik3\^+RM0,/,l2Jgi1QLaZF5rBUAh?'XWAiSr<j/rurkt;.*.%8)rUNL0!j1i%3F/ekc)A'KijuhhOTD[<?3k]7W;a'@g-![s#rpX`5c]O'4Sisg[EFX[o7q;"YYGUah`I""8QF5+]jiFWp+d8M:/45H38dV@DK^;:K4fUq#HfZU7V2Z<oD]3#i[@OU>nWdge@8*<2_0gOb].iSaH+_eH\"eq)odXqF^?&hZHiu#r$J,5$CQ0`Xqg:=^aH67-R5jZ+bS"&%h*P!:1&3D36&9tIBE&!L>YL>EVigm58>r=.SFYVA^Ki0SSA;F3OA%]`A)V?Ma\8gspC:=^PYJf4Xs/NN73*[^bY@lD_8b%oU5M-@b=S$!$kUt?O(snMgnlVpI(nS7l\!!=@Z2.Z;P?'db_[9Q=EcR5g8^L0qjaeS$_=qc'PC0_1Br)F='/GoWhV[0;L73*)N<IPit$&f?'/"1T<@>qV3J$M_U\\+cgLP[S@bB_CT9d^@TlO/I[7_9?Dt[`k@r@OXNBk7iF9A-<0_#)]<Z5fiLQ-D9"c452oOg#h'WqP6Ae*@cU,"4(nTjZ;AEc"hqLcbE?&<3LNcm_l1:Ke-Ur;hgKk4c2L<%$h"\go\X@]LTVB'G($=/pWh'b]:HVmIeBSfpWr&uTHdC)eGA@?)@cr+[M[LWkgr"6Q]j#97[2YQ>W=dS)3KMP3i)OVa_Da8rk%-Lo[aW)@$/EFT\X1C_;rDi91#1\f<L=h9lb7Ml$'GFS^%CW<VUKqMNUKo@JI9&]A>IL=@TGRW]c6Le9seO;"Hq#4_s`5qiu\AXMCmdN\%LeH^d)S5b='sg0Q>.?b-o_F*&2E'#ZDaAA!Ut+Vd6<:"g>/;"eYVuerr$eP5T!6\%ci)9&H3LQHcG.UXl2m/9M=q]DZ#7GZ/MW(M77s'mP;`9<YSpFJjQ\*So2tZl*eX\)homd+(euOfE"$$M^\\&2dH\O(?3!L[$*[<2dL>L27tDjrOV*6T0i@4,><\_(-6&bi0YPSfA)4(pmTOCknksYP#I@NQkH7X.5Uckcqn#V&5dFr#*^*-B!oN"1b)hMI\%O4!(kpK:2&=GPHK(ba8T)Rs-=/il)#CUaULr^O*:FnZ,bRPbC]M3j7-R?:AhfSr6-bR3Hiu%+A&e#$lFsmkXEq6l"XOf*!+KAHEZ!603Z"ldF'0hkd#V\oQ4t\PgfK*fNI%XE_d-*@dq6OQafdAWZok8qs)fRsFDOP&kC%3uKD66232h00Jsq'68QS#*.XHKmr)Hl\OPDPk]*QnHYpM.KJ!d_u`=MeZVbN?D3?2#*j*Q/+XOKqj/oKVtX.0qQbIROMfp1^+J/f.qIbt=aNB3]2\.G"oX0iAe=pX+!GW#P,NuRf/IC)S39J6*R,l&&m?76>pB1Yf<2NB6o"6oo50UZFWrs.LDibl2HSTY9N&9DVsj(('4)F4D<[C^N^]Vm)<l^X2sKb_`=(Qp,jUtHKF8]U(6m6AL8l-p`!RmKP_adq;(qVBLN(6GOYM&q'mJKT5fJi&1#_3qgTfer0Yb&DA_LdY#G44ofI[oSN#-D@=YtuaOuBPSn*'=rOs4PLUYLN+BCIlEBU2,QR5"2+!r6l%9@JbX4R<`FODi)1B1>%$a!gcA`>WVgM(o6(.%9Vof6\8bh)5a[0UO/3&FT]87L(cnafD1::j1/14%15bE41*@VZ_dW=pYqh^ILD_5oJQ&Ln1C!MV%aK1qIHd^>fc(XBm-0H,r*IW3XuU+!LS#B:PWka@p;$9XN;Z;$Bd(JtuNb*AQ]&(Yu'oXR`P5l=s)TP$F;EE_2m!YbRaeaaI%\=4Po6pN%aa1;2\11P/=30,MBqaj-rED]AGs4QV.k5nNG*a<RatW-AV8qB_IXdG,g9Q;2GqLmY,_cc*ItR?Q<nV[bVVXjO'g-(@5[cp2)op.JQ!CGrGh."'LmGqto(HVdu53:P[)fU@A33UK"^cc:*RR@1KZkJqt-)q<(B,T(:c@GEGLJBX%>A&as2fbrHuimb6B/FB@<)U!6mIm<RScftFAZ.ng@G's8'8&OicS3G9#r.au\PV]%QMmI`KA@mG7lL!?b8G(s?r#%,-2T'7&]_9[Mr9b!apC$6X'5+rt\Yb1%0lXC>E*0RQ";int76Yr_eg-,g;WI->7A+f"EaMN06W^P+U,G4elFEF"iXtGMg`R/A+<?rSPf`lr\q^1[]2k'7UJ2U"!:oC39AYJ-0`f'HPl11l6Cb,#b&LqTpHDNFr-pVp3VKLeC@5M[C37ZqnUn3u[tnL;#Thm7OT8ke,#+LW.Acka!%]k06Y-4&_9XB#OEr#Y1^,B=#?`=Ws)pW9T#o+/+crLM+p[eeLVF<.$1T2;GcJ1cqXN#(iShAO,1TD8#)T4&eZuLor_d9B.o+J(l8GnPQ'r?g#\+PsWiLi[:A#B]l\hir?3A\iWtYgkPK9^-7EOe^R>DY7,YVB<_*Q6Y-NZNqTn2;/MJXO)lspN[&=ESU,>uW3Uq]J*rG^E.&rI=QK.S!MN>ji<X\JE)=G[Yf[ZWV'D%=/>K*ITmBkYN.Jb8(Fo@+h+ia+Em!hD_=lNN^c.\IC`7[n7loak)s:bt7LcAXJ+U9pF56&O<?Mn1Nt_$8P(@"YdjE-96Lp*hsXq2_B/5lc0iY-]3Jh3^F/$bRD!N=8ABK%38F0d,u)T_R:LYOMiiP:%:]$uJ$Pfp6<-Q=QB&_\#9$+$goA]fR1*3:IE8;uWYH&OWXNh#[;sA0K5VOmSBU!Qd+t_1@#t"0#,\>8N5H*UkOf3T34?f8#'CfE3-o7p`%C"bkmUK?GrX/9nrQcnrZs6rCigiDSa4mF%6?Se0UP#B6,f!AmZ.bepc@8I\Jip'dB(E]c3)fckF832+(,J[E>t<1plDYrSI$!MGO*ct8(PHR1OHl@aJ:Y;km!o9:&]4qO7G-kj%s^5Znii&q4AjO/fc?BUj/(ML64W9#3b88Zh?RRrVN?/D778O.+uD#e<['#-dVBiOa*rM35Ak9(h)AQ*PY*gqgM+S:o[YE"`HBa9_e)e-0)aHoe[Ca5lI468DcHQX,hi?`i#UBc&*Fc;U/NFU*9#tLe8aKI%\?0,ANhK_Eln8F`*.*3o0i>"hXBGX(F3!%"S#.s@IAWq3]-tM-JK]I>X3tDD[4DCRPDC#ulLB&#dN"Z5d!%;#B$Z^fom)6L`GBBHY#]fW*k<4Yk_@M=dHtD5^jsDJhqq3(DBCg4#D?A]p=AS[?YNL,c[\IkDi-s,IrRA,;V/t"Z"FWRI0l8$aZd%=3A6h70hP4bScA`kbosXTWQt*eE0]iP:Kul1X:.'_%IkjeUC7%R7;7YJQHGZ@HB9unc_2ucc-"0\KoDO-Ll0a#8bM=\LrH\&F9eDF4lS\A6Hi.*8o&Z?R"Yr@0ZD>oo]*R.8`9j+4OmtK>pMm6AZOO[*BVjUY14nU)6o3rNcAlMYZ)o_6CB44l"A'+(aRbVHE:#knmIbrbbX_9d&:\YL3_f1tgTf@*D6nWI'ZnlJL_G#(\5"4bRlmRDib:M69Y\nYVT!CTaoVeYT_TIJg7u-Bg(FsOj!mG.g8OB'WG6RD\6+?+rEikgmQQ*pcK,\jOj*(3_B_^oP-.e2;U<bsPM.H5hBSYJFBGSbG0\Qr^RDc/g3PpJ-^L5t1fYZh1jueZT_@CKGI0,_)sc_k7hrXGS$\Pc)rSnrOLAbWoj^+CSX*,A)'!WqUK<lW6si@Y[:^TFLH$Ma;6X<Nm;J/,QT5AfT_i^JN7tM%;;AD]0lgDbMa<dW+E2#^S=+jH`:IIK9Iqj/DO]EA7;Sr=/jF,4f!RfH]`\A=hT?IEOn7As"=;FYO_2Pii,Cb<_q4fM-KAD#n!C"F'%,B[r'Rn%lnr.>p9Ed9AkTP=QbJn*NEjuU_9\b'59PG'l9?-`*)#Pe@:3I#6_HsI8c6ET;$[%I9o+$>\op6b#(pfGrL*bS_$E7`Sr3mG5D0R*D.?%e^r(Y7kLcE)A99V<ci4l6`h3tt"*?(.&,=UW(N@WGV8/)DSUo'4^]:u#*=fjTo*d?07dA#+RCFuP]9HIkdNV$E0#L;/E<oJL3fbA*\Km=t.p9l@?fqi("+-u&'BeiL84("q'HX'$@2C+&KC,c=PADon"[X[6ec1R`jU>`HOrsc)Ooo7^`_W4P+M8X:\H9OMI)Zgkh^<.7"nX8H:B#434P4'qmL$Z/a.E"`il$#BKI4Vk*::_O=_Nn$FR#&?$V=H)RfGTp=NZ^KO'f'5W%0f(Q"h"1qtot\n`2M\D;+F[9H<jKjYNmD6t'(DNJJ:>Z><'G6_p)48OMKO*"8=!Nb(hLVDKD[6Kk]3m19(MM3EIFJKcWTC]Xp51kbug?]4,&$>B%b!43el"n`rZ)9nIkBuY?2:>eaF2*251P<YtN*YZX]4&=B9)%#(5;M5W*/Dt]l+FL'=k#(*]i.[<rhi!)-89-1^UqBAdm5-FU2A;#8(\79c!dY?OJ4&Q3IhMnD+pa@Kj80<KL($4^%6R:IfDO5dngEi[53#@4jAYoC%L9qP+s0:l:/^7#T/X?oG(Q(d3Q6*(nin&UOER^j;5O-(_i"H-mc_dM'@bHTL`#hB6@'_>pF(9AGt/7<a@FkSjXnB+ntXt(IU>hTn/c0bTT,mo*O>b(Hk2n4c?Ij[^^`_k"9H"t2c+cF6pJP8.B:%%.[d<PZ)G3do1?O"'gq6bp1cB%ac,Qg:s"SL_:Zj)Nn-?nD:A"%&)-<^6g8eAb\0ne<OO*dBrW",q?9-b2@:UeH:V_&WKb9;0N#Td[?+X0_?7,#[D%gkd*SdKG2NOknV/Cp_$4^Zd$$dc+Q*ck-=u.%p8"k'.`Vm1F</bf$*7BOGTM#[$ue55_mcM'%PtQK,sh=]:%n%$6q%#"QlFb1YaU?eUf^FeKA!!kZp\.,[6K?LVQG$DEBC1Cj,seR_d!5k3(Yo8')jL-5LER17iR^1U0r_&,=>';?:\K,b4JC<Kau\P&eR\q*j<JEHB&1$#OVVg?A;r\@UVa(Zt9h]cJ?>-3OJnnE8JYq[Y"WTO=+WcBOQnk01Oq1WHKtPp=?2<I1SV6),kg`:K(m,Bir2g/k1F4[B;C'S^UiR=M_TT7Fr'@aTt(KbKqBm__\XkA`4&udO.u#b3gftZR1h\gt%uP:f:,&<f]o@F*L\;?1JG_YfbZ\NLY]H%WnjCPn2f'i6\NBbAH?CdlFlR/1>3bk\R.BCD9ZS@$I:3bcBcmc"NDG-q4r!`>o@*@GKDBLhO5g04(GUjj;^BQW#n)/]8ot$2PVJ)YC74e*8KNQd,3-bSgn#R(Ia`)*l)q?e[FL&J3>$"=-C",_SN0!<F?A6<BWs]G"Y3'ReqK<O$CN%&UUK[1p7dF^1PjI@/[9U$3(Kd_i.UqSu!/:,)R9&erqU&FsrL;$_7_9Qe(7%-m_s(cBeA?8Z%Hr1?XV@^`X7/ps"0h,[d,m&J.^Oe+#49t(?NjU>%Sb-'I1OG$VR"l)q-Ogp5rlA?smB3hS-BliQck?DqsN-%(VC7-ocTrsaj2U2!Y%`j)"epJEKA!MU^-p/1?I9XE/jnJ0[Ic^[tA+HVsXH?%.20^n]];$nsF-l"M/1s:[#se0KGDGaj\d.n4&pd&tG:3\Sj&O(N[=f-OLN$W9_@Qbagc.#(RH,FuQbh`([e?C21C^^%HiA"@>/qlQmV$27_$@f0"df>WJOf#k:1h:diqEV09aq;4VJ`X3NH-oV%QaK'Ls`3E/crC:3_q$r&IC`*1,$b!^gQAT8%7@POR8/%)Gp;?ii;?%@9<OfVDbsf=MXr-BL#['gn=88cI]=.^/D:4^o^!)L@`jRarIA/HTe/mG$>f1Ts_Ch:uX9f+QaMo%>=nXq4u/!e;YR,dK.[%4pMD0Ie!1)0Ji5R,"Q4mbh(]m#P[lrW:KlT(\'Si8&t?R.Op%SB-38ThtjDI6e=K6$-UB!%iH&^fQDZ7gh^kcLT@[C606g&FVeA&h6MTl*M&(g\Xs:-lMQ$VTflqY]^R%"E0)t+nPdulCie"fliQHs)D=pBFJDC-#G`.)]dWBX^1[b=mDGm5$G#B#kLEkta2H5]#]pJ-RFXMBiXA,g2YU8-e\mbicoAMD%VUaH&YH>r\b:I+VSk__hXd\$Cbc8<1#^NV!nRE:8bANqU$!X;pq\'0&sJ0,8k\?F38LNiWV%TnJmo\Dp+aXX8ht+Y]_P,)')<:$*=4Wjl5I8u<TOVacOcXr[-2[oga1O09GO(E"<umC(uT.dD9p+t:l8\OEDWtf'-tC2dhac3#a99ak%oV;,^a!F*(bl\"WrfBW3h<+m^a$@N<+2gTuJ0N\n@[_"oBOM$8G"%Zk-,WG6s4>F+2FF>!1Is%rtQIr"URPe<[3Y!U^$bQX`/Q9iH^R'GHlSC-IjGUm=\E0H&QE@k*tpVLVM(bW%@oJ[T!Se1Oamc&dp0*-qDl[/F^P@h`9s"amoUC$^mYZSPIn!fUnZ'$MGKd=JB2eetE3pL/K+$;Ym*4cOi8Me;,;7m8Z#pDR-ZHZf_1]Z!(/,bVpl>$Zno+?@QWr8+UPYH4.M(-?o/*4E'/1>PtJpnE"iQG;/Yp)mN2fnF#7U>_`E+nkU;MsdVK*sZ<Stg3+/_9cX4e$jmpth%Y2kZ]/d'&)AG1M'+(3uZ^=p;eoKFY&$-&(L:s*=Irj`$D/_U)qeVF;@LOB!;lWfN#\mV\BR3qgZ9\Fhq5Ym#I+V>#F=-<:1`Qa/dWr5?U`K=sO$A3ZXNuVhVj70Vs*?r+@Sre%"f*O[q$<^N^h?!/ZOMB:gk`n;&0,s<AR$,(cXe>tLOGu0[rN(,DnS0CoXiT]f`s2r;HX%0Y^a.?K]4!W]Pdh3ODs1r6q&C)`NeI<Qei_mJFHJ]6[Oq?6'r[nAf4^k*ku^,1!D):dBDEFKH)Z-@/Gs0^*dT7n=9I&9Uq>n)EL8mqF8QHoaDUfTriH^O6kgMpBDb*"-YYl3<)7(WI^qnoaX=MX*=+?3!)(LcfbCnbjk*_HG=E*bkoWg."*XFq@G2CJk>CH9\mAT:BR$Xn+P)]ZLm76mRR5WoQYMD/$f+e>sBe6rZ5:d:I>ASDL@/%_4(-'[Uf!?hb6?2C@k@<9cgF<d8mMe$aPR5'b[sEI`!l<&#f?8:C;lj'IMY0QHLI=ek#H7U=c\=!k+!;gc(qZY3L+q#HZp,$tM7`ZP)eB_$<>ahdO.rr@;6GRc=gD"7h\47ZL]*9Ed-pOY[djDp!Ka,-g+#^U3\_qLbLCr2<H;>W=3k"F-F=W6[=%[\X`^>"bl]A*`[,'Kr($e7\\Dg1f3hmOJl=i=E^0)4;kJojT&=NrunkG`Xb-`b'P=!WG&N#)%j5dG^?B@:FZC17tm,U"k=tC\U9-FN"0t0K.GdGbb.Sq@CNm.JV4!I&h^*Li-?kqju,Z\!U_1rGrOtnSo.rkDdT?SDHP2fV+[B<,b4kf,;NH0l"";5+_j`.'LtFj/.F1\Cn_;%?Z90m$SR4nP&NHN^L&.G[7^-0n!BVDpOHtbe1"m/2KtP$m@mLaF;Jrrh%VaG1)?TnHp@.E5OD)!L6mVK)N#:k(Z2*0Qf,C[)i<9os>2EOE*VM%o>-V3#j.eK*@r7YRP%CJ?`7M6bT:JFCF:U8E*?"h\e>8?p/0+/KBR'aNZ`O&+A;.gU?*N4<:$l[(m^!9gl[0B4AX)jbjDM>"M'_IlN5Kl@<nHRECH48I9qN?jMK#F<(uN#nZ0+2!/?rs"B^]^/<8<83@APer7obLIN4:YZPkhq#`JJDSEZf3Y4.ZLV#/@#oG-,58\h/2u+I\bfAa"4_GF7R;OZu$n?9>5f'-pUU3#[r1?:"!;BNg5g/-B<r$]0^Rq],ZJPbR!#rffmpXj\$Bm=SLt;`=(eaTiNOlg^"C]Yk'bi&eqkO?+%2&`$a/IG6e/'7,1LAUSP'BGLPjicJ$F\f-Rco+e)Y_AY'o@&dRn+@:(G<Joh7Gbjp8<_q-gX)+7298$Y@lbc%[qg\&B@"r;!U-m9OG^pO^)a>8sj(dL;43%LsEct>!H@>c73:FS3WaS4nenolX>][RJ.C.*L7Y-iW?Cn`K:#k2`gJ#4[0pIN;a^Nm.I!*g[H7sV".i?]E-7]5s1@"UWs.o!Wk^@"`=7s(,gol@dlL86IKYnc<i@1QHA\_<=UAIN&gcQ@RJ)(cMIptGsZ.Zp-]nW7VlSbEm68e8Gk74p&T2HXM=t+#8mOml5Ua?1O5F?\E"VJc%]m?Qjhl>I67D'q&_`T1<((pou#MkJsQ\&AdaoW/K]C]nA8,AOsBlL.AV%adG6Bo73,_fUqK_N8M[p#&bh,2-B\e3o_Y[!S685`nPM[eo<^/'I9L3VF@.d>GlDOBMOUfe@=ZA7fS,4'BFZ@:]Fa##9Ej*U6^HP&&E?$cMB'H;%S?E0(+Q=3@koS-5J6pp=>'ogVj2\%=!dVY<WP&(dVF=l.KakFH9:i$%C3p.",%V'?a9fEB'b%7=bO<6ReU9!%$aKXI\4RI&AJ@3Y)rIJ(%Y5PIKr)6*MT/eO&5jM$0^]aEt%#5O@23br=.3G1c@-W(78\>aCI4c00jS#5aH446gp6]]Leb#[C=oPlhlD[,<:H906g_i&@;Pf/I$l9OA'>J2Ud9uRe*$Df)@W?I#@/d8dn-:bUa^G_pudNG9<teU`Xo_onY@(QZFXaK/=R:qq[`bMg!['<%W/b8;SS\C*R+$+WMD4(p@(b[/`)$aaQHmg%G;kSVU`0I16Xo.E#q^HgC3g/<\QR."l[h#q"")kjJE6ThZ(iBAJ>O#]l-rO]dh&NJU$D+!D/uX[r;Q"$oIf@;&Ki+A*sqWWY4_;de>^4>@B1QW!2Ob'5'7M0:#s`s*\.^Z!!X->O+*Mu:W_(gqQ^-H7`E!J+HY+MVt2A01FhqrZ)[Jbr%[,n2r0!eOmX^i-]f]XS\_KIZJ33bcL"Z5Nf:?_Pp6.+$QTCOb57qFfO+`cR!e>ur`'8m\[^VAXMF1X<0.89eR9db-#<">H/?LjmuE&;djt81k.UQ.o+p9`Fbk!D#JT9fA)-NHF&,P7:5&.;`'b'l\1r]1B49^V"XU4iU"XOD)XlNfkZHPADC:j=*KH?V+Qj<s+KEn%B/85b<piOrm\#HOu)=&J?:N@YBP/Q6iCX:n!82U*:;-TIHOCM53_1A;1PK@E9F,.Dp35m0>EfFZ$.7a&\:hBK_K(q]LBm;F_CXVLB+1+B#MW."l519@U+0j,#jh_Rd'##IuJ([N7q5i,7n2GI$?aMn0C-ohTA%:c7QJN9-mjD#V^T>V%(O&jh\G((%6EOF67Oj/pqGV3Y_%P>IBN&<d@n&FjED7Q4l:JMSS%%(3TF+u1*-;"R*ce21Z/d1PYAru+5,Wu0s,@]#At7Un.!@j3BW'Pdn$1HZfo+P7+"h@A><65^TnRHWF&&W%[(2b4,ER<p(CclF,i2ZmCOBJ^4Jr&pKMqp5-EZn-RfNs?ukTAlai#Q1BIh#`A+rtO47?MAPX*hLCX%iO13g%s7TSe?`/=J'_bX3cb],fE*u:lOEPjOH][ob:Cc1`)/ufh4ZgbBu9GIT\3YfC;8/bDr0rT@H*i$DMK`+ke&icL=QFDFjrTfNqmo)scpQO&5L,qsCpfXVR_^\f^IVE;<c7\S"%]Afo]0f%7H6,lQ%+2k=Y`\L4@gEAJE9(8J@b@lq-aAP>LCI[eF$hT8TphsRu+a?*8^pmeM`]ZFS5h79DORZr._aY?sq^E@uR-JVqOI>m!POEC0G_nrZiQ@7lg[LO^N'[$S_TVADfnSe0]rh"+`e(F\aI!#GAB6m7XmpXBT%4fsQO,p68O=E\n:I'd%,ttk&0L'omBr5h+pc5Um%+YPbD@NAWPKAd-S1i2KBYA"]LF@sP)?uBs(&>NLCch(RQ@$:RiQXXb=[dntI?[M1O4fZ[31I2lBVD$2dI_T=%qa`AjS"q1dAjWd`g^8SRQL:,Da$/>n<**8?lbdupn&,\I.E/(6q>jbXfl?=NL:X1Cu@dR9Wjg'62LIVbQE-a6SSY27046T8I\%tf^@,.RPK+\]ZdrW%^sgDB6MJ=\t/d&`B7bpesP0l2"_E*HjTtZ,qkX9:*hatn5Pbp+9D*?]0A6k+]]*V_5?K0[DrjnNtH4iB&72OX^V]nhE#-I2pH&pn]$qr1$o>I?ajg7;cq,@C>@lohO1Oe6c,OKc_oFFkE:iHUYa%L6cB0hMkJ-kP2JqY4'Z[q'qe\]JkPnZM]Gl8MO%/C8Z's,IHAk%me,D;cn>;Og7J%QTZbGE,W1M#B;Wh+Qk`>?4&Ik6j(a$7=]%<:#;KpaXI^I0[>)ar`JoXr5uUdn8,+490=UUpp4)'<e1U'X(Y@I#*JDXcJ$5>`dJLKU?H)N/8WP\aW@hcLh=Y$]B7:&"He>3%W;4$TJ?!0Xh)k<gbf.MJDQi-dOMh:UTr$&J8r./ak1,_Z_0dhr00pgH.+MZcT0B``\-"P^l!G'sJ`r(j+iPl3q@l>+dJ.I+f]13QSh2$7%@EOh0^]gI4+-Rt4AS<ILa5$<$[C-GY*D/mp7X'gUc2[&e?LmbhE#YjZfa\0X.ER7rbl(j.X=,X64eDA+4N%+J9EZS2!B8p&b^W*1.&]Qj*P\md;,S7APsqpd*m1WE_,SMrppVp8L,?9oI0\ll%$E_n1>KCL`(U1)F]]F1ZeN63?7XU6i>-/cj^09&OU7UA1hA`k\Q3MjE/a6ibK!U'6kO/a?rMQ#/dd#bC_".1H2^>7$*NrLAKTLhI"n6WS*.K@dnT04,UV!`uNH8U+fu2W.`j$1kE(neYWJ"pM^%Yb=CurDlcGK%FgJ[ltP<hgc,!4$TC;noq7s!EeY\C9&#hqFCjk#R5DUS_=Cp3mW0$]%eI2(!_+;ZcZ-&L\8_U=JqoXf:c\3M(]B$sc@KAADA-^r,1?P`bq=R_EM_QVC][:JN[GFSTF_VT_lh.cf<TQK9g,m]A?K=;6mjVuoGJ0D1n<Z,prVGX1nG"g>Be52SA_@2@+\^P\I8/^P2u2[!7Lu!g9MoHKWod8$r&!B!A!I&*u3Jq48]o5]&[QV)K2Ld6EF<U20sU0G(uY,4`kShk500::<plsZo1iCR,V%M8mO>PUXD<D^l1^:dh?;g8/6k#mN69G(MOV[OV4:*62p5%q*RMA7=M<7+>fid80e<PZB>iRX?cjf#Xjd'.g3WG0G=L`c%O(IHt?8B%1Ss@!uunqK2!o<6Jl:)o:neln:%@D+R4B,7=6^(CUFfB#r)uuecA$'0fT+"Ng`,GmBm'3*?M@I,O?$0?-N\,cq#&VO<('K9L^k$)RGUC8:R72cm6U&rA*n,dAqJJ.FPR'%BO(@L,99pYT">s6d/*^_`Kd_EAqll.+`;l)@"%%b_FnioYeUV<"1Cp/VJuc^r2ULoOMVTS$e(nTC2RN2`Y2rBl\4>WbJCr*KXo$!0(A*^E.[I(a]@+\8s]iC(tmN&X8$5e8eK_#WupO:g$j+)f>k^Yui]'+`V*RbPoQ8!e=r-^Mt5ZZKKd1/$pTh8u`mqCKf(QO&WfPE%N-IJ:hMe?O%l$7O8>$o\A'0G6`DGVirMl5sQ.p6*VdP<&P5aLeH`_J=9mK\::G^3\h]ei!W%CnI6<eVIK_\Hc[[MD$6X#p#X6>c2l;5?s(lEa<g,(Ll=p.4o_eFCT9=*jesFQCR>CgEYC%-1K5#2Ldj]J8:hsp%U(Zmi7X%+RW>ZFlGUbSL#PMIF0SWgmUlY!K(b]]V_khWhcK?k1l)]"KTRsVacf8n<&cMK-`[!<`G<[H-4jrnKA5hgYP:56Zq0EUC@'SVU[ZJ\%mPfZT3&S"^,%H\4]nS#GL5gprJ<Z8Z'$6(if5o)kO2("Gs%"NgX6T]g&]e6J^ljj!8O,U3KW]n'?+3VA8E<bLTt5A*@'iF,JSB^IGXr&U>i2P=$oR=^c3afb9(#5p^_pTLsl\rUIk:HUV[u\1hLQAf4eZ2P'BaK4.mE1MU3=-83,b'26\4;`,k2n/1D_2RbE7%:?I2]^'!7H6TmQD#<7b%m83tPQ#IRP_"@`q'kIW"-d3pAHA<#$*?1GP>E--I]/,^=&6ZUK:Kna*V@'bAD'6]>nVD1>AIbEE`%n>h*ba'5fL?u_'2`613et=epYlpBlC$'#BQqA*G6qug(aKE!bDQsciYaiT"2%29,b@MU;_gn$@%*gY.]1Eb0B3pA-Z2[!"*[G&LiuA#anr[Cf&2gG!j6?00h`Qk1jZTpPY*-BXO1QjB:K,._JNuQ-r7("&Gj#a*g7V+L;biR(cQ$N\b;STR-S8%HpbU':D>iCRNhhV_YJP:isgdd,I$oN9Iphb(P)#'p0aL)8&hipEY\*Wi?O5!-hmVh'%"Q+F!/E46-[ee<&$_4(?rQ-3RS^W4%4P.F&bbqj[sY_&HgQ&p+/6l('`4J>l4>Z6U%3.ZsL.VZMnIAe0;bb)20!*Ye6chWc"]#,,!Si6".*h77'U`d:38g:C"6iTL"c:!YH!ZGoJ@:J4O.kD<,@<h"hg#Yn&e6g2jq3;205u!^%Lo07A'jkTLH&[#"LJ@#^N%ipn.gmlOkflo43+G9ULH5U/:A3&'3dl;IsR\oF19RnG0g0"<3>7hj4J6#oL^64l,33"N#AbICK9CPULO*(lI\'5o:Ze#pp-`CoXthjPAPj<KFoI:>)F.+)1(6\4/@GfN_,_bUNJG;,?2q$%c?KS4hg)J7RGL77K(Tu];VqCs*j1;3s'GZDBPUp.eQ,W[pCZY?^:I".@3_(&M0`:ukdHiSL8C1@oe3tu"!g9m%iUE[2o&V.-Z%?JE,Wj=fJ]Ja_4\uTl^qn:qL?=kRS8MKKhH1r6s)fs=X7nh4g^moW?4@WJI2FnZ=?ujb78WlCB\]9P`c[p1%JEMN>2!l>Uj6#i`mQ-<K&4D`es$49<R5_X'8%@q'll2./kHD?I?$8i)OX$![HM1&HTj*pqiHc68hCr<4frjhNl:^2^_'D#\D@6XI0s(]6NLj&Qim*qM]6,fF'+Yl9HH8X5GYH>7`WdG(rLVN%"&$h9:l%\91E9n7d>)FsMdmNk0JfJ:3Ti^)&]*Wa8:hn36%H4B`^uscr-P^n31DVD;3[I@048`;%K^kc,micnlQ#j$Tug*[Hl*]]b>'dUjQP\ml4`b<!T39.G`\.mF\HPN8/X2o&HI2ISh[*H%Ud,7=f;eFW82DDX2q=qfn5S5AP+9h,VT^Wdf"ST=t8tLcFHjad(W==VEpjc"WeiC&04<ul$j:PFHZZ'ZKj&gfnr<6`4fIK3A'iDF\$."BX?34)U7TDEXQTCTOeUTP"*g4]&l$,i>i`.0;88r-'P7cTO\W8qF".e()BZ?WY0iiD%BoC#M1Sbg-jHU&N:gCV@E<Aar199\Onrgaus^Um=W?g+30/ghu4^B-I4"D?+<L#Yh,la,`Yt.m#lTBCJF.?NIEH"1"`$gb[EUoir;Se'XBGD=GPNj$qF<4:g%*oT"1/K[!a:$5[44c+:<Mj"nfXH^VX9=ZOktjf&g>q#1BR+@\qg8/`q$^6n\;FH3siP6]rCZct&^BqBH:8%r.l&3\s+r;<_:tD&,WiUqY.jM>3)cN1ll<E:Tc<!f1>kX9ekf[`>tTKM5*]JiD=),8eB_#Q(+nm$rZ9i,^N*0.N(4'S+,"8*"EH@<6aI?[3#/0O"1$WSFal[-fFMZ(s2Ej/N^gKjk[K`)R\VU`[PTO)]kMFq8JC[6K5-TU8:rmkXqm-iek!&P6S$(/)8W70*r3OAIb9fk@Wo&>hO^pd<p>YYpH80gnn1_r,E?]C-/&"sEN$6%>NJHDaaHp;$N)]Mquk(m%#Mnc@eU0!kl>BEWV^Y2[mh.;]ECJ2e+^i1Jh%aF9'c;8apZG!W&Y&UcRCB!sgPJ3>>(RgF?QnR7/[SL\+krg<k#Iuj6foD=.q*K:tjV0#Cn%ZY3'lVR;Z^JX;AiW/pt#=7^0lG8Ym]qi6)e2Y%VT(D_02E'[%hZk+K0iAe6Mt!`B>=0Qe1;NROL/V$B$;HarDTdL_b:E#!-*$$pe&:jE<LhQ6lVn_CPrnClajJ66\nD1_&8Ll)+ObGL[s2%l('@-Z&?dW8+W*:5kp3\V&[4*@_.or$IAc.]:6J3S6(s9na=CY3,(s[$\K(E1LPCUi+']Q4>^g%UR(5TZAb!QN!2RgDDgam]P-mhiHgr&:\:RE$GgA4VPSuB5?Pg@$+pa:,Jnfe74b.@,UM,r'r<_,RhBX/[gM4o*H[ROE#Ok9PZKu(O4-L*h"OKhd,'UE19"Y\erU8X>e_5A#!<7:1<J(1]H)'%D7G2(WZ,nIA:kf<$?o5/+MkdMm9dalC!T1]nqajbE;Mkf26:-PZ'dutK6k>aqblZoJ@3ngV'GSn4:nS#H6Bk(V8cYSs#RMqHMARTG'kp&[@R?2j$A\\>#"XjhKBeO#R"56H!W=N4#R@'4T[-jE+"0Sta8mUO4Sen;LB]o<!I8d$%C?6\aV+L'&Lq3+no+%L1sS%ZVbj%G[T"J1AMSk,>Z#3f._uSH*SnP'i=!7&CiD]#N1)#sQTfSJ&1.t^HVsNWB:2YClaSK=U*<c**%"XY(kq<fLnIM.a;s4Jm_CSVnUh,rHZ%N`.Ei/E".fdA&qg;'Lc[&;4*Ul*;Zs0gOL#4U-6&VMY^F$r\n!:cK8:e+;aL>:GF39=7!g$fd3/:^U:`X?aMZ@9SAn3NjM>3(UZDb"P9BAlN"KHN6;aCd2%9PV_<U/Bp'^O1)Nf=\$%DKY52PneY*G;a)2cc'Hu%,8SB[i0#aCbY[%>iW3sM:eHl(Mr6"^4q0t$IA+@D_g`sDt2NMCkM`M3a4_V;4t9k`b*BIW0=#e-p"ilF&RJVgag`po%%-%(.GK0W0"_EXY*/6p"!)F;M1Sd;3`.%CqBp35Ka3sY"Ggd$Ou&>9(h"ULbtM$rB7L?P5=jEpp1l1I3S\pQlJ!TCVQ9_T5rC"^A!l9KG0"'3:i?O&;QP_S=R%k%JO*09ltaaOXdH]5H[\"`!aQ`ml]@.U\/E*QI\VjQ#/0pF)9YNulA,t)?V=j7#9"XP)2L+eaGYbS8Wd)$bu;'8-tS;&GJ:@D43pE+@'r"qM)!VL0#UO@Y'iug@"m\B<7pmI$#@@4S2*7Xc)[+,Ho]I?&LRK^P5$=I5.5JfTJ-5h[Y3D^8VXcapccVbA1E'_T:+0>D`;go,4E`=qY[:Fa!$k5c7LV#8M8L>UC3"TUXJNNE<jLYEen*Dk*TBJSUP7`eaieWBmK;'Y$$R?Dj&-fHUbCTC#VXga*LS4YUcj^>A+qt()Q,lLYBMotHJe3cLJ.`tK8nONTL-R$j!`]Fs+9Whh<'rs]*gBDf"@/d`"XOUMWCk];Nu`rHLWW>Ue.W'7qpm]R-;X,UO6p=5&,P)YhYRSPN;;gk8^Zq1qQKf0F%o?8&.oSE1e:L14=mcX,!g\[1Y+8K@BsLj8[(]Q#Q'YpM@/j(T(hk^k-.#EL#1ifSj4!tUDAe\\0.N2p#_(d7#;Z`)`6XiQI]D*$RKbki"R>hLu%mdIU'GLMFkOP'-4=28"Hu`BO..!0-<:<1gFkL9HK-P>DOFNPhdI%,ZNJG/dsNrDKM'B_9l\'OemYeJ4TD7r='&fM$T4f"T_.<`2Q!udN\]=+3UHV4F2\_P6.XWZ%(a!m^Lr"Rh@R1nD.*Hd\aCF%?a#u_?C#g!JV0Q-<uEoJkOkqKD#15#<;=?9SG[p7*p5kHd9<[7Wm\>:R^Nki-Pg15D*=L=J);p:E].h=Jo^+'`dVto6<InQsb3!p=_1fINiE/%\I3p^<#l0,%/q3lIj3pUVi5lg`U$O=,EqBogo$O66s]oI?VCjg9;PtFU!JrbZ"<\:VK3[q.;kro&]GNPj;`oDC>`biBjrg=[LPH/J?b6=AoC^755p_%j&$t5%\a.[B3"o$.,+E86Q865hA>T@T?;i-7/jFOM[FsOj6)-k`GG+eafHT.PUKdREc50mRS"FRV`C7rPN%8EQI\JlmG,1r^1-DErJR8JM(Z/S?6aA-DT)qIlk]^8ZhAdYU<kD;)hCIN[M(7IGPr_`\G1]*`lg.+HrMOiY;?S$iT,mnh;HV!J/#f#*DY4_2e>qZ[?A0+T_t+E=D"qb8ILUqu*PD6IRe"fS0fBmskU]Xqmj2aRC(2rbk:ll?Jo,Q<dh,Il.'l"FnA.9#QsJ#r*i*6AYe0%u]<BPZ^19_?Z%QZLNa"K43"SBKl^@g.)@)eZY&apB!hW-alAf/)d7e>JdA/.Vg(`(J<shp%QNqHst,jS>%D9bZ5lS!66/u"S@`#*A)n7*.1u]eF0b`MeA7G#Z^Vl#'PX+JF!Ink-uZ[UWgDaai5+)UV&.Za_I\Urg.sZ1p:ZD&#,u`&)RJsQUkf=5\Mkjd-?0>','SC5UZ>6f)B$TDj/T[j7"Gl@0FA=6\e/D!u,r$C#e0Cp&rk@eF?72L8ZU<SgBJWe8ObsgXF"PJ%t_eFM@8n&qC[mi=_J$+HSbV]SdCC+P><WKT7&^YlUZ\QDadF/-U-Q"a7lg2FrnXc@Q>KeNfc.Qt7g6'9ahED=goLf8pQ/c81MK4(fo559]kS<d'(K,kI-<EdsJi;r-``o^ugQG<65dB6kkkbCdIt]EYAFXsQan13>(V3*l%2MhN[54e-or67W%?dqmrb+^mD$:2(X4pX\'jjG&<2LZ%?c!H^L6Qk*(lAlXf?W"bUUi4*l1YoUsp@HN0S71>28G?3[8[?@3m%hiTJO%W!eH[F[]<-9DLh$h@jX8Zgnog`rk@^X.s1uF1@>JF,7$sq7rJXZ?nA/b<ujeD^J=BngDN%sVB;f_:HoR"p$<h-gDb&ka'C*Tef,]mT-3oL-G8$/n>T4JnlId@G"biEWL[d\VJLsY.UOpW,([>kq_&I)*2.;+%JW'8l6Mi7Q^mE#GYNg*@U(bDSb*2fq%%!ju0H]Mc#_L-Ohm$olqhs9Yn+<BSV=JZ<8oK-6[ojGTSaFVd/A.2^VXN>9(Mm6;JC0A5F7aG&\lu;`t-Q)8u$.6tkGVbaVd%V3mC$R5#Yd,>eqR7+LL#d\`hF4^[a+u_M``;Qb<8;WmF!I4%@1*^ZOZ[*OmTp>#fU!'mW&L;dp;$$g#(SO^iLsh&oF0FM6i0LZFj>WB"\'0*=(.5,gge1r@CJ@&"4fuFk<:8HVj/#bJZT!oDIS&X6QL$@NW-Y<Ksg-1#J!cmmgBYsC;&;qHD;tPg/WdC2s%qU<m\8R1'0a&Vem<n(MPdda4>num[Zgu_;&m>KgNX&La;,%/VV^sI2_3ug)RnU"/>!Un6WGcPt(?L@;?e*\*Cst;28J;k8Q^VciF?I@LX1_Ot,$,?9I(hi7!qF'b#)*BJqa6gi.]j!rW*ca(r.B)WaFg`hPk1gVbBdd#$D-/jTdl*%5gMdJ\ko$]\KAi=6LF:<2-Qe5bKks((IrGRlXhok,[M6ZY5u*5Tian02I';H4H.O=m"0:!k(hU5'T/F)tMP^kGLG<Z@sJ*s=_t/jhi&:h'$W+uR0oeD(A\"Gd99!;FtaOpWZpD=9n.<Ci+%IP'bi(OG3)40#M0TIMffk#sQC+b1Pe6eBed*Q2@J"-B+]?%KFMQ<%G309P,Pjm?RmpH*5[K-Z6kLr=$4"?kM.*Ri?bfEAD_QDYB";cHZ*MPD(q-BQV/OCJJG:'rEj%Mg=B&:X%k(eg#(@l\Qr62@.RO98rCY&Sso6t44B.jP@O=W?&t;2$A\-A-sI$8.tkl6"agjU&=\b/'1eJAR0Ib!O,4a'P'pH-DrUj$%0H(B?hnmt&N$mOX5X=aF(0WTH4Q!&?VS0\BCld@p4]I%`g%+qTSJON,qYQNne"8=&T$/G#[44:Qt+&YrHEKLr%'i(3jaY%_C(.&EU3*#Y0O3!d`W:'6W2?NEXu5;8ApReK<ONs11?'-Vnd*8"Ph['Ik3(bhPVM.Xbg00t7MS*Ekl/E)OEb;DmH#)3X,6<S,!9Nf]0jH+6J56r/MM4Uf+EDD_4::_!_ciN5^(<s)e<?jVuRa9V]+H8.S_cG$fKA4F-jQR("a219cE1\<H@m0Q*=.kLOjlkWa83+sZ$$l_s92q8_#+Ce\cm"(u+Y6;f#rk.5_+9YO""jnLob^sKJb'Kh[7ITh*V#Wf;AnM$mU"c!&GU$IUW2CQ<U)3Aa1/kjJbdgV5J:#g8m%h<1*O1(j-YTR`R"gF),`h=%KdDe'VUg!Jf'fB%no&SWr-DDqpM?l.prd34qPM<K8p@3Fm+kK3^XYl7r(JNG8($NLiLkA^-""u]A?il>XM(%7&))D9=T))E:B`0ZOu::R-rX^.7tcB7n7ZUaU;ZT(ammBa7`@IScF?<ra&V['oGG-:b#P5rR2\IL+qCpCm6K#D+WUW3[)d(=r7arT:p*u+MmQ>:?.s2SoG3-'?Ks6(*Bm.TEe5JQ,ddkZB'`Sd-L:oR&#a7H'b6Em,gha5SksqmjZR1,R-,7TP%4aI2bSk'MX`_`[LZSRtg_sRmRu(/^^)P@tW79)j^-)qrSNqVl1++r.Wn(YCh@\C^hoPfOne@RZ%QfNWBOp+piI'DP<MS;VrSB6gD@Z^?(QS6e"Y!5B.2_qoA!)N5$^L:Cu2b7T)_Sh@>PZ8-LC[5q"Yi4-*8eoUsTM.(IQq=u9,6"=.^Z^5gIO)>?W-E1*,9h.=MVRqN!Z@XXo!8=bS?9S(05QtR[9)l7"IC6BiU-q^4n7R>:N#;eu3[ZX0!IY5*B>87[1>[ZJH.eUB9JY:gU*DkFSk3FA-(4*QM&G.CFopQa]`Cc`C6cFeS$6DD7ME'6T)sW^J(6o2J'jtkoduHhj(Mr#3gd7l'jI#H/.TGc%Jc@XV`RN7eFb74V"QKc!m(hpJrnRb482:C:1sLM#R:,JPE3f-*Id+655Wd9\p@amPbn5p.K8f^F95hcP75u2*>%(nJs.CjA`uZutD8J+qmRf^T96B(Wf(Z7BX+aeT09bY-BZE-RL;k47DM<o]bQT\!5ne#o,1O9Le/0p7.g@i`b6Zq!.oolR/gEfR;CuX<\fEYSF8L:Xcs#UaL.olKS,BeLXVHi*HK!Om;CWYR@jrcN^c7u<]bk11&R8eL1[0uM>$J8q&iL!*ra*\9'D@1K5#U6;9thW1"O#d>BS_KrW08[2M!A8'k"1^C#NW6<Hpd'<N1$hs597WdNV+9D*,1)BP]I!KMG#@l\:b]'DDloaVgWl+l(b#1(g*$$/Ti]_LMkb;UmU=]0g=V06kjn`\mi."_(d5PWR,c$D<meX[KViX+NkZYi`F5>'im%'fJJ#gG^-aKHQmQD[5WejTY1*Va1:NXd%4"):X;^S'C]5NN*&8%3sJsP`e]`@l]7IP?_0CID=1O7^J+Lp(r*7Y`j']u\uAS]-k_mSc(%>Zo**Pugqh-8MA/_Fp<*XG#ggS':]r&B;Ad_8IT)5969g82?2[Q3jn?`npH>%(Hp[bQY-Wlo&4RElfb5#9$M"39.@Fc"<%`rPQP'$TcIK?D!+Qm:.6cqELZG7i.T4gOUN.*L^8Y]23d2@LeiU/f7QlUlJdm1H>T[SB)%#<7204tQ[0lAa_3u:iXRWm'.>$SNVno78,GM_pA2pQ?/Pu4'jJ'#Y>7a4A,E\`lE+V!u-?7Y=f&VGUGK)/t[A7,KbOo7*NPs7\cukLGW[aTs8o:P$3FK1(2q&L85/F8[E+Pamm*/_+NC'oZkU`D"*MS6Sqq!)J,8QUR]7*NVX7POVL6(,mN$i7Z9;5EJ'5bXb@6=c@!dPCl0\.#*>Rb9O@:B<c-WI>C#R1JNaXop-3eI3o.l'@XRR@.]_^RDBBdt[-+G&-F"njPL30F`-Qt%1j$m`c[H)E<&aMSI_13(`dhr<g?n6m1;@Z2/R^SE_7"1K7R+3=9X&'2aeoO5LPjG0UEJ"TJZ'f?XUrupp]q*L1#7R7,%^rR!:%4[8V(QX,jV)*,n+Hq9C&r+"'ZsV1q#L";%4<P]LVW&okQ[sQM&+tG?\13$^9I^3kG]nJ):@'*8&gW<.E\^ap!Q@FS:(:AV.VrKLU)H=n;bEa6KLOUj.5GTOrUoi6TqlCaAdsP4)GSNg&_E&'E*/,GNW'A[4;HM7%5%:71C1n_AMm3u//h1UipduMi7]?\S#a@[6a8Om-'oYa6FaIma875EiGuSZIO,*N3`SZJkq72(G7G2PkA^>4WrA/W7-[&n:n\jr6`5Du9=!f^/$>/6.7TC`*+4krWG([t],IW"BU"025fGR/W,WqMOarmT.TM=7=sY;SJte>NBppB6TW0-8d2IfJ.B/1+,mHKa?SS4($gHKsPQ`U+<CG=?$QGHN+[#S#Bn2"k7!j7bL)WB>KC5AH+DVf0RA14U/=[P;'AabM7PK'02C,r1/bm0K3J&/+>GFcO_\.D.,T&[H@QfCW\N!Z$D[s<eB'TYKqJI2Yfl4d)$#_O\cB0I6f8;234:bh7*04g/c\.BUR"JocjD5r`m<)Y>3V;qFpp2VMOD&>@4^41$^f"PC89bl9p6*K%BD$15$3,,+D'lW0'NbjU_6]eRn9tC(1W[AI$=Y6^R_6)^1lX'f5YS/Pnc927$7Ue)R]3En%g78oBSrNNM'bh<Un;M',U-.+ECE5_YqSmC<=K'V^=T1Wp"V3V8JCr?Ou'%U75Y05qgk7ADbrBRNkoSqm*b)W9u9GU@#U>+DX+2D33!rAJAhh'6/shXhZ9"5/Nud@#$o"X+IAJSmoq\9$GaN<+*q^.EM#Z!?X4R5^`g5ic&3/9DWrCnMF6htQHt;6ZfUp'H%9HmXu''DKefZ*Q]!@,8f@^4EY:-S?%Yr2rkGe6-)V7o?f67YJpKN!W)Qr,pT:5s<0CsLOHO_s8*<@n&q#W0c0qB$(?Df\I<EnVDn04UT\alKa,S(_p+%oIG$a=N=$]e7]*(`$WMU"kBgV8QD$&9=8<d:LrFA=ib"X.\FH[Y&U*,+u*AaQ2#Xk6b2kQt]][JiJb=Tt0C#pln><\:>]_a^[6Zh#=IaY@#%TUXlhhJ;HESt<fOGf+\bo2LJiN)!pG^!+f^.,]o&tu7&S9(AZ8$JbNk5=b4Sn;1ag<m/.)^.rc@Ek5'41ibcFDH,.+EYptNkYq3i#'h+$^QIZE4Su]aai.T%!Wo3%j4Y9,lq0ZeY5u;f89%T.!8*YAeQV0i8,TdOd6gq!Kq[GnakPuQP8(J3fFnI1e4+f%s>-sL*f\pi!5bQ5=49R%K64HlAS2VSl<+CC`/b9FXd>kX/.].FQqX'*ZT@%^!#+QfEo7D9BiMEK4oZdSlsDe^KsPSd9dHj8R#7*rHY87h$kZQ2W:0,&;[]NUhL"+2,/ma6O"G(Of`3M]%8II=@9XG!4s)/jRQX>+?jK?09a2#EG237)%DUmj/ZTu0A8Z!+Z1Xr/VOU4+;b+9Ju9WA;J@7tBOjh^,7$hr#?dHR@*L$o]>1?-B?ur1RrJI<.)6Hb@/gejT*+i6Yj2f,k`=-`Q1c:Ho!@V2S!\2qqHj3&<4R2#C`8b9"gG\H="\Ut9e/oN7>%l<`3HCcB[\CBroU51"1geJmJ[:[E_`dD1$;O,&Q$X27l^<,Dh]c9@J-8aBc0UKg'R%2<g;[tM?6,.jGQp\"Vtcu4V2B[OK.l&(f;Y^+X/?Q;(Ls'f(?jd(;%eggV6>)4_Yr.Xs]iGbn2dPii\e4,8qsZ]r81M.4[a<I-BSK3@8sFOlqVXEL]/?kH:#f_RZdC4Cr*QO4EB'OI6d>=b`h7$SsSa2gR9,,]G#S<BW'U*D)*.0]dtL,h\KJo]hJuMd/q*cKaA+\9'2PeT>.>\5da,ERI^EA#n/6X6*;oREtG<;6FRW^e_;::QI:WnG#g5OerabA=So-OWq?^+U76W7<5So(G?=;95X2W)5Rr`@4(.mR$sMJ5$^5GZ%0]eipoFJ4?Hk/?3lpQ4<og#0Fn(;1smPaC)VsL`/#7_5nQLE^E.\X1UF_QL-V\a=fbVVi+>`UfjaXU6MT2n+,!rJcPa9>%:>s3GB=[$&'*P*dcEikP<#sC:5I,g178^"6'6J>L@f)&6pdRsN?oi_Z\'eKSJ\I+XJ6YK^CXmSR$b(PM_%3_4p#@3Me3SSiEjH,hIPY!X_qrYmG1K('+?X:0YiE8!J:Sm^m'rQ7?T'.]kWkekWQUt`_S;E+Km\H^cQr'pY*q6G#V;rCPbGnT,c97]Pe9a6iPq].Tn!k9!F(Sg7(([L#.*8=VHd,V\aAMN?H;YoM2k_dctqaK]DU&n&p%>BhpZnaeU`Ae!s;,J`2/S/tWX+*Q>jqTr"I7LUu*/$tgn$_gm^;'DB@RiI`E)X[ADL0r2!o9bJ$=kA`.,#9Fk$XV-Age/+IkLpWTW,"!H/%@r5i1H]rDR#E)qkCn&,dF1*=@'J/:GQM_Uh`4m3`K$D'o]gK_ok<198B-\Ok6F8T\W]?W8^EuK,W.[.&L;ZpW$(JR*Ha5fno7T6/;2F/Kf!]r`DM`H95^0<1J%NYgu.bmoGkr!Z"[(hp[KH>;(V0>4QWE`@g'&X<7W@@d2>[,*>G1rO-M]rK1?O1I<ab!Ws$h+N",kG.2;]b3[qf%k6cS(]6irQ/!I%p38]Yi=f/XFH5/<JD"bS+Dd()NpU*Gl0XK'2MM>k'V76WU\hPpZGIu!"IGL'=2jc6-%@sT[P26/K6<cO,X#M@IEuU*_k>g9EWu3JU.B-TQ'mCQi4\0n<f*iO9]AJ/O$s&2(GU6F-:(cn?_\)"r^u)UnNd\sSXGF2f9H'APY-(\>G+oCJS?aLff-7I$enqc$5k+$\2H^gUV]&kCpX2g+7%NqbSi:gN1QN<L>S.S=>654O7gqDQA1NK=NZ`.^V$%39X/[VB@l!4WoH%OCXaIWH_Lc9Ui<0-h1i29n@uV>13Lgll,Dr;1`[,9)3Z<,R?.h5Q2lLksKbJg/?u>Z=V4;*T$^NH#"uM=@^>e=a,kbiM<@UuVl5*Nb5E%^=F`r(N_:EOaq<Zfce/kY6a\L"K:P,\0RPdRB07i-m0kmYaL`j9T18\UF]r4R`HC(kj0\+(`HPMBt+V=C"[*iA8A=tD&.\fOX;7#Cd%`2.rCN1/;_@T(Q`[&Y?B]4TbNV5s+I&9f+NU@\3V/m_j;iI0P.l$fGD/`*j^6PN$;UI>PjW'<7G!?]pQTB<-WhM[&\iSAh]fd/-P9$,TTUVfu#["N6p.IB-GuA_#S`Pgs>)c2-2J=lhHf#GS_'(tB>pYWW,Wdp+n!-6`0L:R`eh9<N;`\5h!1P)[MfW,r<2L@<LBk=Vd%Rg;"d6>`YD/f'GnXNMQH2cO8UU@q4?X;$ifD1]F;Jj*,*R-(ZuLq+\RMK]9tKG+AiRD/g1C+V8OF4k=pO[7,sPZH>#I;hUV+k<oa[;TGk/7j/2_4L`EQ%'R/;7a(>I=haf.bSiP([uo\6OF/f8FH>u4"t8>O9n2HsJ[$q:?/75l0V+stSl8"KCeA5f@B5'JT$\eF8_QsLdXSu/e*"6K!=G%Wj[+hQm?0Rb4o[D`Nn@l.-m@ofS/[)NLc8fh"[Z)'2_ANN/10ooQIc"=N2mjVqh6"L5#SWg-Ebf*9HE+nXb/kP$>Lar[+2+0cj29j*6?=W'_p>W@)-^/hA,OV,g^$qV%eLe)K('?\PPXA5M\nnnS>it^'V-rV2\pDHa00$,DXYWu/V`HF_i^N2lnTTgjlTn.Z7>#:$P4cEE%LY/&VJPlFG`gdOC9FDF<7e"e0o],*k[B45?!/p#;)^m*hg#X`*As`^W2fr!p=hI*a*';!67b"5@=EGFX#A4?4@apDN086Y;4FlTM3]p^$H@p@bu&adO;VQ*So24+4[,BTiKTlJ<!BES@BI_5pu!LLM30LAMq0[PS"P?@2M'q"(i5M#(Bf`5*='Vj3YHdm9f94F^L""U\e^a3.&a1i."p=k1sK;]ZL4,q$TVhd6R9M[Ec)i*E6`3tqJf`J$^@=f1ncBD=C;hZ8d8O[5'9l&%7=V-Ru^m"<]rmR?#E@\BVoJ/=,0?%33jlk!MJ_Q9a=HZdt&.NN$40%X`2fq-aCKQ46]dB-urAS=C.]6=P`gOGlq;[_._R,7LQ+`^sob6Xr\@,<4tHQ.sX9R_Tkhl-/.`>::-rle:GA02BUn16I7tm`h<tG*$I:HJ^]>#*X"4EV]X5IG`RGM2'3HNFZ':d+E4!8$jIu'^AJd`n(0Y]8;q2PkT6#n+o37/V+1QE$tG`6ANFN,>S7A\5m8qG>u#)F91Uh+8gP+/;>aVVQM[MCK3[529HC,KR:N/"M(s,_=RNEWl&Ds(>9U%>.Wnd&)h$npbbuLBC)#ZJU%MbaPg5\;Wq1@lFAF.OW/>bcRl]J`jX7\I*]mA[2GPo*<8G_5,)@]qN23-sMB@!&^:h3`1i9tOU*=ATO\\H"MHjg`)8!_>bKCW:6R!%(W)?;1KJT:LE"!0:;R5b\42nB-M6SphX!/gST-P2JKs[;'$\bn+cRM*s]*6B0NonFHb[SSjKR$9[f[F_u0Hun0dPqt_k>iShahIZ5`:Q(S$tUc[;b*l*&CfTn/;Ee[L-jU2M6S?Hi(tAt#*XegDf>Qn#7W8pZ\LY*Fk)@7fL5PW$YUA6qABf&.2#*."S(<q%5;+oD\AbcS/UDD7YkdcE#j_&$AKbnT7cVS+%gR4<+Dg\guMt=S.3E.oPc+/U,p6<W,c/p*,P1Z\.]:>@]HH&RAf'&8O914GXFu17kR>0:b$UC5b)GS-HjGA&SBg"8]rS'd2<E+HmK0XOkJb!n7Nt,N-'cJ_hG=QaOcNHM"7nSg8$OXE/53],Ej&`og/6Scj,["6"jcl(BHK&l#qbpdu[Uo7f7Q8qm6I4m8%mJM$f1HA<+P/^2U>2"?I:]ORN-\Ei,D[#I)"[%*lTM=p.@,<;$9ET/H*:lRF-i_=:d'W5o.k*CjZ9+*$^7I7Laq#Js%<3X\8Yi",NIhdCq*9]MNem_Tk\#akG>k+!JbQ1dRc!F2U^gc1!^+;qO+-9OE#!q^kpOobnDTHZ>u/2gHd,3SEql`DEV>>H\?Omo4+>DBD4$0`GQAeC^>)+k#KQ.h25jK?L&`C-_=Op1SDd+S)5(E32KdI3Y/_/eMj=]uh(Vhup2c]+K26[Y)%+s%;ZZH2U$/;q/PHUOcglAJEL=Ii;EWO&L*=1E=l[tl>i)\2+MJoTdMIp"rml_EH,HMHNk[VG$N>e&g'eqdlbX!q(`.k?`g;^N`H36,=W5(s85XJgFZI&SMn^Q]&+Ut-kg-8_ZU%6&`Pb4cmKcmje4qXrdYeE#H=\n94B-5*e])N5&aJlL+]%b\87JnSHM7f<EG0P<b,7\LM,-o>r;`0Z\/JI^rp+dGq8e3+dZTr%C*5LlMF9n8b#r>e8A-c(G8mO!Jf)YaGk&jS'6?4QO_YnA`"!`;45C`jA_3]I5cES0CFBCJ\<J;=[K5Rhn"ZlP%<9/G=oVs'u?khfZ6s-+Oq$'5L]%>h%N]XTY'`Gu@SKMZVCE4o9#f+EBrlqN_\'gZ>.:@%VIqS7aW6=V62i6'L,.>DF8/!<,Lbi''#1Ul&)LX3`P;bAE`N1]42UtB"oXm5>(O(:br;u)@Q:N8n@XHDoFg;")`M&6\uQsso%/92Z'g[N:IA>UKC#kA8^H+1ce%a2VlID8:f0SPNY\gQMI!1g-\O6MYsdK9b<rs"nNHo6CV$1s!"+ZWE"%REKCK``7OhFb4V7Ta.UXZ<:/i<Bc)8B.ZnGi`P-hcn,6LYT<N6r98:5taVmd'>KliO\(pPA#CpKndQV-nlbta=]#r$>Zin2U)M'69q<OB^ko]#k%fm:;F'eFkM"iq"mI+`?("h'/1r07nTuVT^<#O=O;^ug)+Rj"quJ$b3^U^Fr5nAefB.!+F!0:i0C)F4_s=iC1qQX"I%0!H1UY$5b:(1)q^"[-b`JoW*PiWk.i$.(Nqp<BPObrEQ:I:on.`5<T42^)8%LYR7nhE#f@,Ri<pcM2gG#@4PPOR@S],*'LCE".\t&!;*q"0,'T4h$ud*>Dbe54q$2:[oR9:NhBap';cM4ECUdLl4fo$io-`m&14<)MMPRn)R/VK&ZqeW[L^Zq*MVLo,1['5Ua.=H+%,mrJ]X2%"'#I`kkO_$'`Z._23NW;Y5oRZS8Tl(q)]6C"iXASfG9%JS7C/_d7^a5T2TF:I3!sm1k=9R-hKX9i`8YJN8MY4SQn"1)3t,ho*k#N<A.&O?'atFBd)DELYGOaaekB#jl/B,iQ;0$a4k9sTO>n`^da2<3$P%AP$i\ngL5\a'nXqY$!K%RZ((]#,^mE>$M%);;aWJpu#jaO08u&rEpu='8`?;Dg@O3LheRf@I/IXRU3+?0n,-&#K\Z&"K9SZ&P\u4rFS6e+eQ6bD@(TSZQ0ttiW&*7#iZG_@2I\nEV_8/K9o(a&bm0V*bH2Gs\TJ*?`@ptKk#07Ei3<D2OU!f#D4ee`ZkfOU<BJ_77BQ9T"0e]JF7)`)p-u&P!:hTnQ!e:MnLL2,;/PJ]:gUBg:(bG<%EQG!.o"5i[*cUp\\Yg`iRYO!Ed$QRi+_?@#TlX&h29i&8Q=C7NeV`[1j^$CJA/_A-^q2)[L[?GW-<Bf90<3$6?WY;pUc.t^iQ7`$dA7%f470"823%7!$m!LW2cQDqm*h1iIZb]e/#-kL;9I"+B'#`"6VS'P0ji/V2q'PW18HR_6_)M:mjkl8:I3/45f&(b9/3(T_*JVu7FL;(#0\F(T\teC[`5S1Si<?6g3pAgNRI-pL#JrG;""l6mA`-UZNtY'rKKXg*`7_S38h]Og#*m`0f(JBLp60O=LX@oU-]QGg4pTjco35*)[f.69p*.37Z$,GU*bYq7T(euI8NG0";19foO3#j%dZ.m3$JY%32?=6ILpoE2mj&lCG8:GTQ`XX]`Y#('GM.B$D8=,H4bme4j#uSXsUaGZk@?;D_;UmJfVkf$gVJl0^_2lO^J`.\'0B$7L:%9,#H*F%rI,XL/marb]S]jI6K^%Af']Dp^3.'P-)]jc7QtuM7bC.!RTNTbd9#58)P4G%c/:og\6U1b%;&inNnO]0QLuQ%JM!l@Tu+=\E#T'*&N#Bl+L=*_O\DbC/Q"2$A>&6JJ=7q8JZ6*JRU#P50:(M+DIOBd9*#%>/08*#hP@+qKM)7C\I,&SE<kI-ObPpL9_V".TB8F6H4q#(AN1pnM$q(#&9giI,T>6B2r0qD^`n;K@bueSFl_c-/?)2?9<l%)iT9c]c!32[]-a"`Fnl;EQ1ueVH1`OP38\0mZc\Y.,.?GZJ)-*$6[M0/>bD"q_h`f>P42u0<ZCe*12t`ohL=9Rir(LY+j@(YEVs]ZD"k;$9n!*QDB_%;\(ldP[+b?>3C3S4c$)>N8rU:L0&euA[KSrd06IE(M7d*(<esP%MD%logG7u7F:;.7X1qZ]M#/.enF$_MFb@3jIAd3:452Vk$=01X-le.-,KIbD!-C!mg_]d:9i5\D!`t3AElMJRVkO?d7ap9#b8!@lTnAZCh;3%E+.QY/BH=NmM[Tt;d39k77*5mFZ@Z=`C65\\hL0g/[D2qC:bc+N1`fOYjX!=3'$@<VS_;e_pN\eQ#U"Y\IQ\`K?`]48'FK"mgc:iQ'?0u7@B.%!V!s`Krm>^$#NL6'beT5*Z(NC?8coId(!CVJA_HY@5:35qFi!Ri9?*N%*E+;Z"0;R+cqSJk^kRJV+tL3UBHAD^cdht&UH4++Ei@*JlSWWKqZ<9^_D>ITTF*mk([9'dP2"RNahVu1^U5+!'.hALN,`M=F2:10_1DQro-82H''mI9hnu:[QK=2`#s=5d$b46"38%6Pit)3@ZTd?bss0a`"O`!Wbe/,6D2F/`ZS(s@b<AJ^j1sM9`=:`$0\"57-O;-6.-J3j1\V=`&qQO8Q(q4Q%3J4'k'^&,Y2JHR\Z5],cZO3j5,*32nf5EGeDLn'NZFUJ$ZL?%L8_M"`R7d2`M_I,HX3nOo`#&Vr]-*h7'[50.O(I5^8&/=p[)4&c`Y*+TU:^kkmUmG<;DLE?to!dX>4=d<h/8<gjhAf@e.cikK;Y6#e?3+1`!8g1QZ0*IT"hg`=@sk]`HtJgBoNj#')nE=X<#0HqA#&!(j7XXsos94b@?;3\qhd%L1Xck@%'"^)0DrdW,(d9bSVYM%Z"`_Z$s!.Ih58JeOM'E+X+[+[f.OGjS*&.\Y,.k@eL,`G:0KM=4FJVG<ek[51K7YH=FB$<3[60Q4<E_k%IYm`!<U_nNaquFM)Buo8:,j]7gCeZ7$;f3+U.$1e%n7Rpm@QGDe#s%=?kp-_;n6`j2g,tFh[s:L4`Ql2i>\O]$cXHdBE^t0X@g2XOi"uZ4mNG$X6aT-(&LM.>:S?KbENu+X-oulEC&[aJEYM^:C`!ENgA1=R)1Re<#a,ld]#$ci1*Q8c_qb6eq%t2_F]\(:3BK#ra]^NK@\:9Qp`*$]J0/f,.S!kNFbDQ10:oh$CiL`HX`C]^Q'b>?'-4'>+<T$P$m)hr,*"@Q8e`uT`jFh0KdIg8Y_fd&NcF?m7=<+2@mV%!RBA?AecFA-4WU%&V''/V6O%@;m%86:L'!)PKpE5s#h$>#n)ohD6PO.i>WNP(K;*oG/7?@ciWjP^&Y]8`&VuREZ':t-kpUa`P@8[TbLtVZ-:q1@iCoEF4NOOn!V`0nksgod@?T-U9Kr!,`WP)GKG4SY"Nq@-6:qJng&gr_M"%GJI@r9>ZVV26,VG$F`UIMkH%oc;3p>!_e3j]VPa'N_`(7gDfUOV7d0hYA.-j>)XQ^_#Va=ltRGJSBTJI/-/V%0Ro-Qcdl[e(mfc*i;Pf@k0#6OF<cd6=I=+W(V%T\C.@LuR.5YLOR0kE_J&'#/FP!qQF#=9-*:spZ09X,lX-m'!-@0.bkTqD_sKN#XQ$a3UeqqqIP.N"nR#p+](VZ`HRaBAb_%0Jsg6OHJ88Wa5i'gYY?#M;TM9SASO$S\@g"JjC3%"q/O1e\8[1F+Nh;UH`l"H,N3,bjq.!&p%i/--$P8Gsf?+e]^."]f/"dSbVX!FJMMAqVE@p`n*)J=B/-.Zl3fT^lI=Encf1FZ#lEEqn[L2h*I4)aNq%Zos@-KAAb&3;;E(,tI/0Qd!?;gED8>!UamT`Nu=d(*T*L#gH=XqhPX^mnE5$1X.&dcI;4!NuLT[P<<aL@d,RdK4+Y)*2*QnO&V2GWo1"=+3UgfZf!Zu6(BN@Y.F/_0k%4tQN9AQA3WD?m%S7A&blDIFT)D(V]b`:fP!3h02`VEU8FUiOQNLUJ$1N&1L$1V@X3cW#(:f#W+t]t9suqTFYrQiO$I/U,s)Dq@ZSY4r&l(:kom0c_J)]&+DJ_QH_XY:FlRrK!g*UR@'+aLB%E6fZdO^RUU[tG5@[%]_T!n"1mG)9[D=rm;[p+)L!q#K/[DV<iEPbkT@8*(-Dpb"C_d?B+@ZLZL7:^e+jf,cn9n(HIOX8T8"tKO"taNC\2%h[S2fkLrYb8&(cIK)4=AY>>8W_Uro7/a9kZ_H;?N'9K7\9B;0J0Oh_]CReg,Fg@<ad!d)TX*Z)G"lS.C2n0:<1C$E+TCI\oL*R2@uCEJ"js$7UMiLo)Ib'Kd3e56b$so)KMXT@S2drQt=d[u^$d;I,8^6rD\b4W0nd@)aOn+-39h$OAqkZAUn#(OpRp;Q?Ios$`6djr2aepKguY5<Ch5i_5Tgj6a\(QU4&MhaG*BSjo:l)*$R),D9MrWOH4PlacU]j@Q,l8&4iAS3ZP,jYXhnhJtss6CU:0`U&i\m(m.$RpgC,ETQ(okQXod,ocPoCG#MA9OG8:M--Q9a4RnuQss6OpeNm-rIe/gBF5MWL.YC*/>.K.*Zs?9]Wc)F\Wj#LoXgD;.1X/iPbI4FR"dr[%4_NeV5#/u_F_(T-urk-+qu.Q0Vb9C69TanZ!aBr.'Ja5.T_$?&$a2``"(p)1S`0GX%Kup^&\7$q!F]#i]6T#Hqtp>/lk]*s+Mga6:(<C3?"`5"_)",`bbpJC$&j/JtIi1r@d9h+F;@8+FTcKWc4Il70Ol;H'J?-6WV-QY3cBBN='b^?b/P+On"UL-3,hBBY7T6nXg@&I0M.S_.Qt+$ktaG"^%'Fou3$DW,uncZNK<BZ2;A0O*`=1D[I-p1E5/7'N5H%*OQ&r%448g<F!ViN>rW'\q)RMA.^+fC,AkB.Nfr2pRe.8N!Gpl1C8RX9N[CRfOA%V6g@F++LhW>/gV?k!YMqVct'%Hm-#l1g=eYnET:ou$43Lp-((>4[]iJ*2+5CsX;O2cgUsc%cpm&3@4kid75Y`[;!dCb(c@C0fl^D.7=r>h(gKa5X$VZ*.,UF28&+BUCIBD:A7J"5E]O5u-[)=1lG[?>e1ZXe_MfO!UJNZ_e:qFbDogl&A>\(G29\K)C-h]J[D;QXF[Y453eoPRPQn+5d5@:BBEg8d9a#imA+k?NVn6GBlGRGt(<F'`%CBm<d'Ad(6di)1%%g$_$nqcT0O#D_Q:`Sc2Ful%9+&&cEj)0FnVZtqM*-Zj04M#lU/lq=r(hI4[#TB1C#_U7'@85'UgHK_HlENs0d0]"h8V"N<iJ\3$EM0%Mg6"Y_TL;7lQ82Bm"(%nBlpAD^p:mqBJkn;$/O\-KV\.;4!U;;1jGWUqUe%!&E:V59RUAm:GUP1#u>I&)Ni)MHqsjCLH%sS$X1>99hI/P0M)g@3'qa$QO.-nk:0gKlF<3D7'NpYfj22?d"1k\gs1TrPsZ*hJNBJ^;O?unOV1LMG(QY:$D'Uu.&$u].)*ta<\/nm'kHof*h;G[WYj_C5GqhsKTDRuT)?`=,rLNl&eI+>55WLfJ_7^A4mDH-Eb.US'RWlt!V*r-@-,ZJs,9DH=Gs?jP4N$E>N;:EVohF^/AoW)&gEWV#FD&9&Ir=+*mimjL]OcYR*_[0"d3.Y\"tW6J1#g8T0<iTkJ-u=664ipjIZAr%6`PueV)8[f^C*Q/I$iQ&l=t8U!S-@Z"alTOcKr4BI]r'U2Rol]*[4?(a+[0A:U=dG0'mRi5(@%#c'=d'DJFE05&B_Zo639hJ%ii8s8rSj>cj[iBs"1)O`]SPO.)6>1S`[f/B81@-^9)l#hH&kUX-24,+=>"sG%Y+Wm<s'dX+)_&dGZ6r^K,>N5rfRffB(]^@gsjGR-P=UsgjXD+?kN_GO[-9PhX#P2rpH$LH:0D=H;PWcV7UWfP\+V[=BXds)d'NWSfJ<n4.;RXAS:nU@EIkJl?FFInT4HM.F/;r/E.;8M!$5*\PofLFgm$O/*`1dhn,odfK8i`j;mcJ04rgg0JgWGLKKc<#GC,'cPg9R^)LsH,0:bYu^f;bq_dItNh7)3[@cc;DL4fp:9ZnSP4&E?D%rKpX7/X6ba80AHVU-tq5nkbm6^gE];V2Z_U$u2e\Tni"+O&osAe:YaOTE)=`+G+\Y&J,,`3!;'$:#G?LJ!BT]&teeoc)O<KHA=(LdOEfHYu]/M<>mPQ4V``oY(HFcKdZcYL<htU"4/4:BM&9$1^!Rt#f-'CU6_AU7M.?$$o3;`#tTa[LI`qiU)a;5RRK&1Ld]c91kAV^:alM]"ThL+)H>'E7T=%CVigW.JBmI$!aeGc%0enK2NPd(TVOIoEO\*l?i<Am+B9ft+Xm"SAjQbA7U9nkgM%.FP]UuNTS2uPYW*;bScWHLdLp+g.!:ciKIW9),W6[MOCg.nNf#7p5(q:pcPu?0G8m6Y"&Eg8@<_eLZlB&a<=%6NVN`Mk,,eV,PpT*iPU)t[kjLbM5i<01rdnIJIn'c+G!79^g8Jf.%M022h(O#UM[Z[@r,eLG_r#oFU\thh3B<j!^#uU_LM<oP2lT25!1q-E#=3m\[g^15?.1eB/3>XEN,Np5H7li\c#%m'iP"\.*MKMC$Nr0@pGjY4K]PX33S<9`Go2]X.*)Y,3IZEIo_krQN]1H;@E,2O*R>3P2ie%(c=Nfh=!*a(4$QL8GMG1D88t0<P]deA>mr44kEmK$+s5Z\AK@c#*M!rKq04`c?s.>4W5p\3HAleko01d!/+<6NQl22(O0/\:Se`H*rqJt",5Y0[?Zs`Mo,Sq\*2OUHVbbS58E3$frg6!E'R16)Gp*!pSq&2`L^/.]oB-4lKD5qq"XGB:2+.KW*rLH.68iiqY$+)<#I"DT^&@Mr8oEI0#AQCn<&sljG.YOOed#]0(&UO3kK#OOYJ.ZSVJ!D49FPBnUJd-k%`aD[Yf^&f))-7$ZVRX=:cSW+3YFF1k&SD0c0"#,r_Q!ErVRBF"\))(Gt9bD4g7<d5C(e&Ha^'R%o"MB:RAXW=5l9qIdCen28.&KG/9ZC9MJG:B:O[+HFTjqb(DmVT8#uk6cuc_EYl^@!C<c`*H_AsGfW1E2J)XS09X=U$u"*%^d\eVjq2Nk;FZa1;$15C9\[$n^%%uU*Ah8[hMXY(h-6]Cm'CR#E",_oDBNkE.s8;^M7"gj'dG.BoAQ;mmQ4CdFF?_;dIk2q/T\No%+(L4M@irU)b/Mql@EaU>XV9*NiQ+_K5C\1C`D(oK=XR-Dh`GOW#BmAJ]CFhS\iI1#ntTNDENe%[$k;B<'5%DY?XtX"PA>f`RHup>pXdPOq*=!U^1KS\SQ!ffS*f^TTp$+7<%6'^r@BspiN!*-FYti75ENJ<B/W:h(B0_(_n4o1h6b8B]"j!FP)h'n%kZm)B'BTgaAt,OZc4c&#Kb[ICRkpUkLh;-X'EkN4*]PM]bb46UcY=K,^R)#9N]>LJPGQ"B4Fbm[XC<TgM!H8UU>sQL#/T:mDI&O^iXrl4GkQC;880>[&,f&L-3Z5T\,7VMEb`QnAEr#Uk9tZI7GqQO^fUB&=HS'7j$q8S)Qb7>cr+\[#4'l:=&#("<p(9$o#GXc69;i\k;j"ZM2IJ]E[VBX"F/M%CjG$K/"Nc01SI8TSqRTlfcD_%5Oe%jgqe\Z<3I6k5r=Pk/7LGe\D>KV@E)J9V2['1rEO"9R!S6F7*9!>$Og5n&SQ.!-8%VtL71,n^c_8]98`LbMXm"Ysb;'7lm7M5l7R]/*P/5T8W%%+###!D&1O2!G.kQluE$`.oiC&4u6k;$^S60VAuNd4eAt5Tqn9ar#]]R2o*^Pdo?I?r?QHG&.>glg[#\pmhTf8t&he6o"bhOSSrA:VArD!Q?.[+6FCb@ph#?Ut-Z31=_Nd#X[0*@iYTu'NHVf\hE/GR"?.Xkl"'42j'D5gO[,E_#DY,kM>>d3'5M@.h0TY8WTa/a5r7I9$N#:*<J'<WMElK7Y_U'Ps'R5'_6Z?P-:hcU^ircM7o<ELf@)(1os;p8qn+XhldU`N!S[k%H<2Va<Lj2`->ZX(++SDFtbn@V-OAj4uH-<Pjj8IO'=?a<+Qi4O'i-o^2o`6j>s6L$rf9TBs^E?(`UUfRlaSWL9ksW)3/R57s+*@cP<nQ,C/Y/-!jQj4`fDT6V,ucG(6"8^PZ>jJOM?QEF)c$@ouqXaXTrmFWGU-R8SK;4eKP5H2Ei7FsNOQ`0^)u"5<gTm?-/<UmN&pPPu6Z+Hh>:H[TB\Zl]^p#_jf8Aca)$!Y=:k(a)ADW.KSn-%q'gjWJ"(PD'S]P6;T<1/'Dr/5fiUaRM<_Y:mX<:4UIh+ij<J4mDi(PTHfcnkj'Ik8,R%VZ+H=S!-nOW_ebR9$j[TM5`>t39qamZ9u3T9hWR2?[Y*B\at4C?$Y9E^%bCDh!X:=?7=Y$>O9$k[?-sF=qoI9:ofd;;-kqMSX^[>f!@'ZWm.\@eSE)ZInJm`qcVMFgL]]q%\FBr.OIiW@<&a%-CFU1<u#MmG\EZb<R)#8d>D&Sh]T`ICnRdVBTu12:t2uf]3o,J&VQ#K"nQk0JcM)kM%$W]6jU;N9bT9K[2D&d7j.B`2h2qXcNdM;,)jVEEL*==1@C<,e3J[s22eTWb&)muUW1).#uB5cg[Tjk#r54?!ON%mk42[e4`V&QE[:aPF\7@jeR1Q?EO;e7WZUWDF=MlO@i4\lI<&d2>/FU5@WA,#1_$3jOs$=mD-LK6rSSOqq&"C@d4A]4&XiuE!JR%P2_<>XodU$)W$!2"dfF-`(jQ0&#"j@7ZtrDis"9H&b8^#pm14oh/18E0Yo3($pTd5a#TAs05C[;/^s%,;fWuH';AkGSGN:4G5b<Q>h?1+=%4Ok95u]-e1GV<_<AI7$V$TFYaT5"3cqqr><D><3&.fF>8r5tK'U9A05p7dU+Z..D7&1Hj8M*b="@Of^1FWG-,_P0/TP:*o,Sknsi=k;L&%>\8#;VYDG_e`l!,;E31mniD[gh0o:P]6omiX"YBb^D[+V\TiM-<.eKd6p,qnI*[.V_RPS3u:_NJ'ZZM@"lepBVk'(b\D2&hPr7PQ_?r,uP:B#L4==Y`fJo+Z(o''dekBP#*i*8BE=q,XbR):%V:(]b?I6+Nb()K/R4MKA:f.g^gUmprID%O.gq]!'kQ`$V0PJc%4eb&oiYSegJ_+h,ILm&5"gf-A2b7rn\.K`8@^p%[ck5DX%g!7Z^'XOJuWOR7&n,!#On9Cg).%V@5jWam7XkNPP5PMF-9s"63F$B7bQ5$V5#N,WdWJc"uBPr(UTI!+Q*C9[jBX0an-.&Z:Z\GB\.*-4Rus!PqQE&dd%8S%c\R6Vr!$U0qBa6NY^&H5IX>F#b!SUIoPF=WOC!*C(;!Z?IM_ha_tORmn#<E+sPUI:_3mGs*4uk$V^SI,Qher5<EH'9fZGQZj@BR;!d?+4SAQ+a\Ro:>AeXcAr?rmYbV1'*,lk#NV?m&o**8,R?Dj&%k]L<2'[$d4+h4"057KR:r*[&&L_1d_?%D0d"$le'[f^0.#gN1IXo6<@gR4'V_r7p#]JKG3uUC+gD)QUOCt^E8)DKH1fS`C;RtqUdV0Vh,nd!/sGBOj^q_Kh*fLI_6Kja>Eghi@[^;!1*R,FckS#I`Bt6'?!KV/r%A]ngM(MZ0M--O1jeI:lMA#Vm@tMd9PU+Z`.hB6X=!`?rs&.@?d[j#_kIDYCg2;N^%N\gR"Gm7Tp9ahd2O)q2f9k!k?=^T@76pCZUB1[5pRZXMaU*W6fl6+(geYPp];Jp`Of9uSmd'CNc,#Y&)doQZW%a/%^_pF#LZ")F87fC\)q/jW,Ci\p\&Ko2#LiQPRIU,`KLT@eg`?+cZ%=+W);@-$j0?L!lbqhY7X3Dr"AGHWq?#&>">L5Y(f"g,bYN,6/re$Ts-Zd75c;i0JGjd_M8Z)onQ:lIc%:]HP[QmIH_HB"Y[Y=%=O3QZ5\e@+80+lQh%/YjXRrL>1]+JZR)?;Bnc<5#4C0ORh3T$fHFZb]KE,7*'iD>l.\?'13nC*C]L.fQ`PNKdVPMI5,SCDH3/t"=F(VR^W3nCMpDat'<d)>#Lo]@K9&<<ahAG0n`G^W?PUo/$#eYm+c-H/ml/ZKW.K&`G&eniXYbH9Vackd0m"EB_p1$[RMs+u-BN62:cT6h'g<>P_T6*P1#s?^KATXT)bphKp9N>EPaQV^qR<J*C-T$&?At9UoDDVYH8S`/[*"*.S;%gXR\*6paV]PbWlkU]brtHP_RT+gM]aKk1c4V&BT@o.olSA&\r0XBiphjT1c+)./0"s0)[;(,`_)CDbU"]s<L3!pEKD`]R@r)on4XQ$i&2BOO$e10_`]0n1ajHj#VFaeD9t1ASq^oj[@hG>PhaEu'.fs6dCJC#B=Q':pE@*KU<#V4(`EIs;[Rr!`o7=R$OQ<B^J'l&N,'qC<5Q[dH?/M1_Za$l0fMIA?'a1cN/,]l\kP!3aosZi\JC(]iF.!eQG9qlZ(jtQ_k$++^C(i%qasc?9\M<IE!YN\.uX.r$nA-W=X"]-KQeREBJ_S_nZ4>d#8.5%K[?&4%^YNUjS@m!RmR?hr4:F0HKd[oL'7D.r+1FI%T0(d<ae!^#YYh01'(k4=e$a$\&)1T7MM0k/IYuS@hI3R5hdNHF:i+XRms??W9g*\mq=?Zi!:E`M%E2pY_L#9-_9_O<^W:66QT1I4lQ_'aU&gaH2qPllaP]u(c-mS&E22*j!Uj?C<q/tMTUD2DPJ;.1@>cM*%,]M;C)KH"=I#i'>(K/\^o"85JNHt4=YAi[Hn#Z!V$%"n_%pN<:GRpIV;CmL7i&ZlY%?T#*s+6$.5UqLpYg.7.Q2ea@BgY`(3_#`D$I=%'hT57*e7T3>fS_K)un-qJ\Pr,OF85+[H\s'd,k;E=!=ORg[#(#DXqXka_b5//RbFhi&(=6\]tu$$IH8fOGJd(de]HFUZi(K+&SfGcJk'O">ok6hNi77j!GC3.MI5K[IAC;T^;b,=ou?+tjmL6)+Xgjrd^DF/fs)#hm`5g1\WnT`r\5BhkOc[8KSs)+$0qN*tHE\`7PS6mP<"S$M6lBJ@a9clX@OT"Z=i8#$m,\LuR=G4TdPJrpaHk>YhLB!.*#*(E6(`7#OF8;:*soGQ]M2N*/g^n\251$cG+8]=sNc$]u]:C@E\fVcCeK@pWpjlJu=^dHU@_FD?R+fSb<(^Ht\6fSJE[tjOsT8*Jj".nA4;T=?p>UI%LA=AV$Jf0.i=pejc1CPASlq`+,JULc(fRKuocf&5naWK%`d#4b,C`A.KU)MBZ/+(a&oo>u_MKf8f.7D?7+YZdjOr9(5$<Wj]__Mc+&jf,^f#CT=Jg..>ckP\.:Doq9=Fr+*WKp+)/RUn`$)#`Z:F#s,ONg@M9J=(jjMLCM$>\t>^!*+%/f.r%4b[?#(ltTXfjAB/$MSS-1bPZ/32<:26rCV@F68c-Q_I4/8I$C4"]%f+'7rL4ME5T&"%6OoeO`6Q[e5-bpTn.?cd[J-*5l:&Wl/SDjh\CU#Y7q"PB6TZM;d)=cY\TMW&l>P6g2LV,_=c^]OYK45m+V>JlI<"$"[Kg,UJ_+lqIf5%\Q/#Ul7lj6Rag,loZMm0REHC#Ec'\`Gb[Df)AO2INq+$-u:&.'9Jt9CoOHX-kk\4-S_>)99"b%S+9LOf86#b5HCW6BUYAu.pn"Z4P#Q?S8-.^)tfAJcRRYS]/lsr35%^2pfOK0=,VDAI21X%[[CG]jd@Id.[AobEDQ>#S>tlBe_O(d_ccM/'X/-WSZ<5'%TRDMqjb&a'.TVZkE4D82K'pRqT"sI*>?Ti)DHmfB:!@Kf<Sd'@@/?`6OY!4!(M?2m1\m+'6e(&&N567L1_AKEVPuMl3[u"7+_4ElM:<Lj+*]379X-#eQ&8odWh.t&MrY&\"Yl3BeT!N_Tgc6ZGaRj&RfbVQrgsET(C1*k(^f>I[t0N`1V)SVDuj6$#(.3f8-3oMA9Y(9Jb?K"X"HQ?ZN.X5#/04S@A)[QEWN'm;n3TR$#1!TfY7O3^nT*L8gF)s1*dn$k57+F]G4nBQeC`dBScDiuf1k-b"CL,ba`P4<t!t_E=Xpdf=&5i,-@N8FeUJ\JQrT-;48lW:h7lg,tDUdJ09D8U\Wm2Gg-"0dR#Wi_R8k-Wk7@8qg)+_W.l\$.0YaUOH_/)AG>m@/QOf)LdIM9KHf]WDcE^4q'T7r2.M:C/\Y\lhM&@:>.@L;-%HD$j;0(8P^P#=CIS!^15XFg^9XWmnl<,R7HL&=!dSp5[a=GNg*(r:D^Dn_>-W<0R4\r:OaWK3i%JL3afSW)V1+'+qUWU"OR4f'WU*o*`ZQM>Z;Eb<(%io$G^;-_*CD^56<f88F9jZXMH66SK89dkR^`($"N75RPA_`Z]r4s"q%-ur;,Hhid=3e4l#]-c?5Ur:Ec%&I)`7$&4i3P@\@YLCjBOKF;5YY4!=r?nkh6!SpE>>r-GfZRf6b8aEu?T")H]+"uC$EJHQOmPZ+8\DGm_N7KUf1%](+A1>H$^B%/6@0[IPGJbaq7l]j_75X`Cf*/A'/:KS(^E.5-g+:%I*JHS4B-a_CQ8ls4n"'\HXk[R\$LclPFZ9>*mOJ3`6'_;kHpA4^!Y3)3uZPEcu1J&XT2trm#4>gW+pMnC=WC0YJb0t,(4>4$mcJ3U$br];FL@-k-Fj?gXmq/;,f@9X&mde.Z0-JFg#E+aP9/__Gfr$\M.)LaTA0";so$Ijs&_4`6_<UjDXX3Z#6I=Rf&fr<LY\PR1i3>-WRX0*%=.X]lbSq4X(1#@r:^_t6![3L=BRbq!@JYK#J*d3PIufToPGLS7l51PG1CXIP:m8[_84q4Fr>D@Up=,jV+IZ:t_P%N0A\s^IaT""cp=TVAY@6u6M6;5ZU<>/iY$EcK=DY1Bh!<&Bof.dE8btJ',Jb^k%u$'\!qRNG8KUl!MnFk!b)<hrM2WQmlF\24AN*Xe*`<8a#t#S;(f\i3JE/1!Vh1cPWSG]$*l"KBB'/&B3Vs*bp^a8u>EcV_@6$^OM<QA)^gYb"o":l%Qj;+^i;O"//r(L`'pG)L(kPu<+1F5EMBBj-W"M\-Qp5$CcZdDTgcQ),e>R+r1D+7sfGf"@3#>\%XHGC4em()pGj+0g)l]9fd)f)>nN6euLD#.fSEmW$^LsP@CZ;>k1&,>`6FiaaoIa@&kl*c)*oj@6Ka:LtL9d\,TrHd3`1WP&1a!P.IN>q)B'fJ-#:7d_1"fetS/Co5*F5^(Y?G>obe)*Y=XKB+@$*p?&G7Lk'd=?b;mD.%%$XRZN=4/=,uO1%E[<1QK<>EHhiKmrg;:Mur%[1LZ>a6Va]jcBj#n_4mLH^9`.8HS,l<Y:8dLO\Pn-KYJ6)"f!YRj@OL-&XI/e]bV:l-9nn:s89DB.Ipgmh],F/kFK@R12\fD?L,0FiRp)WhGBY^MLPZ&trBVNh%-J6e`P6j=EnN6^kT0):hh6g"-eqI7b'fMVLF`pDKUtF<8O3l*p[SV"q*2?1p?;r:C6^)6tiZ/j)LK4CN'?^OA.MpL^n3+%Zf;s/$+'0fuDe!N'XVe?o:UmmB=Z.cU\_Da=PMoEcFp_U3`aTq^FD+?_m)*X'H;DD$+QX<saP/GHa<D0]dX[,W^[BTF1#"]@V?`-W`\b9M"+F<7e$2kM#mf2*m,;0GBd!'Y$KO#_b+<S=T"g>ndc5>"'/%^^[%!#'^,'YQoU^kJ0!5OWI^hKOnX0Ns@RWfD4cciUd6U,L\"Uj&fQVn^./slW*Y[a#g]t7UA!-:UfaS4OI)8PY!E@E5"s'n@geR#"KXG9NUn^p]+4s#75"A4sL,/ro556A52rj001?ue!A**muVDs?CBe[S)'f\"%U""38%Crh:b;IN`5:-qu%YnM*Zlj'<"s1?(Z.5eD?#%S96)?2kL1O2N:Z%,b3$O[-$+ai&M65K;9Vjd('"8ihSAYUMOTpXG'.->*7`O47EefE]-od^#BM<W^bJX33RUJJ)@9%#*(4sGJU&W*M<$<C')-&mHU]T0a)J891\KEZN/.,hM't8?ccJ^@)5n!ud,G"@*CEur$=60&*U4*78cat,j,5mPia[JQN;HY<qM&o&O>M7'-o?S?D<]tX<dhGr)-UgA%820eR%'Z2;Wm*UZ\dU!q1BrcJK_<\bLt%8=(8+ZfN<Yo8flYX_^%G]Wa.(B8Os,&B,j=e0$8t,$4n@s3)^h`bnVH,Q;I].jml\_B<@2l03QA?m7`K"n(<aMa/Jfn1C<OP/.8jd&&GYYPF3V$F3BSQY&PWs?(`7#%-]<f]V@tiZGW_"UB?<6FmarY6P._][3T0OU$qjZKaJki\(go%u\cJ\\W^<!#\qOE!gf3kkjoRsae0P`\`'L9?-4MZJ"N:X7<.r'jZQtd"[1L90"GDjIY63(sDZb/>D!a.7Z[ge&infL5eep#UL'gUd7i67m[Y'g;EE@@'.j[!K/?*2SYP*mO[u(mKMGt/Nj(5EQ9-I(&5.p[RXYb>Ok8i=5[aEHK2b3(;>Lr86mbg0-:RU'/7XAVJJ6GqaWJ+:TU5:Hf:dP4a7G9Y'3MU$=hKm4g2M]dDr"F0#iYY]BL8@[;0gV!Pq,'%)2l_g0qNhL<E?Mi"I\.[o[Em<7aZP-KY_D-?/8147W`_nt%"lY69PMn1^edGg@+a*;p1#BCB-%pEPTI,K0'.(S6]u29BEG;K&\J:6&k'N,'GQ4F)GZ>>o60I0]_!uRC1<>DCb-igJiE8Aj%d7+2,T+J`fb^65<SP38;PNqI;jaIj.EL"bZVHTZ&#q%%5<jN7/h8*"g_%hGjVl+FW73jZmsi7ALNKL6/W[bibFMeBnU-T=buEd,M9R@L_q0%;2BC'_'HBF6:jkA%<Oc?BheX<>AS=G'mVQm0(,g?9Pm7TgQ?eg@HGo%<L:kc%,%#A1G;+hj7jJ"`\\*u"FGSW,sd`rUICtWW.H0R:%!NM?kN$48ha*.%IsVeo!ucm,Rau5P<BX"[:<Q!1!tfH12%sW4'qEq%HbPKNA1E%\i;j3LC<.Pm-VbZ9$ksD4pO9OhT&:a0M?/qI?Mps:X/HOOL3,&74<$/7-^PnR>T>BW1>)HIp2A8eH_[hL0/U\[>3/-m>t-WcXFqPYi`W7f%t_Q)?4FnVM?<GjY;a?p7$hR8/PmgW1=0W6e]T+%"d%i1!%^RN$ZV/Ie,eKiJFOXC0n>?>nbPjA$?B3Yd-U2pn+`uQbQFudmJd2gk[2#OOd+"HK6fK)!ARAdo=b4I9cHqj3r`an)pf')eQJa48]?nU#k?1%,R#/.4/"r1c#eUAkt<.GEN]O@.1%$,##ona>rJ/7(^D"U+e`5INKt$8X0_n$0bE[7^&872sCDHa`n5OP7@pKN3"e\1Cl:>Yh?F\r2;>G_,H>@$afVVmfQt2)@8rf,"f^!:!'(Mb#5QAS/qOh"/JfC;XMu@a$_7,,1U<8'2%]p5$E`a,^?8QZ<U![OuLZU3Y9P(Ufa.m;>c%pkQkp6UDccBM*jX$V\rdXG:Nd%[`0mU.=s?V'M80&k+>Iu;UeDT*tj$TYu@:Nd60esa]/$;k[aMjrMLOQB?*&`3jr`9PJn"4mJoWC:uY&8_[m.6@R1;&_MTmRU?q5Y*;"5[!ukaSi$t.U_!X;.#>eD33ohoXWX[V`,Z8b&1FsB-2D[[]7QJQ^,p6)2S6JcZ6,c:!OOicZA2one'T>Tu"UPTo"K5]N!76sp$nrp^5D?$[DT7e`m:@PXU7N5s3V4.6;_hek#$bdC+><qsAO7N(YUjej8>41]R?o#IJVadVPfj/gXSl&ua%AX:$j!k1YXjTr^O0jS-+L@Im/S"9LXI4H!C8t-V%fjC"@,C@OMXj_6j+/(9gD)lT;lp4,%>+%(m-*k$47W%WE,7`(hOTtJg$9a@?HpbQ6;t)@#0\3Ja\5r&(<$:LNk*R"U]BHQj+m4N";\9rA_;\G7msTr6D$/]a+af'aSrY@Ye23-n'lUM@)m$LkN[*Qgi;hV\a1pZn)!6[Yl7epR!!kO]l")O&p+-O)#tjo^%>u9h<fH=c\(5$/dSE0B>PcUKGmWR5+g>j&.0J81-`_&<'-l$AC&aN<`'tcr,GA`=Q&u4NiO/<g97*7Hi/0<X_Mi",S`=J3=:.4(-u901?q9G0ug-@.<uIV."<mBWMoBR`Ti*IIe!T/4]OS.[I"e(mRA'P+CZ1#BK$(pFRKtp]^_PhN<Wcjc"bC5e`4#0Aeo]pBC[fYEq'RTH\KrK*s(u^q^U;'T!it(mA*iaU%Z*cGB3GND0Qr[6po-,]Z)eI1`7=8.hp!fD46=jKGkNZ/*4=YI?Gb[`YeSp1tW+BPY%>L-,PZgtWO='s#^5D"Sm-i>Z!LRP4Y*k"_@7L;0>s-p,g<=@1[N",=cej-aX&aZ?q4V,C^/66i^g..Sd\Cr3L.X4/M#A%+OZ\'F,A%[4q4j@Wfl6ks:\9cg=SXoXInJrQ&$<QHE$(/(,tjSbFJQ@)X$`=G=5XpXEVl<Uj:`\r&b,[!ImMQN$u2H$V<%5NT@/3[)*d2@qNnW7Im^>p*%68!2s(9&=ZH#(NH.GGfbeoXMhS+qs^WMk#kTZ<o3[Ek-`DBNac4Mj7e@4YD5l#W=lKPNCh^<>CFeO5uD2K/'7LE4S[EI44RbfM[P0_@KNqICp@j[4mD"&S^q91T[5)Ai5X'hbGq9I0a$<Q,CYJaPtj!9cd8[+,L?,%Lu?_%`Q).su6qd/!5@pP/e)Ba=3dPkG$VYb)lLl>[?KTrLC,5n0eF#CH^fHcoOS%M?%uI7<I;:;%^P4Rc_7B;Oi/g_=`q50Wi<JOp`n4a=c)^bOc.bb,ZC:^fTG@L.f$&b;:kXVtT2hSDiY.[LoMPJ;Y>FRD1"%#lnGa:r`.4P#*lZoSU.;2@%sEOd-$#`(Uk@mLf*"a&e5lC8H]_nC$c3A<u8^6H)uaH/+e33"Yt8oa(\Gc'uNEK5E#EHdl.F'*>LhKaaqN;#IMSH][&`"B%X'Yps$L__Ne:luk/+C$76_IE^4e`=X,k2c"sr\t+5L>!i/kR7NSihQl"&J1s?:67XaVa4<d>SW2Y7Oe_5W$4PR**q_/5u.1$`nCos1QQmp8R$j9'F&d,^`07'C^gVY`>Tg0"2d$l\)p2%[c?pA*eEOLTG-UGdZC8ZJ59HC:_42U50daZZEGG"]&S%u5B4)Hl-sM0YEYMBqID;1L`ir68G-OXOs>k]D'd[p[Ym_M`3^F@AGTgrQXU#P/0k)`j9D=GN'$-!.bmOp;,ep8/FN=S&ZkDb9cK"C0KA#:ru<Q1i86QW;\H?@E&p5hq/<:AFMgO=LD:cVLds'P2CSM`=K.868COSrbL<;Ona-88ep8CL7YZ;SJ)N%"3MFG[Z3O#5oT?F<+FdUKfE12p?qf,:&k3C;'Jt_/Y$L@p/N#]f+'s(B@`o:1@A6.<V$<Sk75SYa=R>[Qfc\U%j\d%e2&VnuDup>ucl^pBT9CGu@/#B_&#Ac'5VER6Qu:4m5K37oP?94t(qmd@gNn7]Y<UcQMKo<8=uM.b=Q-0iC1gn.H2fhpb<f.a"&/@99[s.73bPV->CEu__kdhO`@0"iZ7$\!1Gn<dOSXMalNdS?.;3IMl<kH4C^Xt\N1qXX;%NIKN4COC=_"@M8DntrLj`fIcp2ou<T#1U6i:9W2^B[%2`(_-$),6<W8NYmrJ.#1"Xh@d_;W_EJq$BDB3H`0,?QBcSXi;>KhNFp8t"$TR=W@B,kdsT#l658&C=)h3!Io:3=;rH4rat,+@FNP?@Ztqoj[m2r_aReP!H>Z$tQ%n?N`O]'-tX1`3@WD,0^Zj0MDQWJjf.6U!lF;'G+!DO8E$:d,glsjl,.XYlTCqe5InA&Ch'<&CNrd^i:R'AjsMVW+\H?"V=U90PPm(L\;aA*[D-p+TqlM$?oo>:j!6gJ[2d0p:-/+4:o:Motl88O5:2uWVrD;hOcKP.8UOXLVb6Cf3io4XsgBFLD<eIr?mg+!atd!!`23o*q.35c&t+@S:Gg15*t<kTT>&pmf.33o:Fs0A85!;&;:TTYj@"&c_MX1+GQ+f]Tdsm.Z.3!U&K!,>b3=Poo<HnI:e@$1_1H:k_ZXP1Idt0e2t$IQ]QF$*>-jDUY!#+p7VU3I6_jT%Q="%J>\;66AE?Jh72R.n$8Y/iU.rO]T#)HBcV`biN:&ko&L&>KL/R*$*"Sj80EKu#a$;2,$:*tO@!I_OED0BH!*?q!t'5&!Nscba&]:SUj-L:fnpK(/DqXl#Dl:S,^LL=[*l4=(5$f_g))/6[7)dXJV2`SD)uWpbGZ7?K>F/GA<)2Q0HP55l/OK-W7qur+V`XF."G$bg*<m=0LK>lD?=[\)tPNaZjL3$_8G1N6#WZEO96al;%cZdFEmom*\3TgYcd'p,m[mf4<_P&aEf)Q3\OS;l4'G1JGDI*h\]H7+0SEDU&N_/WHO8hhE5+lmLXm<&g2'WS>?4Ek[sfBBf68=crFD['EZ'L,>=e/*Pc.Hk@0P$b'g8Q?=85L?\CRNf@U>,6_Gm\J^a\lP2rW",e_fD3'mG<G_+<pOJpq2'`64L5/C$DK(E6+!_D$Z1'nHAF_TBugE<*';#S`PJJbGtG(Iq<V+5#ZP6(KQ:L(1JfVq5XK+jsQA@!T<8u`(!c3JWZFK#%j6mp&J]i^qSV8/%C?c9)i\Ps@3'kL7Eh$$a2Uh)F[]`n(e7"E7LbOVg2*HjiT\<RL37"k<^Bq994I3b_1MDu.=OLRCi#"3^PPT,@!KB8gRTns%c8:pe1R00Db1H.mRP'`>mJLGi)DFUY>p$k^8AK@WYZ-GH^!-=s\5q["?h*hbrkH<`*odgYGpf^Y^-UER;6nj%"np-#8O3t6I'+4KMPWg>5Bhbs*9S;b=*kbk'8Si^8*hM"4r>'_[kup[mCa&H2$d>mAZ1B"K/Hnh%Gp\7oWS@$^,h!s0l]p10Na(hGOpUWtPg=YME-hKc\!g9.OXS5s.0ln:J[*EtnTT`Y/<1iKE*3jI%LPah#_ZT:qlKkd,1bI*gu'gc)_[*7$9gQKK7JA\/*$C\n+J&V\0#(88$dm/.ai"8U),,o)"J$$M-(mEVFYke)k/#A%oN/qp5`/1*N)-/7-i\SeeSf+^`e->l@#8QTN!'UBHVWB;(5X==rneA3?&"P$IT4l*n.m86\D%SHt`r'fHk\\^?jHXO01sQB%MH<Q-+4n/csdC8*cA!_B1)qT@^P9moJ13*p9J`%VoO2&tKIQn*N5B&J\#3+KuG$CaQF;&*F@Obr'Hhj8J@]gD=-L>C<B>hm!)UVl2bp4j<L?!^L.AjojKK*iD@?q?hc9p4`Q^GW1+I+$fI#I^1<JPn8a?$<!)qfJ4p@S>'K(KH?3#p-THWhKYOa(ia[3)jqUG&H8t#4!odE!9]l?'QOd*SZ3RComAs`rn$L%m6f"VIF16rPaC?[P/u!0@tXR+kd6(1paE<DS;n<XN2a*,G)(Y<N`0^(e!^-FrB_`X9Z7-Oq0F%:J5\qt(>-l_QnUCWl@^H/DR*`':tcZYTQNq*%uLQ&aUmJg[/*U?4,u@3o>NA]XYa\<NSWAl5IKB-'`U4<aEJ,&)++OY=V0:dAl`.JQZe?(`hTV//V0^F+)hZGV'>.e0_W!>XgiqWGi1qH8N(K90snHX9.5B=<>69@9P"H,V'?:EW_=ZU%\"OnQZ#4aX37=S-hq@;BSt+A:I*6sT7U%%/;H6LBK9dBA)!VR@lQ#N[GAh!dDh'W<OK10Rd5./1M3X3'uIu5".sS`dD.\;4+,T!bZ1eoKp>o3Tk)`1iHJ-N1pMa11p6<_EJL'&UGJ'ND#/Ltm@%?Jjq#05)`iUA$gIOQ'DUpB,cL=DDR(HETXms;_or*F2%kRuBQOdmWZ)Ug6u[RghHl4H>I\@GPlRSWDfufRA@X[+@47q?b*"2i)Uo((Rugp1qQdK^Q;ThOLI3pW#<R4lWP?JEe`#D)NGU^GPZ4&9q:C1Z1fBPtIY7DA>T7],N>TPofL+g-I0UFVqoeiJ"*;.Md4^5P@SJt?3['NF`m/f"*>8+O_s@oM,1b4>.9X`o#&Zu-g?>B0)^1SN+mL^Oi7&XLZ3^QJi.8X]Qc*;(+(lbDrD36O1X8@bcaGgL6"1+0%8%.Ybj.<W%^:\_KcDg1X?'7:5):2lF.>G3"+gf2YR['YcgHhAFKF5h[M6VHE46Fu?Z=$K]9sc^FL^YR53(p>Pt9uJ-ldcd(n-E[\D]/\0H)k;"&U<U9bO^?$A\"t5aN"t4d3B:G[[AZn>jMM[T4jgnu0etZg*7,Atr'slZ0Hn.r5]N@jWPK@s9`%;"a@b(h@6T3X\f`^08Yra&dgN9cO\gfF%r-m3f7NH2=&O,qO#D@'IU,OnQG?D6-0>TIiV`QBj@F+`6!U(P`]+O]t;nF#Y%P>)!cdf*u@am+pd$,J:X,CX&P?)UjpG)S]PV/S.=5]af$N(rrU*a\5rEC3N-H^N5jLr@$WMjOf-"TE*X:dR@TbG-kho6U9\,jMUmIFnq(;AEoeU$D$"t1-:7MZFG3A5kH=H8Z@'_+%]d`'X8"FJoK$)TWk\Jm%`>iRHiYH>^*SI5DaREolZ1>WSuDkR<:c6-]InAX`9W&D45IYnE,P*,9b/"eBO8Sqd^uK=oKLc)Lk8:9N'gb$/P6%oBndc2*cgt":upYP+\0T13`ZtrRjacr(g4'0G4<f+?AWA<EC`.UhOdXns'^Y6a81n1rkEii(Kf.[jBg_<1tu^lJAKsmC22T`<FW_SToWgrt45Cr(M&GLgNf9htU[W8f?@i+ZaHcCeI^U5kmUr_ENb%W<u76N?7D@-mg,rdjtqB>KoU[&Qth$0=VX(%`N&l8;%$O0h9SUfcPe1!TiBiYfWnZ1CR905i[,1Rt#;tDa0a7#MIJpk4slui4q<*\EY*_TQq*#r7OVKp^.PX84I^h5j!m7Uis;a2u/1Q9$@!a[LZ_Q@17t\R&[M:;Z\)'Z=PZs'M5VcYSFd$@n__r"eCA=,%2<+.U%+:h+m/=`dS@`!mfRc)&/16O)ETu^Z7=J0L?c9?ljmq"*IHOBL*it%%N.h0h4J3U#(@]GU`1@%HqIt)l)N8JTCR<@OK/\s*=Vpn\O*)2X+eDc]Y;,=0/,.d!^PJS,MEFMMSrPMK/ORjMo3!!0_*50?;`^T^KuL.39'+^cT7.-oW5<lbo14dCXth+*_R.#B7Fq/MrEg"_aKrarOb86V5b3%2r`M`-udOF#5h!>#HXMFqrnCdqL#cU";.B\cn:0g+C'=^J%$$G.l:=)cAbJBo>L6@T3LJ1-jE$2T^Kq)E+uH#1"WkrY5PtfJ6,Qf";ffkM,c?S]A_'$OuE#Rk<dDFj[LWi_5<%L_*r4XHlS^iE?e4k970/lS`H#h3*R,8,EeEMu`H0@Qg/WjJ$kc\Ze.,2/6_X*'srp?(3<pDcGSGg8B^;8DB.1N!pg*/KXuhAEZfeI-]ePj&7(01!e/0*BQ,9pWgZZbiEbjI<E:.f&C.FPHMF\Fp\Q_&G-IjB?dL?T/]YlUW_F4'F]bpcc7Q_%toK_nH2EV+iD:l%1fna5hLFY_dVM6<=&d96Ot$5rA>im:6Q6I8sG20IM>JL_^=I'-Fb,S;=h]JK@kR-$6l45RVF"0[OD]n9*6n:a]2@-8Mrn(,st6<5nl^c1fP2E'%8ZMN2oBH79(c;1^+<+eP*n]9N=La:dYm"9`[YD'#bSb0a(MN3e!,[WE51>e>,N&%tc9<$3G_3j)XH#'&!m]F^jQ.22f9(:e<g4%G6!H7oRD$i8b4:6W(*Cp!H>Mmk/Rbai>6"hc[I7EfBSeH*k'ADJ3G7*(E<C^<=Wfgpnnf.1MF\gCET3Kn25'_<<*SMLk0S#!WMu_R0_Z<>Y9`M`X:Zkn.(2A3XQ6)Cr>/C(4ZZGM2Pl*(,*8i^C8iF_;\3Oh-.HDGroMeFQ^f_DJsDW'<hb+gGCq;$PdAjq*hsoi@LQ0LcdW+[Jtg3b;QQd32251qd?\naZ+P(ulUgYiAp,P`e&P;(m,^(LpNUM76C0,&/u*E7TLSk=^elEJS/L`JCN:K7.;5FOO[9K6A"<NEq9KW8O58$Q;utJX]bJQn$G'bf@mcUt\aL2b^@UWJQKFL/^Fk0<N<LjXGC+J_7sRa`sdUTA?7/[PXk]L+NiZZ.%FL-VA(Gf,)TlqSOh*SJ<<k]2C?mZk["nG@8l`aUAgo`)]Gs:QEq)]XdXZjNq1b'BB@ZMO'*eJt'Y1!KeZRe"p5O$8`5:HnZQCaS&Z!b^#C@3%kcXO'Te/.4?Bs6).PK$`^2j$#jB0(rhH;EW]ftqe.gi5+CTM#@8kIid.G@Z4qs`:4t>LCp-F(NZ]iBC)kAoP"ZEr'1q_R&en=hj=Lb.fZ^]7,a0Ar'#>B=%JO6d9WQa.D,F,rR,*`<WhD_i."@GNHE?!@\;(!+)E=Zl7p@8X#i^juD6;X0V,jP3_Qa[&'>6l_@D&`lJKe(A8+'q?!A#0laH7X5`REUQM4:6n2T6=u'ZYb/XQ23/*_*aZC82c=3l[>5iOb%PM:"c.OMfIJm.J;bJ`+OB#!3c6"K+g*GFic<p#4]P4*g"[O!BJ-Z&5!:%!_8O9FU_o`Er>^Yr7T=Gn;P?qhrrt%Ye\:QK(]I`//bU17,r>BHtYKj>\4:%HQ!3QIN2OH=Uio'LlB&S#D-X1C.SD@OPrT$&/q-YoLDBLb%u^^i'D/j3e]I'%feq0kLMSV4`Zs-3UX]_ZIcnLo'Q/#&cd8#WkZ/(-;Wg]Zh-s6g>2<_7,3]W!rjTU%gVlnnC]7`ql(?X0M+-RY0XJ(=TN7an!_fCsNW2MmE]\JsR,,RPiMdG=f(TTj#FW5U%V^(K=0/`<g\"h:lKb/Z`QY?_C7Ye"C0Z:-l`p/\7_]`@csJ!u9Yk1_do`!D<tITer,=&IDk<7@Y*X@@0K-!RcQf%rrdDf"r@L'Z1!l"jYu+DTOZOPY!Ib>oTGRg<#Hup]CU&-<WJ:#!r*B)0.?/nVE22T)oEUlF\DQ@PFFd8B#k[[T?-FZS<-):Ti5Elgjlh==n^;BXnpTUPHP4GQHa(5nk#d6pW(`Zj8E/\q@3i&>94m!\.2&hYZX"IkJ)!,I[@%a)tb]s$PNOG>SkbJ2&/bQDtjmHL1^40Tt&qd58cS&Ha:W!)kTd&<%GfIt!/`"7#"R*"uETnGe^.q:[M`?8+rY*G(IsU3N+Dbu[-TgLf'[fqBP]7HtO!Th,;V*6(K@G_4"T/,7:#VLA"-Dp4XPQt@I,c/g(:347_R$$uFn@(XJEIi!=+SNa-;U#T@N`ub0J-KEB,D%^QZU"SZoF6(ftiHEW$h8^#ln5sl%)X!&`*:R[HG=Q,^3S]B*4AN#i1_=DVWh.`,B*LV<_2_"rFDG![N1[*P%Y]p`??d>)+J5N2G:YN]bSVIQKPMJRY212/8Re#GbGHuW/1%NR%@:UZaS.W5P+*JYAY>pc`'fKK"+tL)bu(ei*N(mCON`V6b;+\OUg7GqJg1qH(W]S(G-H@DX%Ka`M[Y+>.d5f<'>2lUJ`H-\&I]0l:U5/MeUd!^eWLkgU8d,?<!2JnTP=>=DJ29r*P[)WpLA1J!<b*!)2)Aa*N4QV9",&s4&(EPMYA]P$ZS.L:ahPnE^YC=&Rnd.!Y)'np3Tp6/l\&\<A_W#0SC+JcqrpM$#!3B@L3)BD\W)*%O^Gd7nMA\as:^hg(0XUEVOjnR6r`a&s(1pWA/iPfli\2_7=4@d.?ZT6WZVVA?$3,#%B5V%O*p752W`KSac'//mIXPg)Z'nh\'t?oKJC%As)R0(*f+M?q'fLM"VqQpu74e5gkq%FViG[:FO:r+Fr3rD@WTg(lL$^Uu>Q",]1Tqmq1KH=Kku(En#6UQB0L_;f1Lj9caj^7]1C.d1)&';#Kq57!gBZDY2ro_%$eb8L^Z)USpbH'77K]8`d(/KII/gq7<PoWe_QMrs'D-B*,$3FU:TWL_-MGJtZ:4ZlU9gkm*q2358GinBEd#\K+N#^f#Nd^<,X*TuP1@SNRL^n0@A71/KeTYM#L#Y^:]V&pX\Dq.2D*:`nI4K'_t65Z0"ld6oNGP.!j@D$Zme1<CfdKc"2:L<;jM"#C!l-dhZ1>((#!LP_oVM+O$??;`5"eB4Q[:Ch2Z.tS?LfQ%K@cdX9JWt\[?<\^f]+IrI!YFoiU2;n^"J_;3nmFlZt;5Aj?=u6Kgpl#=c3G^,=!1Ga:[1rX?W0fTuTTDo=g_d*11n=AXI(P@[S&d:d8(A-/!9"6]"PB>GBPE+KX/4k'W11k[rSIj!LhRDe+?KR73Hs8;KMt;G7j@%.iA_l(RYhB:+K-K?9Fi.^OBq,oGr1Tr$A_TM]cB3;g"*]hn=QorHH0DmSfl*KJI[c(333g[&fU0Yg96rFW#uM?TMltA+\o<0:Dc3#U4=4)TAY1mr6gg+0a^a\,W3QrVeYq?Rl!DP,ON#bmIl3lLmSM(3Y<5i"ofnNM3=#OV5BW;-jYN9QmimkJ7N@_TVNK98-/Qtr8@kI_:'9[:;`mW6+.dsgb`te`0c)7CPdBTH93s,BfZa&A@)Q#K%AKBB8d\0NH1IHSEf\b(:J8n0&\dd+sV;(6Li.](`>^b<T&$71RYl:#U^#cO9H"2+\miN%*FSR!i",kdgg3rEY4`eH&9NR$W)1_M5!4:GR%Le0e8#94fGUo$pKA-(VUE/5!&S6qOn60o3]OG)>7[$AkH`TMd`h1,@E44*'o,73lC!MS7isjRHf.7oSMQ;BNF[\6nq*'/JCJm3&Uj\T-cZ0`-'%t+HF#mic>cWED7;1N[fC>L1hVPYYn.o:.0q-Td^^d-/k+8866G3&4*E'^[GLEnAeAf#;>!3174>T*.U@:c6epkdu.RRQ>JE6Z?+#sZ`I_3AHrdDNUZ)O6Pr2Xj'SFIeDk((a`lN$%V>&%994\$RiKW&iDZad??K\YCq?_]&=C&"aho&KENh_'#FagMlGT^n=_@E$lQp<V41a`93Wc#-@_3;]T'k=kgWka6M8_aa!f0sG684;!Fds4e>*Pj:&I_o4kg!C;e^lir\t\DD*&qp"U%72%]m$l,nqb6$7jQ;j6(!Hde_;b3Q;j[j:A%X]2C.Wl8'E3p2BJ[_g?Z[Y;RmeMp64Z"l)*2<RYnAIZuOPhg'#fn53'b$N*YCG_sIslY#kQ7gdu><?^t=L;;C-5[SrYY*lVlo7&:4mf-^g^BlsosZ.'k"jUEP3+D33k'/SIn.gQKm&GhX6k!k]L(,.`g4@%KkUS2DZLZ&RE*8su9_)]K]8M\$-$A'\"YbXR%18](C;V,[!iBj-!U'3(a6P`3(FWK/7RuK8@>e%s[B&s5T@haLh'HLsgg01dFl60N!O/EoBBtm5Pcd*p7XW,0AcB_[P1iMfU<U22a4*PXTf#L@K3IB>[rn]9(e)Im=gH!s#lt&*V's$oMq,YkSMS=,qo93n_n[McVTcf$f]I`!P=kCXDXs88KEO@C,n]FP!dhp!?M^J_Ypu)%;LKIJJ3omB*]:W-RgKgr,lT/[U/)3@D)Ut\Ummkb/pGuulpHn[$R!Z1.8_YEl3s:F=5@A,?7J/?_EZGp0UR1T1S@W6u3^[nI96=3%la)A_f$Qt-L<*HD_['L2;!FP^NnMu)1e)2[P_Y1g1t3cf6P`.+'2eSC8JV]I<i0Pc4'/*Mbj]GrPH$UF`g8:tbjfn*V;1$K83Y?uX1,o2(i]V[H%G1,8pb0l^KBoD)P6BHf6rQOYBn>q%R+enN%EtJc!DmaS?65YqQ,hTbJS70po_#R^:Zf!o\0ECajf1GUKMFb(G=@mA&fuSO&!t4QuTGdb4R8kZb9N*,TH,dQgJbTD#=Y4U(e&"\2L+gTtt:aCeVAapaQAPQe/Y=CRRX17l"6eRsu^+4rK,VSCI6VZ$"Bb?QCGgB1+.r5<&Blmc/5&N7AVAEJ0GUojq)../H>#;M:;@fJVFIj/4]P&Z1]Pq-aW<@'3S$ZZe"Gb=OB^a'iPn;krMSHu4IMB;5pu;2Y_7>:A$k(k#VC24haV7ad9;<(5ZWF]BYa_ATp6Y^<#!Wn%#$Nk8qbX!`^,IQd/E`jO%Fc.L>1%rFN!!tA*0BqDk)AMTd'<fD(cPPj!3'C,>^l%bJ/e$?pg@RZU7e?H<Kl9.Nd-Nr%Q'@sL(ec`l,6uQ>P)I;Qql*Z>Bm5$S.F#XeWR?cqj9'qCZZ]^p?Zl3+e['/#rV]*9iBf:+E6[[[3]LCkVadsp#fj9<tm.AK.K0#7F<NZ<@<&I8>>7"p0(9"B>0Z\RI;9,*qf1A,AL8+o.Mn(,tUlnIZ,dAF(TcSIOCQ>Bt2f*7bF,5]]X^^a,7gP?TmM1TeR\B8Ns*f>P31(83b-\s?kbLd*<>!&\26!nkTFYq(N<K7n^'!fuUHV9TWcn>h!,J6"YqDQ6=BITdPf07.LVT"3U:b$a&FtD:8rtL:T$DD4*H`kd@kCGFLm&^+;Pr1t)Bu1lXkXm5kRTo-bh0Rile]e<+uj?981#0*5<a$Ga2X$7p%FI^$qW=<!,P[:fP:j"\gIX7Rk"qhV6=+M?aG/qXfekPhf2<L]%qd\ZgZp6kftdi$_A@`JsEd1rCeY)fD=$1cDb:aEhW(dAeifmI!Ma[B]@V0o6cIF$oP?(9;75L`ND:![WfEn'n"u24OS`;fiP<-3Ku[cD6cC3;XP<fl8<1jP@O-0ae'&sm`rh2$Xoo.FqcuMGt([?K38+nF1QJQ02)jE?d7-GTujih&Wq4FE*[IS/SL0_#tVOI;.q0&1T1hb&citTS[g0$9^X9!JI\&(bEbT@Gkb=`e29/8f;>:Xj6B87VqK/u_%+<XQ1CabhN>c"mu-k.E'#8<4`Rk;m\*h]8k;,XHMlQP(olg(K4C4$(?.FLWW\8$.Q6PNX^XuKF:FC,G"4TNA!8rcgrKqhcm,^@E1<I&e68!so!OD'd*2k4;fgn7T90\!-<iS:7%%^#:Y[]BBS-jY"OTse&8mS#a=a;CPn%&C@[fGuSC`cE^MEtt6Yj*QRF6[S7j!2TpY6oQ1`d;*#n27Eo4.'1hufcCV,(!"'9rSL5[_63iE*N-&`!Te(aB%D^0fV/I;k?1i(Ic>JF(#UUr]96lq5^&lp>AF5MKWWfR;G;pkp$_F@=15GM*8GAse@*pip>lph(N=D3"d'@a/Ce,%./_hY#*!OiB6D4S"sSHKQlcB4Y-QQ#h\=FHM/1PqobaQ7oc0Fd#XcRa6hgL30AP@6/XmHj<sF.;H1_FC9LSEc`=8V_aRF-?i.oamRX2/5J#gN>j\1EVh(AT*ct=8oArTVsMnan@@/>09+[&>]]&KN];`-*q%llS.*=#nN:7A0!jc.lT'sS44e".6g33^Bm(!EA20`r*J7,8/1r6t)C%GJQUqdB@"IScb!qo"f@kUnXD&R&"K2nm<VRn^is[s'<t,SWT\jgMQ))Pq@h`Di.!IqFZnf9&idXmsB\%3*]o\*?)CN*d^bIPb_:XRBPlp;6(_[PmD*;!U9O>_UOH.,p0Q(Tu;<pW4<7<5]ndh?H7r1KIT$ai)W!4kOn/rj+V2LPmjB;PZ>,SUC1hc08_:"lG'r=.@$?AXE$p_;/_RW1<R.soAM_KU7',3KG!9GI1^ko7kO4rYX:XIaNR3]Fa:2)6qB,XI#*Z([`$3S(S0u7FSYu/`^'HbA1Rqqth2J5%i6Phb\apSD!M(b@6pZaV8[7*78l><9#MM6c4p%\XJ3TnV4F_J(*$fU!'%oKKh=cB2=Kip8)bQ_'Db0%jL7g>T_`$W.jG[R_&GIFkJ22>r]L(.u+W_h0#F\SpXPTWO7;NiXVKH>jn8<BJn1/J8-DZX`GKKpJ(L6lCT>F,?UF>l&MSq]b))_\!9Pi0',PULBj(ilL;A=\8JLkl??aX`$2aSnf/W_*sboDj8H2&*ERJP+?B!'q&"_^J331(Zb]$Ep3@Koao9Eb_\83Y:16I%*N(8<F$C@]V(=@L=X<c^(SeM\n/PSX:i\^UUkB1m8X\W.m!Z3^sf;_A#iXHd#:Di)oJhgB0MBoBV3D7O/R5Ef+&N>>@C;BB'jY^*V?o<Cma%"]hl?MQuGkrhkO)4*V`S9LMG`5Z-ucl0g`f0k2,_^2ODFN7$QQ4tK*R&kAV<K,_lk@>kf2p#^-*Y9^VE"4DB%Y".5MZRCtJPL'*N/(;O1[_nIE[iZ37"Hb*Ff,.;g,a70*'&Ld(R\F>XRQr&(2i"Srbrugbl>^M':M@S?.*nt44tu'Mni4!c.Ni>\MPp=dDVO#L9[[4:"ImVX;($7QJg79_alfmka;NYg>;7)ZS."'qE&`D@_3;7@_X4">\<0*CD4Q_k1%jp%;I3j?2dNk(@O2l/)6gB&NUG1HJ>jB>!p`:)79_4'VO=;Tmu'Z$6+$A/g1+o><(-3o,KC`BZR``LPs\MDI23e:Lrb3ck/G^0=YA`uE8lHsPN$XO+aU=:.\;.!FN.9)i^C;63f!]XML=,Cbu;)$%>PE3Z@[a,=J\WS,m?Vd+/paM%<')P7fbopK`_Hg=ib!*KKfHh57cK2WP*+F,p-JR:>&;QI1%J<KT@1udM\aCia65`U/3$gW8l_hZ&.t-Y4=0qN($^^9l0"9&5*iU=<N,<aGR2J3)7ceo)5uQ^-)0.@>o&N`i?[6a#uJEFG3)trp@>#YY;(`o.219.Rb;40r7;QFs+Yd;,_R$\MD'.MUl[]ELnHl\pNi7;N+f=a[RW%30%"h,0.[\Dj.1P'0`X$R?%fhYT!D<JdY>?a4Tbn>A2amLU%OZkk+9Y1/ds?21nHVKRqq@"*"Q1"ud._ZMHd+4!")\6QEI!!E96n\X1-0&"nAcYH\V"I35%(dS>q@iI5e>WV)$-7RRfE3J%&OF7_YsarPt;i(PP'.EWX8+Io]I#ng#`;SjKL+[o<H_dj'.6(oG-7A+fK-[Ej^JkOm$p;KK4!+QMcGS0,SO5R_]&I[+9O@gj[Ci.qXNBQ.u%iKZ8S^;fsli[@5OAA36"0gdO'u9]Cgj(P1][tJk#K$Y4)MLPcOD(:XS4C^imb[Qm[8U^[dCqUoOaG;,]X2uT_1BLZYGf"BdK]kPMb$Xl!g/\GZNX3=k%O5nN)n7\"3Su[)$(uk*gm,CSWRRifEaMZWV%iO@mL,BK?+.*49c4Jb"3KS1($=g#f+5e$&k^/:S;.+B+:BIr;VHs?t&Q@XE+9^-di/cqQL=<77HL]`f$e#QN7jM.&l@m637'-b]SHaWQ]\iOAm+-Or?5>U(.76g;B+J3Xo8QJ7$"MS(.87\FZ<OI<4GjWbFO>Vlip/2g/)EA!"h$LRBKt6fA-L,X.su]rV=dV5n@`j!a96@.",?*$s83!/1s3mX$+P\&C/O:d(I3gjkrJ!b<abe9deYGhH(SVi4;1>JrK>'V_M,@<"],K;"C4c2N]=RNf-SH#&Ch4N7ng#H>O+T;oIUXC2%+OE?+Q*,b^\n$,.JP*@.=!+qm\Tb:c@L]SCp,(LpF.Z0r=&t4ZRJUh2E!Z0p"9*t)hWRu'lH'JsO18Gd@leXp`ra?Ss7\VUb6@X-to@c1s8='l?Gh.F%m%PF![[/!q647I#Yi;>+")LA'.=S)s[`^t'5a@*p)P[.]U8)t5RO]kU5fa:T:KN`W]%$mu5R2.:]>,OO[LgQB,+<L85H`iTNnjB9RSq#mnKXKN+hYli6KB9!A@hq59lZ!ANt`r)>(gtuQt#VOZ)IDX059:V!\gLuPbZ6,V'KG'nN6-&4#R1`(4r\I@o-RL&:1fH(L]n9(a4hJ9*p+LUcAR7fPL?a\62)7^lIdrJD1]Nm'Z)u8SK=KpV]9Ml8Pt6`=g?D!?#cc-U.Gg+Y[Sc9>P^W.'j=qVV5mGOO[`,/sp"hoUejsp\TQ\D)KS*KeUcE6'+G<Tl)V%)/XO`:*ro4@Sd6J&)%m(dD)!eW*fUE9#QZZltd7]Xn@$iJ2[#bq]%<g`YaE6i6s]?(!/#?)nNli_*^J#.pB#&VVI!3_EQd&CCnftam&bBEq`3<5m_alRE'1ic<5=3.dbHU=D_=3ROF)_-u+u+A>g9lUlI'H++ST"IY12ikaB56^r.X!U"!tR[kcae7fot\'-&$4K=XT]q4/n<\_?nJB4Rs%1/(Ysg_h&W6)C:%O&L::M*tK?\:Jm28F0eQ9K-+g)MAim-s4a+mD'!a(GfeM.&UEnfOCYqU;e2bj&FYtP3JeGZDF<P)dUK#Y/QdD>rj-=7M8";o\5"Oh0f"pqWG)Dj!!K0Ig+;aoHa(NklX_O(5H6J+"QUc-'$]tlid4-?bd1J5/;F#<`-9_6/%qDV[5$_@O8MjeetDfn_9[;Tn7'UF!V8e88N*;"MJ7k4USUL*O]XP:d_F8+PK1q=?-)>JOp"a:KSZYCtp9Ke1(3"ZYMLI%CUFY_*f[GG^ipk"H.8=*B4`V)$Ym4K9.sM:uH(6Ku+92'FhbYTdhR!C6?XbF_a-eNj(.1rAC(!6eH`r&gA@qn2AckF;6)$ML]YkZ$?B@5f%Or0T[.b@bYV!HkN!>Sdn/^$`\<2+o\E+e&Dm6pF1?uQ^@WU@n&F+O6nH))RR<<(0AfI(&ZV2:+i.$:%:D_c[KM)@A^W3c<rHE'PqAaPCkm%`u<sFP*&DC]\AgK%.'a-m&fhoC2d^g=imVmW<V>@ojtMbU+^RXV#bJ;a*dC6$EU"-FTf6hZl?%1S5rfs97`a/Q3hWPUa=64X$Hh3`/71'G&]S24&*'Nj.HTIGk6-R1R!I7.52^>ENAiAi2u;?$OAR*ZS5R-NA;Om.;?&G.?&4be0=0e+%I.m@EfHRdhMo:Gb/C]hL6-'GQj&lBHq499ZIKs*F4`Wd\*ZjF^eXOAA<.0=LZV7hO"'n/o&u&K#jdQ^I(:lQebIF_da2"OT(653s3bA>?$?/;.l&#Llcj8VaF0,?GNGo.=RI<!nehjpssTaG#aX;$FYXDV]niKno/c7k8m1h$:$m;MC2ar%Nt^3JlIB?'^Q^GC?rjhLYP]U.8BW(E1^\P,;Pf/BUkt5Q?+[9'"p"TT@d?$>8=iGP$!H_X"RT";^Q^8>_HfF9nb8\>(g3E;7[qgR0t]dm,2X43#c?d=Dd#WU1?SIb<fhn&ZJ)ABJWJ'W=`@?G7b15d\A`P%*jh])5[JBaKB>YEO.6gHbQ0>VpeTK[(%-<gW!Q`!>ujZMq`J($)U(P@d\^\$475s=enK2&i5cs,RN4qGG+i8`d%2_qWC"73T?Q,&8Ps%SF@5T>kj`<Cc^HU[@j+S._$?)fs+G@6g!b_Q)OB*$[j8*p!*2]QoM>T?(:H<cX&:C\&AR)I7<,Z!I\"h$Hi,7)6Ih;00hN*CWXj==>L5E=KRq:@>Qc$[X)0_dE;i8#fPG5W_Q0>kW.J^.V,!"HNMXQ>2<XY0[LduI^Mn2m3deOT1LQAFrWr;*t6#@mn_7FQ(70K>O_\<<TYo.[`BXH!VM::bHi$pO?6,dKuln'dK[K%+hQfd@cY`MAVpjVWiP9G@\aH9;n@gcSiPmXITeht@GTG8Z;0a23[pGp_?VWi\$q\UL8eYl]8'hOc?SEJai:YB:q0K'pP#Yck*SXr&kj`8HW["=CW_p^(32]aSld3dgF5c^P%YSb,&oRri+>C,jX,JT;%qSB+^Xf\cK0GeajW32qWdAW*_CeR>s=`P2rcNNC1OJJa]qYg@=G$@H(\\/h\qi*Y&;94Uot3f9O;-aeu7P`9"K#/(EF30*'.@TLm(:4;'7h.,0=qt/apnI'L&6hT!)aj8>V]Tem6[I=$<M/i+gc?119COQ*)es:tFcfe&a6:<MI_S2bsc"Z6BL_j*RXSc0[EPh*VD>!u44]C3k)>J6bhU>C?+UbgEcuTupDh1=B,Z'ZWt,2Rs/c/'-(@9>Ra,[=d8ul<=M?=,F(:\?KeR,?4$CNL,l9#1#Y?fX<DC?pQ'.74(.,FJQ^NKJCi[%&IC\C(`iNoTalg2bE'm;-%C-qB/R,>>Fp"Wd7N&_bG)(o$hbE4.<MQjXRB6Y/X#)":[4YTj)]gnXJQ#qI^[)F,!PV2YbRQ,rX+jd@q8!-Um#A-[+s1Ll$-!-0\F(?!XJNQP.5L!e@r-'b;hPB-Ck7:McUGc%\'D?u+?"RHre?I\Fp8,DIccV^9bH]/#Xj<A*+@Cb<63pF,'CCUrDpF1iU4ZCDfUd!'ONk_/nYm*/%^D*nW@4si.b@CDA?.9t"R!,GG.62/TL2\X+HLk+k5cBHaU*\ArK"r'mg.*t^'0d\+P+Dj7FL5)`:D89hi1a'&N`A$f=N:"*2FiPl.nRo]+LY^*=!mEuH_Jh^d?Jt_Gmo$had:,V"mVGML7Bab*ZhZ,A"-+Si$*k:$B5u^>5hSWc%NKQIIpQZJ^n$MJ0EIibK`\jj6U]R[r&`cUk'lX7HJRAr8r93sMMuNHG\,=q^KOJn\;Y@BCLsdB;]8BM>%/d45]T]eQDGtS<%KZAMT=!mH3E\;AV>BY<7sYHDH;X.@Ciqo#g,RbH'jj8E^YTc"r-!dO]g\lKh48`WE6H>HI'*l'Xi*cm4/cS]64t0*CTQ6VPHaZ@TL\r/&ZWMIl3gm9%R[.h_N`:QA?Zo787<ucupCr+bKSccDjlLjC]_IO:EgpU_M<iP#kMPO?#[:T6n7h(tm[jpHYokG!5+58N\Y?4sUN`4cB_!BP#-4$7,r8+M>0R;Cql*@)0Q]#YH$iTGP1Jn@6k;YlJr6RKnB.#?,K)i5C@O0JRk`U*-+t8Pmh8m</QL\I8j8*%$9X@s0/OdbC<%.Vsj]HOUS>@DTOR,6k[k3XQ3\/I9<>jC=s4M."gCBc2f<b@)dQhtdi8/h_^Sgs*2oj=%U`=H_*e(7(0j1j_g,B/&8IGi3Dsf_jMpQuV9s+UWlpd1VN\JHb?h4GXaIoXikGP]oS/CGHE<@V(hrdALtB>N6TB6pJ^9'TB.Hs1D'l[0Kn]-p*(tR]D'm0:JuJ>@H@1qU/[/-H/J\?dEPnEaZ!:I<`R:BO08Pm8G@*f@@\b=M]5;9a7boi4ujR[?W*^#IqJ+:Xh@Yr!X;'%VXQ/;B"j_:b<g**32F:.I_X(h:]]>+Muk2bZ(\j&oB#nif=W1X4@GK<H<=D?FoVr/G@s%R1]j9.rRg[e#i"Ng[S;7@!`inZV!_4)^AK[LBA>IVVn%n8MrG?0"?^qL`2@5=VYUm@XWP5A$$,J7$66?ZQ'oiZ>0,S*7lDshDM2]\s8gq10knJ5ZblsKhgJ1Et$$nW2cVRZhEdVa)WEoE@(0i"Yu#q]\qc4@oS9BOf-:LKsQeVO,Ehn66l^s`]"YT/n`aoH3j.Rhda\Pj<t0;*Pj(XTs/Wkp2"o/$3@FI"OTXlZP6=@6rJH;!<%LjSjuKn_MkfJJ"1'45]I&u(N+ca\;pqtEMKe!0N9mNTJHm?D6;IM5i;o[RL#jR.>UMsPUNMg@.Udd8E(q@;A#>H",nK:@kp@QDB<GZ0-gPcU-3(Xeom!86_h.m.GU3;<=i?BKh8iu07<ALSaNGtgkmOJ#"YqaG82tF,LXr+gcTr,-G0sG=<P],gO_cY%o6YAB'=5$'dW&W"jQo?CF7?sN8ZWB>K9+$-(0\J:mrK%*bj>!c-6ru<60#nWN<Ue==PkXWYa<eHB3.=qflP.Bk7j;ViKqCe^=sXl:_[?PZ:>kfnPDJ6.10?f4m\;4I>bo*,*=H"6g1`!^n1?h''iL5cUplWtS)^TKj]-n:8bCfB\$E(bq.<@/r1Dk#/3s8Wq5,0bXmK3.=uZ9S\mJR%*i@#RPsQfF-%-_<*^2;B::,5Qjpm844Hq#_MWIBqcq<7!s2RZG//mm?"ioL`bK=ciLpJ1pdfY]-_6pK2b5IV$e_+1(b]4i<kpT>kETo0<&$/&5>DM+V5c6askDY_@^`0:Q0kd$/I"R6M\c='b0+gO[,oM.4BPo<JZ$R6&691d=V#Y6M;0R>[;O?TZjJPh*t[&+kn&)n&sG/nd*+;hSVg:mYA6MO?"I5h1_X8/g3-(2Ln']13!eZ:SKOd?IQ:#le6s'h^DWY_pJH-F?&#;;le!(5FiBq+4bH>/[N=%=;Pb@TT\sf>J+)0/l?S--4t=Ba5JqGC-*FIKH3P2UNm9b22]=q-/%B:ceH;^VU"b2Y0?AV_EB$>kk!as@cY6J4k[Fk9EpUHlWqCj:()Z8MG3@_-Eqs2<!3dF<<Wu[+;b)@h/HPWN"Md]is&?%1e@\O7[Y*l"6atH,FGdB"t.I'L')*?@)PpEVaV0V(m-"A%2q!3ZYg6`=kIP28-tL_r&`9JE+sP,blP66-.<C7.q"tm-a2GUO0*j!jm%#q4nZ?oL,^%_7`8b-J`G;Lol,69:U%JY@%j7uP]BhJ;roJH"$d_PB$T:p]/3^Z3/3Me?'0K@hZEo+5GQ_(<S2PLoMq]CBd>JFch_V`];t2*W9WC%@h`Z#J`rl!j\4!sJ5LDeP4si1T0/JXie1i#(eo?E(C+B>H)#LL%/uJF)BFp*14?56j53!jgISW'Vp;!q>o5:jd=1*S%J[X*#E2rOKV]2//gD]=@?"R+6?=(VEIs6@($F^MKcbjkd==M?8Kgqr'.QR:4-)S:3t+tO<8?ZWi'macLI_^^N1*FocS5$p#Ef&iLXQSOkQ:lq</G<-=HOep<2EKQZK)JhRg_lOgdL79+)AK:>C8*eb:R'j#SQYpNI_A#+fH$r4T70c<dg,i8N%,mT#JgsJq/fr_E9csP?;;-U#_A#PT=2n!KVAsprK]_:lmBL7&kVZfdLkV6`1tjmu5aPg'n:a'>P+Yr9TN#1+E(Gk+@)LWBMj85m(Z75g!">3)2Tfcd#lf-`m)C*W=LD9#=tU='.uM=>AJG.d#rhIPNd]hYrd0V2WktL`;L=.&7JlG!F8iX$eE'e(Em!)_7Q.Vl[mX35&461\WcaI9.%sJuX^@]54OJQ$$nre%XVYer*sJ$^B#Y%>/=B9G0^k6(nuSBHpQpQu/B&]Li``Yn;[=\LEp^lL'pKb:nkh.&U=W^1R8kekjrMWh=92US>b4lChpc!>*)IUO-`B=Bq&.NU<*ZiSGjJ:=]G&+S0k%g5i/ZccbdD_>-E>H95*1%%&$A.J.X[^^\Tpd"e;kmQ,6;BJcoDiXt4uk<<j^5VroNbn*j<U!V5g!s^Z#o@.N'Om=.>0-NC_.:2(uNj5Ni!'`*>QJkKr^uJii^q9r;(u'WcLl_q4G[VtMb#"Qe;+9-W6)^Ot4;+iC)ad%*;-plnRcauJ9Y3=l#<bu]21T_3G4>F*o/Q@]aRO?5T`-LeO=&/,;4*hd->'O2a!9^2nN240)!K>=QJq>g?6H&.55@M7!`5X3Le9?XOo0Cj_D6rY]`uE.*?Vs"5V`sK,m>lDRCg)%coib)N\K<cSW$Z[![l'I8I6Z+Jlmb;c&gpWAl7[t<&CkmMi%=&^#C44)=BnQ"Z0Zq4eQg,$t"#@rkFlk-9V2!gr&+:)7E3B9([!Bq+%kqE(.P6Ch6:qgjQa'dK:08ViUrZ3Y8;ZBEh%*L^>4?L'^8"5d[NPHHJ$.6D'q&`:f!7a]3P6J11e2DqdD@7S-c,JruFnVPso3OJS7N(-Xr.^coi&&)Z"YGSk^VJsfHt6@Y/u=Sa^0(U%BQi+W1C8G7i5[cBY5pQJ<++5*cs@']PuFH9Fq1`?H]O_JJ9Wa]A[V[-`4%VO#SflC/IKGl\q#RFdH@LdKpUa3DD2pA/nE93q/)o3mr(%,;f4V5L4-5/V5kHY?AZ1dC3.@7`)\eh_:W5&P43I8T%"*&mFARst9@f-NhSjE\J&9I3X-.>s/Gkb[.#V9N8jPD,3PP<jA+U.q%9RPRapi4.$JT_^?-!"dC&/8T$Y,XX7XRA(+7[i72_GIE-:H.I!9F'GiP5i4(8fqF`@#3_ihqm3=o+?).QYFRH[?/7!,tC]V#pKjG6QTB#.JS$JU5EXd'Bat^jFop2I]')2N*M;Lh(TomA`sr`lbqQE0\Tcse`uuo_k_^eapsTIHf;jf_.nQ"E:f%;2:&.[=uN:%6BHpFT7D`r#]2:q"]Z(b*bcC50Y.bseh/&%Wcn10r;ureJ"g2$s,9DFIcK9W*Tr:;9GI^s'7QJ:MGa_8pPF$u):1CDD2dLl#(i^[LitJY5Y.5N[6`O\<<eCZ,V1;-IR83eCr>Y$J!c^?+QjB5nE_"YL)Rt$!(jhpZ\0L^PIGt%f2+[i>V68qU`*p48<bPh:S.XJXN8bq!/+&u"X=UP0GLi*#nj1/5;*LQ0LkH$be]PT#Tt;t![OQ_CbO4&jpm"KA&#:a@KH*B%Ur4*,/4qV666\`>PYpO3.PZRkYL1fI6c4*cjTW1#jOct$tVHK+S&QX,q+ADe:b)::$45WO.=lp,PeVf<&@$5F7eKK1_i.2BH85[_T<Y?l-.BU7lWjDK\<;[Ahf3X&jg"E+VI=48kPXc9fNi=Ta6qs&k3.<+dAE4L4k4'#=1U#"M+ef_kRS?,Fes-!`e`DiXp^!O$eFY30Zr@:%g!*8O&Cd`L\:d2HT*mV%c7]-;R&1nhR"=La-9Y&hP'W)Q(s%,83ELk4&UDS'ZS4]Lb+0U<1=G^<8k<@J^XN$_k:s+2F"k9Xp@HVWaiXl@J@da`\d\joSV'Sl`%ZR]B*RoOZhnMO4hrl_Oe^%M0c6V$nf*n*\5CGi5k=3%f]Wm-4n1ng*'ZC?)MdZT3PFa\MAs:TS*_:`e>AUp>[b;"fa/*0:n#TIn7c9dKgESW=oj%oe'$S$"TsN>W;amr8jhfdSS)l-R0.2Y`Z-,[:mt*`g3YNl5pGD0q9Hr_30%YAReQ@tZgjr\`'rgeEU1=q"T?PS!?iFW7dL#!*d+dp8BdE6_9)>T*CI_@UnqJtd^I`"24#,oDI^-mASha74L1HElU[QE="l6NPrm6t[$+4+VsHEdZP(I1\N<;%=_Xg%!QtT5;F-IQE#G(;9B8;BR%1N+_'*`i$r;,S<kN!h*ie\(2FMQbX[7]ZcC[Se'NO2`X[ORH>M$frL]H`WkJ?K+rk*G46bAS;g'0+P_-R`IB#l=pN]!@,O"tp%gaG"n*]0"CB=k!X`+A-3h;j2@W%eo#OuebGb`7OJ3sicfb)s%<\@;l$Y>Rg%)+32:qu.](ot(k]_bVi/lrG3=RjHW**>/qgRF0p4&_6^Ure2cgL=QB@6^NGPjRQ^]#.`So=#jp9Sdgli3$rqS.ftr][OXs%i7`J%OkA5Q1Pphu3*En,IlEjm@P`J)1"3`T6bsJ=+=ecNp!EH@lo]Q&8:cHi(%XU0YO$1];tE5u@2`$!6uP=oH`t^LY"?;%]qZ'm#31gu($ZAn-qjKe._?^+oY,Nj&,-i!2eJY_P(Hl9kG9:QXfh0l_pHQjA^KICu'tjPNaX0sc]0rZMK09%G:AgT:`]BHQaEO>!&PAJ^<c)EFr#2m>,H`qdJP`P_Ulr&RRl"p,Bf4"'Pp[PMZk.#:B]MM)FSTgW*96E1=`fni'FjPE<%%fX8WG$&10(g5auBoc,KXEjk#GH5XdFq3%7;/8U"TQ9n_o3qRsaYhp[DCnh=T\DBPV*mdp:ESP3s"oeLXT*[F=5)E.Wf3gq9(u=P[m^fD_.>k%jf93>Xc,5uc9-2I(78hkZrU4LV,f)TOXi:<?hnrDE=u#[?`t8Mir(Cq'ob+En9.:+KH#b9J$_I!RcX!b/U4o,]Z+fSF@'UAs"Esp$K.L6;RLV>_1LtR,gHql<MjTd!J8Z>/7@#(WHd?l4T)J2+5i#Q<`g@R#ir)f7#,1Ogiea8f^4"F(R,3Ligi*Hg]&jeV1MCmM$rYQo%87\H9$a:ZHS+D>VEU;TaD'j$:'K3JH;bdRL2H:PTL:u%n%fA8PC99R+L]T4(8i*,GTCDgI@(SM2b/5<)D,NbN__CK!ED6H1PJDmK@;_ql4X8,oNV8Y+XBJZB=RX*ALL6?>G7fD=L$oUB5$E>TMW?g4]Yu<B4#Xs*W*LS%W6GU8Ja,[`WJX$"K[(D"MLS7<D5p]$<e>:".Q9G_[X3dA.^&74OF2bMCu@j#(kDoJ?7'nnZVeH+UYADjMf&2#B]!bq0:ip2F]o[!t2jB&#Cde=M@6WYYu6KLOBJdR-Q5GV_'Q#l.n19YNBqa0r@o[rt<kBfK;9B\7%o\ZHRrBgK)`80WZA^siE(ZP$YKH2)W=m%VLQaSS+[n'Jl&S]d$f98'6cA5Uh\M*U;9=\`e&o]<g1_Iipb&_7uHRW%mC_VfJ_"=G0cmfIU:SAg&aUU41$<+BK?pGK?HXF6,XC-k#r8W/=5<6>^O3V]4MT!JI[!JSp"S*T4Olm,1<![M08#UrnQQ38C#2VdFJQ,pfu&Re)#@_ETbrjh?iYZKa[*FAF`lihf8'gP1+6H#g9AMb7ag$\K[N&df_Igdh+`?=Q&Zo=^>Ok[QIZP6YrAqLWX$4mCg`p-.r,"[a^o)IEn)CW7l*T6#GR-[EB'@Id'+c)g?!i_uU5P\-j2uC3'7EK[K*bpJU*"3?^5]X(HhL\i=*/UWFYVmTX#hCGfO4M_Pm!`^T1LWZh-+Vh19+oiho\'1,jb!\@]h7IO.*dTOHfRDjnEJQp?9,a%cBm)]F'I[(<=;OeF'K!G8d-I\1JAs.7.!T[V[8N7oR5hZTB'c;2:J8HQ2.D,qKI#]ruH(/BJO=ER5Ca1O1$5gG_\^-F='!O)lt1On$cd=^@uO(s(6b1ruo2*k^WA?pU0`:5O2a:dm*Y!*-8FK3H^j%`R?an4S)fq)9b5iMdbHWAVe=oH+i)*MT-6^*<n]`)sq5TKE's!8>ce-&QpmNJ,
+# ===>END WOOF<===
--- a/wscript Mon Jul 30 14:48:56 2007 +0100
+++ b/wscript Wed Sep 05 18:35:39 2007 +0100
@@ -2,12 +2,13 @@
import sys
import shlex
import shutil
+import types
+import optparse
+import os.path
import Params
import Object
import pproc as subprocess
-import optparse
-import os.path
Params.g_autoconfig = 1
@@ -36,7 +37,7 @@
opt.add_option('-d', '--debug-level',
action='callback',
- type=str, dest='debug_level', default='debug',
+ type="string", dest='debug_level', default='debug',
help=('Specify the debug level, does nothing if CFLAGS is set'
' in the environment. [Allowed Values: debug, optimized].'
' WARNING: this option only has effect '
@@ -135,14 +136,33 @@
conf.sub_config('src')
+def create_ns3_program(bld, name, dependencies=('simulator',)):
+ program = bld.create_obj('cpp', 'program')
+ program.name = name
+ program.target = program.name
+ program.uselib_local = 'ns3'
+ return program
+
+
def build(bld):
+ print "Entering directory `%s/build'" % Params.g_build.m_curdirnode.abspath()
+ Params.g_cwd_launch = Params.g_build.m_curdirnode.abspath()
+
+ bld.create_ns3_program = types.MethodType(create_ns3_program, bld)
+
variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT']
variant_env = bld.env_of_name(variant_name)
bld.m_allenvs['default'] = variant_env # switch to the active variant
if Params.g_options.shell:
run_shell()
- return
+ raise SystemExit(0)
+
+ if Params.g_options.doxygen:
+ doxygen()
+ raise SystemExit(0)
+
+ check_shell()
if Params.g_options.doxygen:
doxygen()
@@ -152,6 +172,11 @@
bld.add_subdirs('src')
bld.add_subdirs('samples utils examples')
+ ## Create a single ns3 library containing all modules
+ lib = bld.create_obj('cpp', 'shlib')
+ lib.name = 'ns3'
+ lib.target = 'ns3'
+ lib.add_objects = list(bld.env_of_name('default')['NS3_MODULES'])
def shutdown():
#import UnitTest
@@ -193,34 +218,32 @@
raise ValueError("program '%s' not found; available programs are: %r"
% (program_name, found_programs))
-def _run_argv(argv):
+def _run_argv(argv, os_env=None):
env = Params.g_build.env_of_name('default')
if sys.platform == 'linux2':
pathvar = 'LD_LIBRARY_PATH'
- pathsep = ':'
elif sys.platform == 'darwin':
pathvar = 'DYLD_LIBRARY_PATH'
- pathsep = ':'
elif sys.platform == 'win32':
pathvar = 'PATH'
- pathsep = ';'
elif sys.platform == 'cygwin':
pathvar = 'PATH'
- pathsep = ':'
else:
Params.warning(("Don't know how to configure "
"dynamic library path for the platform '%s'") % (sys.platform,))
pathvar = None
- pathsep = None
- os_env = dict(os.environ)
+ proc_env = dict(os.environ)
+ if os_env is not None:
+ proc_env.update(os_env)
+
if pathvar is not None:
- if pathvar in os_env:
- os_env[pathvar] = pathsep.join([os_env[pathvar]] + list(env['NS3_MODULE_PATH']))
+ if pathvar in proc_env:
+ proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']) + [proc_env[pathvar]])
else:
- os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH']))
+ proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']))
- retval = subprocess.Popen(argv, env=os_env).wait()
+ retval = subprocess.Popen(argv, env=proc_env).wait()
if retval:
Params.fatal("Command %s exited with code %i" % (argv, retval))
@@ -274,13 +297,33 @@
return retval
+def check_shell():
+ if 'NS3_MODULE_PATH' not in os.environ:
+ return
+ env = Params.g_build.env_of_name('default')
+ correct_modpath = os.pathsep.join(env['NS3_MODULE_PATH'])
+ found_modpath = os.environ['NS3_MODULE_PATH']
+ if found_modpath != correct_modpath:
+ msg = ("Detected shell (waf --shell) with incorrect configuration\n"
+ "=========================================================\n"
+ "Possible reasons for this problem:\n"
+ " 1. You switched to another ns-3 tree from inside this shell\n"
+ " 2. You switched ns-3 debug level (waf configure --debug)\n"
+ " 3. You modified the list of built ns-3 modules\n"
+ "You should correct this situation before running any program. Possible solutions:\n"
+ " 1. Exit this shell, and start a new one\n"
+ " 2. Run a new nested shell")
+ Params.fatal(msg)
+
def run_shell():
if sys.platform == 'win32':
shell = os.environ.get("COMSPEC", "cmd.exe")
else:
shell = os.environ.get("SHELL", "/bin/sh")
- _run_argv([shell])
+
+ env = Params.g_build.env_of_name('default')
+ _run_argv([shell], {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])})
def doxygen():