diff --git a/.hgignore b/.hgignore index 340172127..95df8a6af 100644 --- a/.hgignore +++ b/.hgignore @@ -11,3 +11,19 @@ ^doc/introspected-doxygen\.h$ .*\.py[co]$ \.pcap$ +^doc/manual/manual/ +doc/manual/manual.aux +doc/manual/manual.cp +doc/manual/manual.fn +doc/manual/manual.html +doc/manual/manual.ky +doc/manual/manual.log +doc/manual/manual.pdf +doc/manual/manual.pg +doc/manual/manual.toc +doc/manual/manual.tp +doc/manual/manual.vr +^doc/manual/figures/.*eps +^doc/manual/figures/.*pdf +^doc/manual/figures/.*png +^bindings/python/pybindgen/ diff --git a/.hgtags b/.hgtags index 4d11c256c..a719c20b7 100644 --- a/.hgtags +++ b/.hgtags @@ -1,15 +1,24 @@ -56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1 -7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2 -0dc81e76166c56aaae64da48b673b62155943aad packet-history-working -38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3 -5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4 -08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5 -267e2ebc28e4e4ae2f579e1cfc29902acade0c34 buffer-working-before-breaking -606df29888e7573b825fc891a002f0757166b616 release ns-3.0.6 -36472385a1cc7c44d34fb7a5951b930010f4e8d2 release ns-3.0.7 -560a5091e0e6ded47d269e2f2dee780f13950a63 release ns-3.0.8 -4db981a0d9eb135e3e1c07765cff8d66f7a55cca release ns-3.0.9 -b5bf2588cde2f1273b1095cc5c83a0c272e55370 release ns-3.0.10 -ee5e1da76ecc52337f097cd90ebb50a3d49ec541 release-3.0.11 -b17f2928291eec5bf5b1c59a4a5fd583f704ac40 release ns-3.0.12 -79dba133b5f8a2d6f6f678a22e8519bc155e6a4e release ns-3.0.13 +56928998e05c9c11f5f3aefe79be8d2843e0db88 ns-3.0.1 +7ac5a4b0969b255c4824c926c2b37ef450136ce9 ns-3.0.2 +38099dd26e9467b8f49f8632f22789858149a6e7 ns-3.0.3 +5701e60bf01a8ac1308945e69001e0cc07948faf ns-3.0.4 +08046b6aef37932507696a2f2f427b42d693781e ns-3.0.5 +606df29888e7573b825fc891a002f0757166b616 ns-3.0.6 +36472385a1cc7c44d34fb7a5951b930010f4e8d2 ns-3.0.7 +560a5091e0e6ded47d269e2f2dee780f13950a63 ns-3.0.8 +4db981a0d9eb135e3e1c07765cff8d66f7a55cca ns-3.0.9 +b5bf2588cde2f1273b1095cc5c83a0c272e55370 ns-3.0.10 +ee5e1da76ecc52337f097cd90ebb50a3d49ec541 ns-3.0.11 +b17f2928291eec5bf5b1c59a4a5fd583f704ac40 ns-3.0.12 +79dba133b5f8a2d6f6f678a22e8519bc155e6a4e ns-3.0.13 +8869a79a391f49d0c787f0558cc9329b4e7ee40e ns-3.1-RC1 +951296e9a277e14113a0d3ba86a9688b222569ae ns-3.1-RC2 +ea16c44eb90db579c83d3434fc8a960be506a7f5 ns-3.1-RC3 +42504fb1f7be7817b8be513cdcd3d9bc8f3660e8 ns-3.1 +5768685f9fdba9fbf2e9561a840f085142c73575 ns-3.1 +dfd634417b8d1896d981b6f44d8f71030611596a ns-3.2-RC1 +319eb29611b18998abbad01548825643a8017bcb ns-3.2-RC2 +d783a951f8f5e64b33bc518f0415f76cae1ca6f3 ns-3.2-RC2-bis +fa1c7b813873cfa251be7d1b7cea38373fe82fa1 ns-3.2-RC3 +68218c266a844f9fbda34a0ffddb1ae2adebd4b0 ns-3.2-RC4 +2ecac911b3ec40d73ab8301471bea6d9ba5b9885 ns-3.2 diff --git a/AUTHORS b/AUTHORS index 4f0da03d7..3566e5207 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -Raj Bhattarcharjea (raj.b@gatech.edu) +Raj Bhattacharjea (raj.b@gatech.edu) Gustavo Carneiro (gjc@inescporto.pt, gjcarneiro@gmail.com) Craig Dowell (craigdo@ee.washington.edu) Tom Henderson (tomhend@u.washington.edu) @@ -8,3 +8,5 @@ Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca) Federico Maguolo (maguolof@dei.unipd.it) George F. Riley (riley@ece.gatech.edu) Guillaume Vu-Brugier (gvubrugier@gmail.com) +Florian Westphal (fw@strlen.de) + diff --git a/CHANGES.html b/CHANGES.html new file mode 100644 index 000000000..38326fe84 --- /dev/null +++ b/CHANGES.html @@ -0,0 +1,296 @@ + + + + + ns-3 Change Log + + + +

+ns-3: API and model change history

+ +

+ns-3 is an evolving system and there will be API or behavioral changes +from time to time. Users who try to use scripts or models across +versions of ns-3 may encounter problems at compile time, run time, or +may see the simulation output change.

+

+We have adopted the development policy that we are going to try to ease +the impact of these changes on users by documenting these changes in a +single place (this file), and not by providing a temporary or permanent +backward-compatibility software layer.

+

+The goal is that users who encounter a problem when trying to use older +code with newer code should be able to consult this file to find +guidance as to how to fix the problem. For instance, if a method name +or signature has changed, it should be stated what the new replacement +name is.

+

+Note that users who upgrade the simulator across versions, or who work +directly out of the development tree, may find that simulation output +changes even when the compilation doesn't break, such as when a +simulator default value is changed. Therefore, it is good practice for +_anyone_ using code across multiple ns-3 releases to consult this file, +as well as the RELEASE_NOTES, to understand what has changed over time. +

+

+This file is a best-effort approach to solving this issue; we will do +our best but can guarantee that there will be things that fall through +the cracks, unfortunately. If you, as a user, can suggest improvements +to this file based on your experience, please contribute a patch or drop +us a note on ns-developers mailing list.

+ +
+

changes from ns-3.1 to ns-3.2

+ +

new API:

+ +

new API in existing classes:

+ +

changes to existing API:

+ +

changed behavior:

+ + + + diff --git a/README b/README index 67dd6c899..72a88fb44 100644 --- a/README +++ b/README @@ -72,8 +72,8 @@ use of these ns-3 libraries. To build the set of default libraries and the example programs included in this package, you need to use the -tool 'waf'. Detailed information on how to install -and use waf is included in the file doc/build.txt +tool 'waf'. Detailed information on how use waf is +included in the file doc/build.txt However, the real quick and dirty way to get started is to type the command "./waf" the the directory which contains @@ -85,6 +85,7 @@ following set of platforms: - linux x86 gcc 4.2, 4.1, and, 3.4.6. - linux x86_64 gcc 4.1.3, 4.2.1, 3.4.6 - MacOS X ppc and x86 + - mingw gcc 3.4.5 (debug only) - cygwin gcc 3.4.4 (debug only) The current codebase is expected to fail to build on @@ -92,10 +93,15 @@ the following platforms: - gcc 3.3 and earlier - optimized builds on gcc 3.4.4 and 3.4.5 - optimized builds on linux x86 gcc 4.0 + - msvc -Other platforms may or may not work: we welcome -patches to improve the portability of the code to these -other platforms. +The following optional features are known to not work on +these platforms: + - mingw: nsc, realtime scheduler + - cygwin: python bindings, nsc + +Other platforms may or may not work: we welcome patches to +improve the portability of the code to these other platforms. 4) Running ns-3 --------------- diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 572bc13d7..54ce46205 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -3,8 +3,145 @@ This file contains ns-3 release notes (most recent releases first). -Release 3.0.13 (2008/06/02) +All of the ns-3 documentation is accessible from the ns-3 website: +http://www.nsnam.org +including tutorials: +http://www.nsnam.org/tutorials.html + +Release 3.2 (pending) +===================== + +Availability +------------ +This release is immediately available from: +http://www.nsnam.org/releases/ns-3.2.tar.bz2 + +Supported platforms +------------------- +ns-3.2 has been tested on the following platforms: + - linux x86 gcc 4.2, 4.1, and, 3.4.6. + - linux x86_64 gcc 4.3.2, 4.2.3, 4.2.1, 4.1.3, 3.4.6 + - MacOS X ppc and x86 + - cygwin gcc 3.4.4 (debug only) + +Not all ns-3 options are available on all platforms; consult the +wiki for more information: +http://www.nsnam.org/wiki/index.php/Installation + +New user-visible features +------------------------- + a) Learning bridge (IEEE 802.1D) + It is now possible to bridge together multiple layer 2 devices to + create larger layer 2 networks. The Wifi and Csma models support + this new mode of operation. (contributed by Gustavo Carneiro) + + b) Python bindings + It is now possible to write simulation scripts in python using our + python bindings (contributed by Gustavo Carneiro). + + c) Real-time simulator + It is now possible to run simulations synchronized on the real-world + wall-clock time (contributed by Craig Dowell). + + d) Network Simulation Cradle + It is now possible to use the Network Simulation Cradle + (http://www.wand.net.nz/~stj2/nsc/) in ns-3 and run simulations + using various versions of kernel TCP network stacks. (contributed + by Florian Westphal as part of his Google Summer of Code work) + + e) A statistics framework + Joseph Kopena contributed a statistics framework which can be used + keep track of simulation data in persistent storage across multiple + runs (database and ascii file backends are available). + More information on the wiki: + http://www.nsnam.org/wiki/index.php/Statistical_Framework_for_Network_Simulation + +API changes from ns-3.1 +----------------------- +API changes for this release are documented in the file CHANGES.html + +Known issues +------------ +ns-3 build is known to fail on the following platforms: + - gcc 3.3 and earlier + - optimized builds on gcc 3.4.4 and 3.4.5 + - optimized builds on linux x86 gcc 4.0.x + - optimized builds on Ubuntu 8.10 alpha 5 x86 gcc4.3.2 + - MinGW + +The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes +in preparation of the merge of the IPv6 API and implementation. + +Future releases +--------------- +Our next release, which is expected to happen in 2 to 4 months from now, will +feature the merging of some of our projects currently in development: IPv6, +emulation, and synchronous posix sockets. + +Release 3.1 (2008/06/30) ======================== + +The first ns-3 stable release +----------------------------- + +This release is immediately available from: +http://www.nsnam.org/releases/ns-3.1.tar.bz2 + +We dedicate this initial ns-3 release to our late contributor and friend, +Federico Maguolo. + +What is ns-3 ? +-------------- + +ns-3 is a new discrete-event network simulator designed for supporting network +research and education. ns-3 features a solid, well documented C++ core and +models for TCP/IP (IPv4), several link types including WiFi, and mobility +models. + +ns-3 is an open source project released under the GNU GPLv2 license which +allows anyone to use ns-3 without having to pay any license fee or royalties. +ns-3 is actively seeking new contributors to extend the range of supported +models and/or to maintain existing models. + +Where to get more information about ns-3 +---------------------------------------- + +All the ns-3 documentation, is accessible from the ns-3 website: +http://www.nsnam.org + +Including, tutorials: +http://www.nsnam.org/tutorials.html + +Supported platforms +------------------- + +ns-3 is regularly tested on the following platforms: + - linux x86 gcc 4.2, 4.1, and, 3.4.6. + - linux x86_64 gcc 4.1.3, 4.2.1, 3.4.6 + - MacOS X ppc and x86 + - cygwin gcc 3.4.4 (debug only) + +Known issues +------------ + +ns-3 is known to fail on the following platforms: + - gcc 3.3 and earlier + - optimized builds on gcc 3.4.4 and 3.4.5 + - optimized builds on linux x86 gcc 4.0.x + +The IPv4 API defined in src/node/ipv4.h is expected to undergo major changes +in preparation of the merge of the IPv6 API and implementation. + +Future releases +--------------- + +Our next release, which is expected to happen in 2 to 4 months from now, will +feature the merging of some of our projects currently in development: python +scripting, IPv6, emulation, a statistics framework and synchronous posix +sockets. + +Release 3.0.13 (2008/06/02) +=========================== - point to point links generate ppp pcap traces - point to point links support asymmetrical data rates. - generate doxygen documentation for all attributes and trace sources @@ -24,7 +161,7 @@ called Simulator::Stop (time), and takes a relative time, instead of absolute. Release 3.0.12 (2008/04/07) -======================== +=========================== - Add Attribute support to the TypeId metadata system and add attribute support to all in-tree models - Add a mid-level helper API to build simulation topologies @@ -37,7 +174,7 @@ in the 802.11 model (Federico Maguolo). - TCP delayed acknowledgements and multitasking server Release 3.0.11 (2008/02/15) -======================== +=========================== - Initial port of GTNetS TCP implementation (initial version that does not support multitasking or delayed acknowledgments yet, but supports a reliable stream service) @@ -47,13 +184,13 @@ metadata system - tutorial updates Release 3.0.10 (2008/01/15) -======================== +=========================== - Add tutorial document content; - Valgrind option for "waf" tool; - Doxygen organization changes. Release 3.0.9 (2007/12/15) -======================== +========================== - A 802.11 model ported from Yans. This model supports: * a rather extensive PHY model * log-distance and friis propagation model @@ -67,26 +204,26 @@ Release 3.0.9 (2007/12/15) - many bugs fixed Release 3.0.8 (2007/11/15) -======================== +========================== - A simple error model - Source files for ns-3 tutorial Release 3.0.7 (2007/10/15) -======================== +========================== - OLSR routing protocol - A timer class - Additional mobility models (random waypoint, random 2D walk) - A mobility visualization tool Release 3.0.6 (2007/09/15) -======================== +========================== - Static multicast IPv4 routing - Logging overhaul (NS_LOG macros) - Refactoring of tracing subsystem - Tutorial document started Release 3.0.5 (2007/08/15) -======================== +========================== - Refactoring to support win32-based unix environments (Cygwin, mingw) - "Packet socket" for allowing applications to access NetDevices directly @@ -97,7 +234,7 @@ Release 3.0.5 (2007/08/15) - Global unicast centralized routing Release 3.0.4 (2007/07/15) -======================== +========================== - Enable waf as the default build system. - Per-packet metadata: a system to track which headers and trailers @@ -105,7 +242,7 @@ Release 3.0.4 (2007/07/15) - Simplifications to point-to-point devices and channel Release 3.0.3 (2007/06/15) -======================== +========================== - Enable Waf for release tarballs: users can now build ns-3 with the "waf" tool. See doc/build-waf.txt. @@ -118,7 +255,7 @@ Release 3.0.3 (2007/06/15) - Many small API cleanups Release 3.0.2 (2007/05/18) -======================== +========================== - Implement a new memory management infrastructure based on reference counting and smart pointers (the latter being @@ -130,7 +267,7 @@ Release 3.0.2 (2007/05/18) - Add support for a BSD-style socket API for user applications Release 3.0.1 (2007/03/31) -======================== +========================== - First public release; not yet pre-alpha. diff --git a/VERSION b/VERSION index eea30e595..1b8ef0972 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.13 +3-dev diff --git a/bindings/python/callbacks_list.py b/bindings/python/callbacks_list.py new file mode 100644 index 000000000..d26a26a6d --- /dev/null +++ b/bindings/python/callbacks_list.py @@ -0,0 +1,11 @@ +callback_classes = [ + ['void', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], + ['void', 'ns3::Ptr', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], + ['void', 'ns3::Ptr', 'unsigned int', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], + ['void', 'ns3::Ptr', 'ns3::Address const&', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], + ['bool', 'ns3::Ptr', 'ns3::Address const&', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'], + ['void', 'ns3::Ptr', 'ns3::Mac48Address', 'ns3::Mac48Address', 'ns3::empty', 'ns3::empty', 'ns3::empty'], + ['bool', 'ns3::Ptr', 'ns3::Ptr', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType'], + ['bool', 'ns3::Ptr', 'ns3::Ptr', 'unsigned short', 'ns3::Address const&', 'ns3::empty', 'ns3::empty'], + ['void', 'ns3::Ptr', 'ns3::Ptr', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType'], +] diff --git a/bindings/python/my_extra_api_definitions.py b/bindings/python/my_extra_api_definitions.py new file mode 100644 index 000000000..e8afeec5c --- /dev/null +++ b/bindings/python/my_extra_api_definitions.py @@ -0,0 +1,13 @@ +from pybindgen import Module, FileCodeSink, write_preamble, param, retval + +def register_types(module): + module.add_class('MyClass') + +def register_methods(root_module): + MyClass = root_module['MyClass'] + MyClass.add_constructor([], visibility='public') + MyClass.add_constructor([param('double', 's'), param('double', 'l'), param('double', 'mean')], visibility='public') + +def register_functions(module): + module.add_function('SomeFunction', 'int', [param('int', 'xpto')]) + diff --git a/bindings/python/ns3/__init__.py b/bindings/python/ns3/__init__.py new file mode 100644 index 000000000..943a01575 --- /dev/null +++ b/bindings/python/ns3/__init__.py @@ -0,0 +1,4 @@ + +from _ns3 import * + + diff --git a/bindings/python/ns3_module_bridge.py b/bindings/python/ns3_module_bridge.py new file mode 100644 index 000000000..8790cf43f --- /dev/null +++ b/bindings/python/ns3_module_bridge.py @@ -0,0 +1,267 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## bridge-channel.h: ns3::BridgeChannel [class] + module.add_class('BridgeChannel', parent=root_module['ns3::Channel']) + ## bridge-net-device.h: ns3::BridgeNetDevice [class] + module.add_class('BridgeNetDevice', parent=root_module['ns3::NetDevice']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3BridgeChannel_methods(root_module, root_module['ns3::BridgeChannel']) + register_Ns3BridgeNetDevice_methods(root_module, root_module['ns3::BridgeNetDevice']) + return + +def register_Ns3BridgeChannel_methods(root_module, cls): + ## bridge-channel.h: ns3::BridgeChannel::BridgeChannel(ns3::BridgeChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::BridgeChannel const &', 'arg0')]) + ## bridge-channel.h: static ns3::TypeId ns3::BridgeChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## bridge-channel.h: ns3::BridgeChannel::BridgeChannel() [constructor] + cls.add_constructor([]) + ## bridge-channel.h: void ns3::BridgeChannel::AddChannel(ns3::Ptr bridgedChannel) [member function] + cls.add_method('AddChannel', + 'void', + [param('ns3::Ptr< ns3::Channel >', 'bridgedChannel')]) + ## bridge-channel.h: uint32_t ns3::BridgeChannel::GetNDevices() const [member function] + cls.add_method('GetNDevices', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## bridge-channel.h: ns3::Ptr ns3::BridgeChannel::GetDevice(uint32_t i) const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_const=True, is_virtual=True) + return + +def register_Ns3BridgeNetDevice_methods(root_module, cls): + ## bridge-net-device.h: ns3::BridgeNetDevice::BridgeNetDevice(ns3::BridgeNetDevice const & arg0) [copy constructor] + cls.add_constructor([param('ns3::BridgeNetDevice const &', 'arg0')]) + ## bridge-net-device.h: static ns3::TypeId ns3::BridgeNetDevice::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## bridge-net-device.h: ns3::BridgeNetDevice::BridgeNetDevice() [constructor] + cls.add_constructor([]) + ## bridge-net-device.h: void ns3::BridgeNetDevice::AddBridgePort(ns3::Ptr bridgePort) [member function] + cls.add_method('AddBridgePort', + 'void', + [param('ns3::Ptr< ns3::NetDevice >', 'bridgePort')]) + ## bridge-net-device.h: void ns3::BridgeNetDevice::SetName(std::string const name) [member function] + cls.add_method('SetName', + 'void', + [param('std::string const', 'name')], + is_virtual=True) + ## bridge-net-device.h: std::string ns3::BridgeNetDevice::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: void ns3::BridgeNetDevice::SetIfIndex(uint32_t const index) [member function] + cls.add_method('SetIfIndex', + 'void', + [param('uint32_t const', 'index')], + is_virtual=True) + ## bridge-net-device.h: uint32_t ns3::BridgeNetDevice::GetIfIndex() const [member function] + cls.add_method('GetIfIndex', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: ns3::Ptr ns3::BridgeNetDevice::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::Channel >', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: ns3::Address ns3::BridgeNetDevice::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::SetMtu(uint16_t const mtu) [member function] + cls.add_method('SetMtu', + 'bool', + [param('uint16_t const', 'mtu')], + is_virtual=True) + ## bridge-net-device.h: uint16_t ns3::BridgeNetDevice::GetMtu() const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::IsLinkUp() const [member function] + cls.add_method('IsLinkUp', + 'bool', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: void ns3::BridgeNetDevice::SetLinkChangeCallback(ns3::Callback callback) [member function] + cls.add_method('SetLinkChangeCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: ns3::Address ns3::BridgeNetDevice::GetBroadcast() const [member function] + cls.add_method('GetBroadcast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: ns3::Address ns3::BridgeNetDevice::GetMulticast() const [member function] + cls.add_method('GetMulticast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: ns3::Address ns3::BridgeNetDevice::MakeMulticastAddress(ns3::Ipv4Address multicastGroup) const [member function] + cls.add_method('MakeMulticastAddress', + 'ns3::Address', + [param('ns3::Ipv4Address', 'multicastGroup')], + is_const=True, is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::IsPointToPoint() const [member function] + cls.add_method('IsPointToPoint', + 'bool', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::Send(ns3::Ptr packet, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('Send', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::SendFrom(ns3::Ptr packet, ns3::Address const & source, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('SendFrom', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'source'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## bridge-net-device.h: ns3::Ptr ns3::BridgeNetDevice::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: void ns3::BridgeNetDevice::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::NeedsArp() const [member function] + cls.add_method('NeedsArp', + 'bool', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: void ns3::BridgeNetDevice::SetReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::empty, ns3::empty> cb) [member function] + cls.add_method('SetReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::empty, ns3::empty >', 'cb')], + is_virtual=True) + ## bridge-net-device.h: void ns3::BridgeNetDevice::SetPromiscReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> cb) [member function] + cls.add_method('SetPromiscReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'cb')], + is_virtual=True) + ## bridge-net-device.h: bool ns3::BridgeNetDevice::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## bridge-net-device.h: void ns3::BridgeNetDevice::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## bridge-net-device.h: void ns3::BridgeNetDevice::ReceiveFromDevice(ns3::Ptr device, ns3::Ptr packet, uint16_t protocol, ns3::Address const & source, ns3::Address const & destination, ns3::NetDevice::PacketType packetType) [member function] + cls.add_method('ReceiveFromDevice', + 'void', + [param('ns3::Ptr< ns3::NetDevice >', 'device'), param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint16_t', 'protocol'), param('ns3::Address const &', 'source'), param('ns3::Address const &', 'destination'), param('ns3::NetDevice::PacketType', 'packetType')], + visibility='protected') + ## bridge-net-device.h: void ns3::BridgeNetDevice::ForwardUnicast(ns3::Ptr incomingPort, ns3::Ptr packet, uint16_t protocol, ns3::Mac48Address src, ns3::Mac48Address dst) [member function] + cls.add_method('ForwardUnicast', + 'void', + [param('ns3::Ptr< ns3::NetDevice >', 'incomingPort'), param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint16_t', 'protocol'), param('ns3::Mac48Address', 'src'), param('ns3::Mac48Address', 'dst')], + visibility='protected') + ## bridge-net-device.h: void ns3::BridgeNetDevice::ForwardBroadcast(ns3::Ptr incomingPort, ns3::Ptr packet, uint16_t protocol, ns3::Mac48Address src, ns3::Mac48Address dst) [member function] + cls.add_method('ForwardBroadcast', + 'void', + [param('ns3::Ptr< ns3::NetDevice >', 'incomingPort'), param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint16_t', 'protocol'), param('ns3::Mac48Address', 'src'), param('ns3::Mac48Address', 'dst')], + visibility='protected') + ## bridge-net-device.h: void ns3::BridgeNetDevice::Learn(ns3::Mac48Address source, ns3::Ptr port) [member function] + cls.add_method('Learn', + 'void', + [param('ns3::Mac48Address', 'source'), param('ns3::Ptr< ns3::NetDevice >', 'port')], + visibility='protected') + ## bridge-net-device.h: ns3::Ptr ns3::BridgeNetDevice::GetLearnedState(ns3::Mac48Address source) [member function] + cls.add_method('GetLearnedState', + 'ns3::Ptr< ns3::NetDevice >', + [param('ns3::Mac48Address', 'source')], + visibility='protected') + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_common.py b/bindings/python/ns3_module_common.py new file mode 100644 index 000000000..e4d4aff67 --- /dev/null +++ b/bindings/python/ns3_module_common.py @@ -0,0 +1,1138 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## error-model.h: ns3::ErrorUnit [enumeration] + module.add_enum('ErrorUnit', ['EU_BIT', 'EU_BYTE', 'EU_PKT']) + ## buffer.h: ns3::Buffer [class] + module.add_class('Buffer') + ## buffer.h: ns3::Buffer::Iterator [class] + module.add_class('Iterator', outer_class=root_module['ns3::Buffer']) + ## data-rate.h: ns3::DataRate [class] + module.add_class('DataRate') + ## packet.h: ns3::Packet [class] + module.add_class('Packet', memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount')) + ## packet-metadata.h: ns3::PacketMetadata [class] + module.add_class('PacketMetadata') + ## packet-metadata.h: ns3::PacketMetadata::Item [struct] + module.add_class('Item', outer_class=root_module['ns3::PacketMetadata']) + ## packet-metadata.h: ns3::PacketMetadata::Item [enumeration] + module.add_enum('', ['PAYLOAD', 'HEADER', 'TRAILER'], outer_class=root_module['ns3::PacketMetadata::Item']) + ## packet-metadata.h: ns3::PacketMetadata::ItemIterator [class] + module.add_class('ItemIterator', outer_class=root_module['ns3::PacketMetadata']) + ## tag.h: ns3::Tag [class] + module.add_class('Tag', parent=root_module['ns3::ObjectBase']) + ## tag-buffer.h: ns3::TagBuffer [class] + module.add_class('TagBuffer') + ## packet.h: ns3::TagIterator [class] + module.add_class('TagIterator') + ## packet.h: ns3::TagIterator::Item [class] + module.add_class('Item', outer_class=root_module['ns3::TagIterator']) + ## tag-list.h: ns3::TagList [class] + module.add_class('TagList') + ## tag-list.h: ns3::TagList::Iterator [class] + module.add_class('Iterator', outer_class=root_module['ns3::TagList']) + ## tag-list.h: ns3::TagList::Iterator::Item [struct] + module.add_class('Item', outer_class=root_module['ns3::TagList::Iterator']) + ## chunk.h: ns3::Chunk [class] + module.add_class('Chunk', parent=root_module['ns3::ObjectBase']) + ## data-rate.h: ns3::DataRateChecker [class] + module.add_class('DataRateChecker', parent=root_module['ns3::AttributeChecker']) + ## data-rate.h: ns3::DataRateValue [class] + module.add_class('DataRateValue', parent=root_module['ns3::AttributeValue']) + ## header.h: ns3::Header [class] + module.add_class('Header', parent=root_module['ns3::Chunk']) + ## pcap-writer.h: ns3::PcapWriter [class] + module.add_class('PcapWriter', parent=root_module['ns3::RefCountBase']) + ## trailer.h: ns3::Trailer [class] + module.add_class('Trailer', parent=root_module['ns3::Chunk']) + ## error-model.h: ns3::ErrorModel [class] + module.add_class('ErrorModel', parent=root_module['ns3::Object']) + ## error-model.h: ns3::ListErrorModel [class] + module.add_class('ListErrorModel', parent=root_module['ns3::ErrorModel']) + ## error-model.h: ns3::RateErrorModel [class] + module.add_class('RateErrorModel', parent=root_module['ns3::ErrorModel']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3Buffer_methods(root_module, root_module['ns3::Buffer']) + register_Ns3BufferIterator_methods(root_module, root_module['ns3::Buffer::Iterator']) + register_Ns3DataRate_methods(root_module, root_module['ns3::DataRate']) + register_Ns3Packet_methods(root_module, root_module['ns3::Packet']) + register_Ns3PacketMetadata_methods(root_module, root_module['ns3::PacketMetadata']) + register_Ns3PacketMetadataItem_methods(root_module, root_module['ns3::PacketMetadata::Item']) + register_Ns3PacketMetadataItemIterator_methods(root_module, root_module['ns3::PacketMetadata::ItemIterator']) + register_Ns3Tag_methods(root_module, root_module['ns3::Tag']) + register_Ns3TagBuffer_methods(root_module, root_module['ns3::TagBuffer']) + register_Ns3TagIterator_methods(root_module, root_module['ns3::TagIterator']) + register_Ns3TagIteratorItem_methods(root_module, root_module['ns3::TagIterator::Item']) + register_Ns3TagList_methods(root_module, root_module['ns3::TagList']) + register_Ns3TagListIterator_methods(root_module, root_module['ns3::TagList::Iterator']) + register_Ns3TagListIteratorItem_methods(root_module, root_module['ns3::TagList::Iterator::Item']) + register_Ns3Chunk_methods(root_module, root_module['ns3::Chunk']) + register_Ns3DataRateChecker_methods(root_module, root_module['ns3::DataRateChecker']) + register_Ns3DataRateValue_methods(root_module, root_module['ns3::DataRateValue']) + register_Ns3Header_methods(root_module, root_module['ns3::Header']) + register_Ns3PcapWriter_methods(root_module, root_module['ns3::PcapWriter']) + register_Ns3Trailer_methods(root_module, root_module['ns3::Trailer']) + register_Ns3ErrorModel_methods(root_module, root_module['ns3::ErrorModel']) + register_Ns3ListErrorModel_methods(root_module, root_module['ns3::ListErrorModel']) + register_Ns3RateErrorModel_methods(root_module, root_module['ns3::RateErrorModel']) + return + +def register_Ns3Buffer_methods(root_module, cls): + ## buffer.h: uint32_t ns3::Buffer::GetSize() const [member function] + cls.add_method('GetSize', + 'uint32_t', + [], + is_const=True) + ## buffer.h: uint8_t const * ns3::Buffer::PeekData() const [member function] + cls.add_method('PeekData', + 'uint8_t const *', + [], + is_const=True) + ## buffer.h: bool ns3::Buffer::AddAtStart(uint32_t start) [member function] + cls.add_method('AddAtStart', + 'bool', + [param('uint32_t', 'start')]) + ## buffer.h: bool ns3::Buffer::AddAtEnd(uint32_t end) [member function] + cls.add_method('AddAtEnd', + 'bool', + [param('uint32_t', 'end')]) + ## buffer.h: void ns3::Buffer::AddAtEnd(ns3::Buffer const & o) [member function] + cls.add_method('AddAtEnd', + 'void', + [param('ns3::Buffer const &', 'o')]) + ## buffer.h: void ns3::Buffer::RemoveAtStart(uint32_t start) [member function] + cls.add_method('RemoveAtStart', + 'void', + [param('uint32_t', 'start')]) + ## buffer.h: void ns3::Buffer::RemoveAtEnd(uint32_t end) [member function] + cls.add_method('RemoveAtEnd', + 'void', + [param('uint32_t', 'end')]) + ## buffer.h: ns3::Buffer ns3::Buffer::CreateFragment(uint32_t start, uint32_t length) const [member function] + cls.add_method('CreateFragment', + 'ns3::Buffer', + [param('uint32_t', 'start'), param('uint32_t', 'length')], + is_const=True) + ## buffer.h: ns3::Buffer::Iterator ns3::Buffer::Begin() const [member function] + cls.add_method('Begin', + 'ns3::Buffer::Iterator', + [], + is_const=True) + ## buffer.h: ns3::Buffer::Iterator ns3::Buffer::End() const [member function] + cls.add_method('End', + 'ns3::Buffer::Iterator', + [], + is_const=True) + ## buffer.h: ns3::Buffer ns3::Buffer::CreateFullCopy() const [member function] + cls.add_method('CreateFullCopy', + 'ns3::Buffer', + [], + is_const=True) + ## buffer.h: int32_t ns3::Buffer::GetCurrentStartOffset() const [member function] + cls.add_method('GetCurrentStartOffset', + 'int32_t', + [], + is_const=True) + ## buffer.h: int32_t ns3::Buffer::GetCurrentEndOffset() const [member function] + cls.add_method('GetCurrentEndOffset', + 'int32_t', + [], + is_const=True) + ## buffer.h: ns3::Buffer::Buffer(ns3::Buffer const & o) [copy constructor] + cls.add_constructor([param('ns3::Buffer const &', 'o')]) + ## buffer.h: ns3::Buffer::Buffer() [constructor] + cls.add_constructor([]) + ## buffer.h: ns3::Buffer::Buffer(uint32_t dataSize) [constructor] + cls.add_constructor([param('uint32_t', 'dataSize')]) + return + +def register_Ns3BufferIterator_methods(root_module, cls): + ## buffer.h: ns3::Buffer::Iterator::Iterator(ns3::Buffer::Iterator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Buffer::Iterator const &', 'arg0')]) + ## buffer.h: ns3::Buffer::Iterator::Iterator() [constructor] + cls.add_constructor([]) + ## buffer.h: void ns3::Buffer::Iterator::Next() [member function] + cls.add_method('Next', + 'void', + []) + ## buffer.h: void ns3::Buffer::Iterator::Prev() [member function] + cls.add_method('Prev', + 'void', + []) + ## buffer.h: void ns3::Buffer::Iterator::Next(uint32_t delta) [member function] + cls.add_method('Next', + 'void', + [param('uint32_t', 'delta')]) + ## buffer.h: void ns3::Buffer::Iterator::Prev(uint32_t delta) [member function] + cls.add_method('Prev', + 'void', + [param('uint32_t', 'delta')]) + ## buffer.h: uint32_t ns3::Buffer::Iterator::GetDistanceFrom(ns3::Buffer::Iterator const & o) const [member function] + cls.add_method('GetDistanceFrom', + 'uint32_t', + [param('ns3::Buffer::Iterator const &', 'o')], + is_const=True) + ## buffer.h: bool ns3::Buffer::Iterator::IsEnd() const [member function] + cls.add_method('IsEnd', + 'bool', + [], + is_const=True) + ## buffer.h: bool ns3::Buffer::Iterator::IsStart() const [member function] + cls.add_method('IsStart', + 'bool', + [], + is_const=True) + ## buffer.h: void ns3::Buffer::Iterator::WriteU8(uint8_t data) [member function] + cls.add_method('WriteU8', + 'void', + [param('uint8_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteU8(uint8_t data, uint32_t len) [member function] + cls.add_method('WriteU8', + 'void', + [param('uint8_t', 'data'), param('uint32_t', 'len')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteU16(uint16_t data) [member function] + cls.add_method('WriteU16', + 'void', + [param('uint16_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteU32(uint32_t data) [member function] + cls.add_method('WriteU32', + 'void', + [param('uint32_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteU64(uint64_t data) [member function] + cls.add_method('WriteU64', + 'void', + [param('uint64_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteHtolsbU16(uint16_t data) [member function] + cls.add_method('WriteHtolsbU16', + 'void', + [param('uint16_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteHtolsbU32(uint32_t data) [member function] + cls.add_method('WriteHtolsbU32', + 'void', + [param('uint32_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteHtolsbU64(uint64_t data) [member function] + cls.add_method('WriteHtolsbU64', + 'void', + [param('uint64_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteHtonU16(uint16_t data) [member function] + cls.add_method('WriteHtonU16', + 'void', + [param('uint16_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteHtonU32(uint32_t data) [member function] + cls.add_method('WriteHtonU32', + 'void', + [param('uint32_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::WriteHtonU64(uint64_t data) [member function] + cls.add_method('WriteHtonU64', + 'void', + [param('uint64_t', 'data')]) + ## buffer.h: void ns3::Buffer::Iterator::Write(uint8_t const * buffer, uint32_t size) [member function] + cls.add_method('Write', + 'void', + [param('uint8_t const *', 'buffer'), param('uint32_t', 'size')]) + ## buffer.h: void ns3::Buffer::Iterator::Write(ns3::Buffer::Iterator start, ns3::Buffer::Iterator end) [member function] + cls.add_method('Write', + 'void', + [param('ns3::Buffer::Iterator', 'start'), param('ns3::Buffer::Iterator', 'end')]) + ## buffer.h: uint8_t ns3::Buffer::Iterator::ReadU8() [member function] + cls.add_method('ReadU8', + 'uint8_t', + []) + ## buffer.h: uint16_t ns3::Buffer::Iterator::ReadU16() [member function] + cls.add_method('ReadU16', + 'uint16_t', + []) + ## buffer.h: uint32_t ns3::Buffer::Iterator::ReadU32() [member function] + cls.add_method('ReadU32', + 'uint32_t', + []) + ## buffer.h: uint64_t ns3::Buffer::Iterator::ReadU64() [member function] + cls.add_method('ReadU64', + 'uint64_t', + []) + ## buffer.h: uint16_t ns3::Buffer::Iterator::ReadNtohU16() [member function] + cls.add_method('ReadNtohU16', + 'uint16_t', + []) + ## buffer.h: uint32_t ns3::Buffer::Iterator::ReadNtohU32() [member function] + cls.add_method('ReadNtohU32', + 'uint32_t', + []) + ## buffer.h: uint64_t ns3::Buffer::Iterator::ReadNtohU64() [member function] + cls.add_method('ReadNtohU64', + 'uint64_t', + []) + ## buffer.h: uint16_t ns3::Buffer::Iterator::ReadLsbtohU16() [member function] + cls.add_method('ReadLsbtohU16', + 'uint16_t', + []) + ## buffer.h: uint32_t ns3::Buffer::Iterator::ReadLsbtohU32() [member function] + cls.add_method('ReadLsbtohU32', + 'uint32_t', + []) + ## buffer.h: uint64_t ns3::Buffer::Iterator::ReadLsbtohU64() [member function] + cls.add_method('ReadLsbtohU64', + 'uint64_t', + []) + ## buffer.h: void ns3::Buffer::Iterator::Read(uint8_t * buffer, uint32_t size) [member function] + cls.add_method('Read', + 'void', + [param('uint8_t *', 'buffer'), param('uint32_t', 'size')]) + ## buffer.h: uint16_t ns3::Buffer::Iterator::CalculateIpChecksum(uint16_t size) [member function] + cls.add_method('CalculateIpChecksum', + 'uint16_t', + [param('uint16_t', 'size')]) + ## buffer.h: uint16_t ns3::Buffer::Iterator::CalculateIpChecksum(uint16_t size, uint32_t initialChecksum) [member function] + cls.add_method('CalculateIpChecksum', + 'uint16_t', + [param('uint16_t', 'size'), param('uint32_t', 'initialChecksum')]) + ## buffer.h: uint32_t ns3::Buffer::Iterator::GetSize() const [member function] + cls.add_method('GetSize', + 'uint32_t', + [], + is_const=True) + return + +def register_Ns3DataRate_methods(root_module, cls): + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('!=') + cls.add_binary_comparison_operator('<') + cls.add_binary_comparison_operator('<=') + cls.add_binary_comparison_operator('==') + cls.add_binary_comparison_operator('>') + cls.add_binary_comparison_operator('>=') + ## data-rate.h: ns3::DataRate::DataRate(ns3::DataRate const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DataRate const &', 'arg0')]) + ## data-rate.h: ns3::DataRate::DataRate() [constructor] + cls.add_constructor([]) + ## data-rate.h: ns3::DataRate::DataRate(uint64_t bps) [constructor] + cls.add_constructor([param('uint64_t', 'bps')]) + ## data-rate.h: ns3::DataRate::DataRate(std::string rate) [constructor] + cls.add_constructor([param('std::string', 'rate')]) + ## data-rate.h: double ns3::DataRate::CalculateTxTime(uint32_t bytes) const [member function] + cls.add_method('CalculateTxTime', + 'double', + [param('uint32_t', 'bytes')], + is_const=True) + ## data-rate.h: uint64_t ns3::DataRate::GetBitRate() const [member function] + cls.add_method('GetBitRate', + 'uint64_t', + [], + is_const=True) + return + +def register_Ns3Packet_methods(root_module, cls): + cls.add_output_stream_operator() + ## packet.h: ns3::Packet::Packet() [constructor] + cls.add_constructor([]) + ## packet.h: ns3::Packet::Packet(ns3::Packet const & o) [copy constructor] + cls.add_constructor([param('ns3::Packet const &', 'o')]) + ## packet.h: ns3::Packet::Packet(uint32_t size) [constructor] + cls.add_constructor([param('uint32_t', 'size')]) + ## packet.h: ns3::Packet::Packet(uint8_t const * buffer, uint32_t size) [constructor] + cls.add_constructor([param('uint8_t const *', 'buffer'), param('uint32_t', 'size')]) + ## packet.h: void ns3::Packet::AddAtEnd(ns3::Ptr packet) [member function] + cls.add_method('AddAtEnd', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet')]) + ## packet.h: void ns3::Packet::AddHeader(ns3::Header const & header) [member function] + cls.add_method('AddHeader', + 'void', + [param('ns3::Header const &', 'header')]) + ## packet.h: void ns3::Packet::AddPaddingAtEnd(uint32_t size) [member function] + cls.add_method('AddPaddingAtEnd', + 'void', + [param('uint32_t', 'size')]) + ## packet.h: void ns3::Packet::AddTag(ns3::Tag const & tag) const [member function] + cls.add_method('AddTag', + 'void', + [param('ns3::Tag const &', 'tag')], + is_const=True) + ## packet.h: void ns3::Packet::AddTrailer(ns3::Trailer const & trailer) [member function] + cls.add_method('AddTrailer', + 'void', + [param('ns3::Trailer const &', 'trailer')]) + ## packet.h: ns3::PacketMetadata::ItemIterator ns3::Packet::BeginItem() const [member function] + cls.add_method('BeginItem', + 'ns3::PacketMetadata::ItemIterator', + [], + is_const=True) + ## packet.h: ns3::Ptr ns3::Packet::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::Packet >', + [], + is_const=True) + ## packet.h: uint32_t ns3::Packet::CopyData(uint8_t * buffer, uint32_t size) const [member function] + cls.add_method('CopyData', + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint32_t', 'size')], + is_const=True) + ## packet.h: ns3::Ptr ns3::Packet::CreateFragment(uint32_t start, uint32_t length) const [member function] + cls.add_method('CreateFragment', + 'ns3::Ptr< ns3::Packet >', + [param('uint32_t', 'start'), param('uint32_t', 'length')], + is_const=True) + ## packet.h: void ns3::Packet::Deserialize(ns3::Buffer buffer) [member function] + cls.add_method('Deserialize', + 'void', + [param('ns3::Buffer', 'buffer')]) + ## packet.h: static void ns3::Packet::EnableChecking() [member function] + cls.add_method('EnableChecking', + 'void', + [], + is_static=True) + ## packet.h: static void ns3::Packet::EnableMetadata() [member function] + cls.add_method('EnableMetadata', + 'void', + [], + is_static=True, deprecated=True) + ## packet.h: static void ns3::Packet::EnablePrinting() [member function] + cls.add_method('EnablePrinting', + 'void', + [], + is_static=True) + ## packet.h: bool ns3::Packet::FindFirstMatchingTag(ns3::Tag & tag) const [member function] + cls.add_method('FindFirstMatchingTag', + 'bool', + [param('ns3::Tag &', 'tag')], + is_const=True) + ## packet.h: uint32_t ns3::Packet::GetSize() const [member function] + cls.add_method('GetSize', + 'uint32_t', + [], + is_const=True) + ## packet.h: ns3::TagIterator ns3::Packet::GetTagIterator() const [member function] + cls.add_method('GetTagIterator', + 'ns3::TagIterator', + [], + is_const=True) + ## packet.h: uint32_t ns3::Packet::GetUid() const [member function] + cls.add_method('GetUid', + 'uint32_t', + [], + is_const=True) + ## packet.h: uint8_t const * ns3::Packet::PeekData() const [member function] + cls.add_method('PeekData', + 'uint8_t const *', + [], + is_const=True) + ## packet.h: uint32_t ns3::Packet::PeekHeader(ns3::Header & header) const [member function] + cls.add_method('PeekHeader', + 'uint32_t', + [param('ns3::Header &', 'header')], + is_const=True) + ## packet.h: uint32_t ns3::Packet::PeekTrailer(ns3::Trailer & trailer) [member function] + cls.add_method('PeekTrailer', + 'uint32_t', + [param('ns3::Trailer &', 'trailer')]) + ## packet.h: void ns3::Packet::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## packet.h: void ns3::Packet::PrintTags(std::ostream & os) const [member function] + cls.add_method('PrintTags', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## packet.h: void ns3::Packet::RemoveAllTags() [member function] + cls.add_method('RemoveAllTags', + 'void', + []) + ## packet.h: void ns3::Packet::RemoveAtEnd(uint32_t size) [member function] + cls.add_method('RemoveAtEnd', + 'void', + [param('uint32_t', 'size')]) + ## packet.h: void ns3::Packet::RemoveAtStart(uint32_t size) [member function] + cls.add_method('RemoveAtStart', + 'void', + [param('uint32_t', 'size')]) + ## packet.h: uint32_t ns3::Packet::RemoveHeader(ns3::Header & header) [member function] + cls.add_method('RemoveHeader', + 'uint32_t', + [param('ns3::Header &', 'header')]) + ## packet.h: uint32_t ns3::Packet::RemoveTrailer(ns3::Trailer & trailer) [member function] + cls.add_method('RemoveTrailer', + 'uint32_t', + [param('ns3::Trailer &', 'trailer')]) + ## packet.h: ns3::Buffer ns3::Packet::Serialize() const [member function] + cls.add_method('Serialize', + 'ns3::Buffer', + [], + is_const=True) + return + +def register_Ns3PacketMetadata_methods(root_module, cls): + ## packet-metadata.h: static void ns3::PacketMetadata::Enable() [member function] + cls.add_method('Enable', + 'void', + [], + is_static=True) + ## packet-metadata.h: static void ns3::PacketMetadata::EnableChecking() [member function] + cls.add_method('EnableChecking', + 'void', + [], + is_static=True) + ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(uint32_t uid, uint32_t size) [constructor] + cls.add_constructor([param('uint32_t', 'uid'), param('uint32_t', 'size')]) + ## packet-metadata.h: ns3::PacketMetadata::PacketMetadata(ns3::PacketMetadata const & o) [copy constructor] + cls.add_constructor([param('ns3::PacketMetadata const &', 'o')]) + ## packet-metadata.h: void ns3::PacketMetadata::AddHeader(ns3::Header const & header, uint32_t size) [member function] + cls.add_method('AddHeader', + 'void', + [param('ns3::Header const &', 'header'), param('uint32_t', 'size')]) + ## packet-metadata.h: void ns3::PacketMetadata::RemoveHeader(ns3::Header const & header, uint32_t size) [member function] + cls.add_method('RemoveHeader', + 'void', + [param('ns3::Header const &', 'header'), param('uint32_t', 'size')]) + ## packet-metadata.h: void ns3::PacketMetadata::AddTrailer(ns3::Trailer const & trailer, uint32_t size) [member function] + cls.add_method('AddTrailer', + 'void', + [param('ns3::Trailer const &', 'trailer'), param('uint32_t', 'size')]) + ## packet-metadata.h: void ns3::PacketMetadata::RemoveTrailer(ns3::Trailer const & trailer, uint32_t size) [member function] + cls.add_method('RemoveTrailer', + 'void', + [param('ns3::Trailer const &', 'trailer'), param('uint32_t', 'size')]) + ## packet-metadata.h: ns3::PacketMetadata ns3::PacketMetadata::CreateFragment(uint32_t start, uint32_t end) const [member function] + cls.add_method('CreateFragment', + 'ns3::PacketMetadata', + [param('uint32_t', 'start'), param('uint32_t', 'end')], + is_const=True) + ## packet-metadata.h: void ns3::PacketMetadata::AddAtEnd(ns3::PacketMetadata const & o) [member function] + cls.add_method('AddAtEnd', + 'void', + [param('ns3::PacketMetadata const &', 'o')]) + ## packet-metadata.h: void ns3::PacketMetadata::AddPaddingAtEnd(uint32_t end) [member function] + cls.add_method('AddPaddingAtEnd', + 'void', + [param('uint32_t', 'end')]) + ## packet-metadata.h: void ns3::PacketMetadata::RemoveAtStart(uint32_t start) [member function] + cls.add_method('RemoveAtStart', + 'void', + [param('uint32_t', 'start')]) + ## packet-metadata.h: void ns3::PacketMetadata::RemoveAtEnd(uint32_t end) [member function] + cls.add_method('RemoveAtEnd', + 'void', + [param('uint32_t', 'end')]) + ## packet-metadata.h: uint32_t ns3::PacketMetadata::GetUid() const [member function] + cls.add_method('GetUid', + 'uint32_t', + [], + is_const=True) + ## packet-metadata.h: uint32_t ns3::PacketMetadata::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## packet-metadata.h: void ns3::PacketMetadata::Serialize(ns3::Buffer::Iterator i, uint32_t size) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'i'), param('uint32_t', 'size')], + is_const=True) + ## packet-metadata.h: uint32_t ns3::PacketMetadata::Deserialize(ns3::Buffer::Iterator i) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'i')]) + ## packet-metadata.h: ns3::PacketMetadata::ItemIterator ns3::PacketMetadata::BeginItem(ns3::Buffer buffer) const [member function] + cls.add_method('BeginItem', + 'ns3::PacketMetadata::ItemIterator', + [param('ns3::Buffer', 'buffer')], + is_const=True) + return + +def register_Ns3PacketMetadataItem_methods(root_module, cls): + ## packet-metadata.h: ns3::PacketMetadata::Item::isFragment [variable] + cls.add_instance_attribute('isFragment', 'bool', is_const=False) + ## packet-metadata.h: ns3::PacketMetadata::Item::tid [variable] + cls.add_instance_attribute('tid', 'ns3::TypeId', is_const=False) + ## packet-metadata.h: ns3::PacketMetadata::Item::currentSize [variable] + cls.add_instance_attribute('currentSize', 'uint32_t', is_const=False) + ## packet-metadata.h: ns3::PacketMetadata::Item::currentTrimedFromStart [variable] + cls.add_instance_attribute('currentTrimedFromStart', 'uint32_t', is_const=False) + ## packet-metadata.h: ns3::PacketMetadata::Item::currentTrimedFromEnd [variable] + cls.add_instance_attribute('currentTrimedFromEnd', 'uint32_t', is_const=False) + ## packet-metadata.h: ns3::PacketMetadata::Item::current [variable] + cls.add_instance_attribute('current', 'ns3::Buffer::Iterator', is_const=False) + ## packet-metadata.h: ns3::PacketMetadata::Item::Item(ns3::PacketMetadata::Item const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketMetadata::Item const &', 'arg0')]) + ## packet-metadata.h: ns3::PacketMetadata::Item::Item() [constructor] + cls.add_constructor([]) + return + +def register_Ns3PacketMetadataItemIterator_methods(root_module, cls): + ## packet-metadata.h: ns3::PacketMetadata::ItemIterator::ItemIterator(ns3::PacketMetadata::ItemIterator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketMetadata::ItemIterator const &', 'arg0')]) + ## packet-metadata.h: ns3::PacketMetadata::ItemIterator::ItemIterator(ns3::PacketMetadata const * metadata, ns3::Buffer buffer) [constructor] + cls.add_constructor([param('ns3::PacketMetadata const *', 'metadata'), param('ns3::Buffer', 'buffer')]) + ## packet-metadata.h: bool ns3::PacketMetadata::ItemIterator::HasNext() const [member function] + cls.add_method('HasNext', + 'bool', + [], + is_const=True) + ## packet-metadata.h: ns3::PacketMetadata::Item ns3::PacketMetadata::ItemIterator::Next() [member function] + cls.add_method('Next', + 'ns3::PacketMetadata::Item', + []) + return + +def register_Ns3Tag_methods(root_module, cls): + ## tag.h: ns3::Tag::Tag(ns3::Tag const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Tag const &', 'arg0')]) + ## tag.h: ns3::Tag::Tag() [constructor] + cls.add_constructor([]) + ## tag.h: static ns3::TypeId ns3::Tag::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## tag.h: uint32_t ns3::Tag::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## tag.h: void ns3::Tag::Serialize(ns3::TagBuffer i) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::TagBuffer', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## tag.h: void ns3::Tag::Deserialize(ns3::TagBuffer i) [member function] + cls.add_method('Deserialize', + 'void', + [param('ns3::TagBuffer', 'i')], + is_pure_virtual=True, is_virtual=True) + ## tag.h: void ns3::Tag::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3TagBuffer_methods(root_module, cls): + ## tag-buffer.h: ns3::TagBuffer::TagBuffer(ns3::TagBuffer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TagBuffer const &', 'arg0')]) + ## tag-buffer.h: ns3::TagBuffer::TagBuffer(uint8_t * start, uint8_t * end) [constructor] + cls.add_constructor([param('uint8_t *', 'start'), param('uint8_t *', 'end')]) + ## tag-buffer.h: void ns3::TagBuffer::TrimAtEnd(uint32_t trim) [member function] + cls.add_method('TrimAtEnd', + 'void', + [param('uint32_t', 'trim')]) + ## tag-buffer.h: void ns3::TagBuffer::CopyFrom(ns3::TagBuffer o) [member function] + cls.add_method('CopyFrom', + 'void', + [param('ns3::TagBuffer', 'o')]) + ## tag-buffer.h: void ns3::TagBuffer::WriteU8(uint8_t v) [member function] + cls.add_method('WriteU8', + 'void', + [param('uint8_t', 'v')]) + ## tag-buffer.h: void ns3::TagBuffer::WriteU16(uint16_t data) [member function] + cls.add_method('WriteU16', + 'void', + [param('uint16_t', 'data')]) + ## tag-buffer.h: void ns3::TagBuffer::WriteU32(uint32_t data) [member function] + cls.add_method('WriteU32', + 'void', + [param('uint32_t', 'data')]) + ## tag-buffer.h: void ns3::TagBuffer::WriteU64(uint64_t v) [member function] + cls.add_method('WriteU64', + 'void', + [param('uint64_t', 'v')]) + ## tag-buffer.h: void ns3::TagBuffer::WriteDouble(double v) [member function] + cls.add_method('WriteDouble', + 'void', + [param('double', 'v')]) + ## tag-buffer.h: void ns3::TagBuffer::Write(uint8_t const * buffer, uint32_t size) [member function] + cls.add_method('Write', + 'void', + [param('uint8_t const *', 'buffer'), param('uint32_t', 'size')]) + ## tag-buffer.h: uint8_t ns3::TagBuffer::ReadU8() [member function] + cls.add_method('ReadU8', + 'uint8_t', + []) + ## tag-buffer.h: uint16_t ns3::TagBuffer::ReadU16() [member function] + cls.add_method('ReadU16', + 'uint16_t', + []) + ## tag-buffer.h: uint32_t ns3::TagBuffer::ReadU32() [member function] + cls.add_method('ReadU32', + 'uint32_t', + []) + ## tag-buffer.h: uint64_t ns3::TagBuffer::ReadU64() [member function] + cls.add_method('ReadU64', + 'uint64_t', + []) + ## tag-buffer.h: double ns3::TagBuffer::ReadDouble() [member function] + cls.add_method('ReadDouble', + 'double', + []) + ## tag-buffer.h: void ns3::TagBuffer::Read(uint8_t * buffer, uint32_t size) [member function] + cls.add_method('Read', + 'void', + [param('uint8_t *', 'buffer'), param('uint32_t', 'size')]) + return + +def register_Ns3TagIterator_methods(root_module, cls): + ## packet.h: ns3::TagIterator::TagIterator(ns3::TagIterator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TagIterator const &', 'arg0')]) + ## packet.h: bool ns3::TagIterator::HasNext() const [member function] + cls.add_method('HasNext', + 'bool', + [], + is_const=True) + ## packet.h: ns3::TagIterator::Item ns3::TagIterator::Next() [member function] + cls.add_method('Next', + 'ns3::TagIterator::Item', + []) + return + +def register_Ns3TagIteratorItem_methods(root_module, cls): + ## packet.h: ns3::TagIterator::Item::Item(ns3::TagIterator::Item const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TagIterator::Item const &', 'arg0')]) + ## packet.h: ns3::TypeId ns3::TagIterator::Item::GetTypeId() const [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_const=True) + ## packet.h: uint32_t ns3::TagIterator::Item::GetStart() const [member function] + cls.add_method('GetStart', + 'uint32_t', + [], + is_const=True) + ## packet.h: uint32_t ns3::TagIterator::Item::GetEnd() const [member function] + cls.add_method('GetEnd', + 'uint32_t', + [], + is_const=True) + ## packet.h: void ns3::TagIterator::Item::GetTag(ns3::Tag & tag) const [member function] + cls.add_method('GetTag', + 'void', + [param('ns3::Tag &', 'tag')], + is_const=True) + return + +def register_Ns3TagList_methods(root_module, cls): + ## tag-list.h: ns3::TagList::TagList() [constructor] + cls.add_constructor([]) + ## tag-list.h: ns3::TagList::TagList(ns3::TagList const & o) [copy constructor] + cls.add_constructor([param('ns3::TagList const &', 'o')]) + ## tag-list.h: ns3::TagBuffer ns3::TagList::Add(ns3::TypeId tid, uint32_t bufferSize, int32_t start, int32_t end) [member function] + cls.add_method('Add', + 'ns3::TagBuffer', + [param('ns3::TypeId', 'tid'), param('uint32_t', 'bufferSize'), param('int32_t', 'start'), param('int32_t', 'end')]) + ## tag-list.h: void ns3::TagList::Add(ns3::TagList const & o) [member function] + cls.add_method('Add', + 'void', + [param('ns3::TagList const &', 'o')]) + ## tag-list.h: void ns3::TagList::RemoveAll() [member function] + cls.add_method('RemoveAll', + 'void', + []) + ## tag-list.h: ns3::TagList::Iterator ns3::TagList::Begin(int32_t offsetStart, int32_t offsetEnd) const [member function] + cls.add_method('Begin', + 'ns3::TagList::Iterator', + [param('int32_t', 'offsetStart'), param('int32_t', 'offsetEnd')], + is_const=True) + ## tag-list.h: void ns3::TagList::AddAtEnd(int32_t adjustment, int32_t appendOffset) [member function] + cls.add_method('AddAtEnd', + 'void', + [param('int32_t', 'adjustment'), param('int32_t', 'appendOffset')]) + ## tag-list.h: void ns3::TagList::AddAtStart(int32_t adjustment, int32_t prependOffset) [member function] + cls.add_method('AddAtStart', + 'void', + [param('int32_t', 'adjustment'), param('int32_t', 'prependOffset')]) + return + +def register_Ns3TagListIterator_methods(root_module, cls): + ## tag-list.h: ns3::TagList::Iterator::Iterator(ns3::TagList::Iterator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TagList::Iterator const &', 'arg0')]) + ## tag-list.h: bool ns3::TagList::Iterator::HasNext() const [member function] + cls.add_method('HasNext', + 'bool', + [], + is_const=True) + ## tag-list.h: ns3::TagList::Iterator::Item ns3::TagList::Iterator::Next() [member function] + cls.add_method('Next', + 'ns3::TagList::Iterator::Item', + []) + ## tag-list.h: uint32_t ns3::TagList::Iterator::GetOffsetStart() const [member function] + cls.add_method('GetOffsetStart', + 'uint32_t', + [], + is_const=True) + return + +def register_Ns3TagListIteratorItem_methods(root_module, cls): + ## tag-list.h: ns3::TagList::Iterator::Item::tid [variable] + cls.add_instance_attribute('tid', 'ns3::TypeId', is_const=False) + ## tag-list.h: ns3::TagList::Iterator::Item::size [variable] + cls.add_instance_attribute('size', 'uint32_t', is_const=False) + ## tag-list.h: ns3::TagList::Iterator::Item::start [variable] + cls.add_instance_attribute('start', 'int32_t', is_const=False) + ## tag-list.h: ns3::TagList::Iterator::Item::end [variable] + cls.add_instance_attribute('end', 'int32_t', is_const=False) + ## tag-list.h: ns3::TagList::Iterator::Item::buf [variable] + cls.add_instance_attribute('buf', 'ns3::TagBuffer', is_const=False) + ## tag-list.h: ns3::TagList::Iterator::Item::Item(ns3::TagList::Iterator::Item const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TagList::Iterator::Item const &', 'arg0')]) + ## tag-list.h: ns3::TagList::Iterator::Item::Item(ns3::TagBuffer buf) [constructor] + cls.add_constructor([param('ns3::TagBuffer', 'buf')]) + return + +def register_Ns3Chunk_methods(root_module, cls): + ## chunk.h: ns3::Chunk::Chunk(ns3::Chunk const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Chunk const &', 'arg0')]) + ## chunk.h: ns3::Chunk::Chunk() [constructor] + cls.add_constructor([]) + ## chunk.h: static ns3::TypeId ns3::Chunk::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## chunk.h: uint32_t ns3::Chunk::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_pure_virtual=True, is_virtual=True) + ## chunk.h: void ns3::Chunk::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3DataRateChecker_methods(root_module, cls): + ## data-rate.h: ns3::DataRateChecker::DataRateChecker(ns3::DataRateChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DataRateChecker const &', 'arg0')]) + ## data-rate.h: ns3::DataRateChecker::DataRateChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3DataRateValue_methods(root_module, cls): + ## data-rate.h: ns3::DataRateValue::DataRateValue(ns3::DataRateValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DataRateValue const &', 'arg0')]) + ## data-rate.h: ns3::DataRateValue::DataRateValue() [constructor] + cls.add_constructor([]) + ## data-rate.h: ns3::DataRateValue::DataRateValue(ns3::DataRate const & value) [constructor] + cls.add_constructor([param('ns3::DataRate const &', 'value')]) + ## data-rate.h: void ns3::DataRateValue::Set(ns3::DataRate const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::DataRate const &', 'value')]) + ## data-rate.h: ns3::DataRate ns3::DataRateValue::Get() const [member function] + cls.add_method('Get', + 'ns3::DataRate', + [], + is_const=True) + ## data-rate.h: ns3::Ptr ns3::DataRateValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## data-rate.h: std::string ns3::DataRateValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## data-rate.h: bool ns3::DataRateValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3Header_methods(root_module, cls): + cls.add_output_stream_operator() + ## header.h: ns3::Header::Header() [constructor] + cls.add_constructor([]) + ## header.h: ns3::Header::Header(ns3::Header const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Header const &', 'arg0')]) + ## header.h: uint32_t ns3::Header::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_pure_virtual=True, is_virtual=True) + ## header.h: uint32_t ns3::Header::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## header.h: static ns3::TypeId ns3::Header::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## header.h: void ns3::Header::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## header.h: void ns3::Header::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3PcapWriter_methods(root_module, cls): + ## pcap-writer.h: ns3::PcapWriter::PcapWriter(ns3::PcapWriter const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PcapWriter const &', 'arg0')]) + ## pcap-writer.h: ns3::PcapWriter::PcapWriter() [constructor] + cls.add_constructor([]) + ## pcap-writer.h: void ns3::PcapWriter::Open(std::string const & name) [member function] + cls.add_method('Open', + 'void', + [param('std::string const &', 'name')]) + ## pcap-writer.h: void ns3::PcapWriter::WriteEthernetHeader() [member function] + cls.add_method('WriteEthernetHeader', + 'void', + []) + ## pcap-writer.h: void ns3::PcapWriter::WriteIpHeader() [member function] + cls.add_method('WriteIpHeader', + 'void', + []) + ## pcap-writer.h: void ns3::PcapWriter::WriteWifiHeader() [member function] + cls.add_method('WriteWifiHeader', + 'void', + []) + ## pcap-writer.h: void ns3::PcapWriter::WritePppHeader() [member function] + cls.add_method('WritePppHeader', + 'void', + []) + ## pcap-writer.h: void ns3::PcapWriter::WritePacket(ns3::Ptr packet) [member function] + cls.add_method('WritePacket', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet')]) + return + +def register_Ns3Trailer_methods(root_module, cls): + cls.add_output_stream_operator() + ## trailer.h: ns3::Trailer::Trailer() [constructor] + cls.add_constructor([]) + ## trailer.h: ns3::Trailer::Trailer(ns3::Trailer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Trailer const &', 'arg0')]) + ## trailer.h: uint32_t ns3::Trailer::Deserialize(ns3::Buffer::Iterator end) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'end')], + is_pure_virtual=True, is_virtual=True) + ## trailer.h: uint32_t ns3::Trailer::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## trailer.h: static ns3::TypeId ns3::Trailer::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## trailer.h: void ns3::Trailer::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## trailer.h: void ns3::Trailer::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3ErrorModel_methods(root_module, cls): + ## error-model.h: ns3::ErrorModel::ErrorModel(ns3::ErrorModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ErrorModel const &', 'arg0')]) + ## error-model.h: static ns3::TypeId ns3::ErrorModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## error-model.h: ns3::ErrorModel::ErrorModel() [constructor] + cls.add_constructor([]) + ## error-model.h: bool ns3::ErrorModel::IsCorrupt(ns3::Ptr pkt) [member function] + cls.add_method('IsCorrupt', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'pkt')]) + ## error-model.h: void ns3::ErrorModel::Reset() [member function] + cls.add_method('Reset', + 'void', + []) + ## error-model.h: void ns3::ErrorModel::Enable() [member function] + cls.add_method('Enable', + 'void', + []) + ## error-model.h: void ns3::ErrorModel::Disable() [member function] + cls.add_method('Disable', + 'void', + []) + ## error-model.h: bool ns3::ErrorModel::IsEnabled() const [member function] + cls.add_method('IsEnabled', + 'bool', + [], + is_const=True) + ## error-model.h: bool ns3::ErrorModel::DoCorrupt(ns3::Ptr arg0) [member function] + cls.add_method('DoCorrupt', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'arg0')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## error-model.h: void ns3::ErrorModel::DoReset() [member function] + cls.add_method('DoReset', + 'void', + [], + is_pure_virtual=True, visibility='private', is_virtual=True) + return + +def register_Ns3ListErrorModel_methods(root_module, cls): + ## error-model.h: ns3::ListErrorModel::ListErrorModel(ns3::ListErrorModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ListErrorModel const &', 'arg0')]) + ## error-model.h: static ns3::TypeId ns3::ListErrorModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## error-model.h: ns3::ListErrorModel::ListErrorModel() [constructor] + cls.add_constructor([]) + ## error-model.h: std::list > ns3::ListErrorModel::GetList() const [member function] + cls.add_method('GetList', + 'std::list< unsigned int >', + [], + is_const=True) + ## error-model.h: void ns3::ListErrorModel::SetList(std::list > const & packetlist) [member function] + cls.add_method('SetList', + 'void', + [param('std::list< unsigned int > const &', 'packetlist')]) + ## error-model.h: bool ns3::ListErrorModel::DoCorrupt(ns3::Ptr p) [member function] + cls.add_method('DoCorrupt', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + visibility='private', is_virtual=True) + ## error-model.h: void ns3::ListErrorModel::DoReset() [member function] + cls.add_method('DoReset', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3RateErrorModel_methods(root_module, cls): + ## error-model.h: ns3::RateErrorModel::RateErrorModel(ns3::RateErrorModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RateErrorModel const &', 'arg0')]) + ## error-model.h: static ns3::TypeId ns3::RateErrorModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## error-model.h: ns3::RateErrorModel::RateErrorModel() [constructor] + cls.add_constructor([]) + ## error-model.h: ns3::ErrorUnit ns3::RateErrorModel::GetUnit() const [member function] + cls.add_method('GetUnit', + 'ns3::ErrorUnit', + [], + is_const=True) + ## error-model.h: void ns3::RateErrorModel::SetUnit(ns3::ErrorUnit error_unit) [member function] + cls.add_method('SetUnit', + 'void', + [param('ns3::ErrorUnit', 'error_unit')]) + ## error-model.h: double ns3::RateErrorModel::GetRate() const [member function] + cls.add_method('GetRate', + 'double', + [], + is_const=True) + ## error-model.h: void ns3::RateErrorModel::SetRate(double rate) [member function] + cls.add_method('SetRate', + 'void', + [param('double', 'rate')]) + ## error-model.h: void ns3::RateErrorModel::SetRandomVariable(ns3::RandomVariable const & ranvar) [member function] + cls.add_method('SetRandomVariable', + 'void', + [param('ns3::RandomVariable const &', 'ranvar')]) + ## error-model.h: bool ns3::RateErrorModel::DoCorrupt(ns3::Ptr p) [member function] + cls.add_method('DoCorrupt', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + visibility='private', is_virtual=True) + ## error-model.h: bool ns3::RateErrorModel::DoCorruptPkt(ns3::Ptr p) [member function] + cls.add_method('DoCorruptPkt', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + visibility='private', is_virtual=True) + ## error-model.h: bool ns3::RateErrorModel::DoCorruptByte(ns3::Ptr p) [member function] + cls.add_method('DoCorruptByte', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + visibility='private', is_virtual=True) + ## error-model.h: bool ns3::RateErrorModel::DoCorruptBit(ns3::Ptr p) [member function] + cls.add_method('DoCorruptBit', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + visibility='private', is_virtual=True) + ## error-model.h: void ns3::RateErrorModel::DoReset() [member function] + cls.add_method('DoReset', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + ## data-rate.h: extern ns3::Ptr ns3::MakeDataRateChecker() [free function] + module.add_function('MakeDataRateChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_contrib.py b/bindings/python/ns3_module_contrib.py new file mode 100644 index 000000000..53ff8b169 --- /dev/null +++ b/bindings/python/ns3_module_contrib.py @@ -0,0 +1,260 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## delay-jitter-estimation.h: ns3::DelayJitterEstimation [class] + module.add_class('DelayJitterEstimation') + ## event-garbage-collector.h: ns3::EventGarbageCollector [class] + module.add_class('EventGarbageCollector') + ## gnuplot.h: ns3::Gnuplot [class] + module.add_class('Gnuplot') + ## gnuplot.h: ns3::GnuplotDataset [class] + module.add_class('GnuplotDataset') + ## gnuplot.h: ns3::GnuplotDataset::Style [enumeration] + module.add_enum('Style', ['LINES', 'POINTS', 'LINES_POINTS', 'DOTS', 'IMPULSES', 'STEPS', 'FSTEPS', 'HISTEPS'], outer_class=root_module['ns3::GnuplotDataset']) + ## gnuplot.h: ns3::GnuplotDataset::ErrorBars [enumeration] + module.add_enum('ErrorBars', ['NONE', 'X', 'Y', 'XY'], outer_class=root_module['ns3::GnuplotDataset']) + ## gtk-config-store.h: ns3::GtkConfigStore [class] + module.add_class('GtkConfigStore') + ## config-store.h: ns3::ConfigStore [class] + module.add_class('ConfigStore', parent=root_module['ns3::ObjectBase']) + ## flow-id-tag.h: ns3::FlowIdTag [class] + module.add_class('FlowIdTag', parent=root_module['ns3::Tag']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3DelayJitterEstimation_methods(root_module, root_module['ns3::DelayJitterEstimation']) + register_Ns3EventGarbageCollector_methods(root_module, root_module['ns3::EventGarbageCollector']) + register_Ns3Gnuplot_methods(root_module, root_module['ns3::Gnuplot']) + register_Ns3GnuplotDataset_methods(root_module, root_module['ns3::GnuplotDataset']) + register_Ns3GtkConfigStore_methods(root_module, root_module['ns3::GtkConfigStore']) + register_Ns3ConfigStore_methods(root_module, root_module['ns3::ConfigStore']) + register_Ns3FlowIdTag_methods(root_module, root_module['ns3::FlowIdTag']) + return + +def register_Ns3DelayJitterEstimation_methods(root_module, cls): + ## delay-jitter-estimation.h: ns3::DelayJitterEstimation::DelayJitterEstimation(ns3::DelayJitterEstimation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DelayJitterEstimation const &', 'arg0')]) + ## delay-jitter-estimation.h: ns3::DelayJitterEstimation::DelayJitterEstimation() [constructor] + cls.add_constructor([]) + ## delay-jitter-estimation.h: static void ns3::DelayJitterEstimation::PrepareTx(ns3::Ptr packet) [member function] + cls.add_method('PrepareTx', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet')], + is_static=True) + ## delay-jitter-estimation.h: void ns3::DelayJitterEstimation::RecordRx(ns3::Ptr packet) [member function] + cls.add_method('RecordRx', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet')]) + ## delay-jitter-estimation.h: ns3::Time ns3::DelayJitterEstimation::GetLastDelay() const [member function] + cls.add_method('GetLastDelay', + 'ns3::Time', + [], + is_const=True) + ## delay-jitter-estimation.h: ns3::Time ns3::DelayJitterEstimation::GetLastJitter() const [member function] + cls.add_method('GetLastJitter', + 'ns3::Time', + [], + is_const=True) + return + +def register_Ns3EventGarbageCollector_methods(root_module, cls): + ## event-garbage-collector.h: ns3::EventGarbageCollector::EventGarbageCollector(ns3::EventGarbageCollector const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EventGarbageCollector const &', 'arg0')]) + ## event-garbage-collector.h: ns3::EventGarbageCollector::EventGarbageCollector() [constructor] + cls.add_constructor([]) + ## event-garbage-collector.h: void ns3::EventGarbageCollector::Track(ns3::EventId event) [member function] + cls.add_method('Track', + 'void', + [param('ns3::EventId', 'event')]) + return + +def register_Ns3Gnuplot_methods(root_module, cls): + ## gnuplot.h: ns3::Gnuplot::Gnuplot(ns3::Gnuplot const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Gnuplot const &', 'arg0')]) + ## gnuplot.h: ns3::Gnuplot::Gnuplot(std::string pngFilename) [constructor] + cls.add_constructor([param('std::string', 'pngFilename')]) + ## gnuplot.h: void ns3::Gnuplot::SetLegend(std::string xLegend, std::string yLegend) [member function] + cls.add_method('SetLegend', + 'void', + [param('std::string', 'xLegend'), param('std::string', 'yLegend')]) + ## gnuplot.h: void ns3::Gnuplot::AddDataset(ns3::GnuplotDataset const & dataset) [member function] + cls.add_method('AddDataset', + 'void', + [param('ns3::GnuplotDataset const &', 'dataset')]) + ## gnuplot.h: void ns3::Gnuplot::GenerateOutput(std::ostream & os) [member function] + cls.add_method('GenerateOutput', + 'void', + [param('std::ostream &', 'os')]) + return + +def register_Ns3GnuplotDataset_methods(root_module, cls): + ## gnuplot.h: ns3::GnuplotDataset::GnuplotDataset(ns3::GnuplotDataset const & arg0) [copy constructor] + cls.add_constructor([param('ns3::GnuplotDataset const &', 'arg0')]) + ## gnuplot.h: ns3::GnuplotDataset::GnuplotDataset() [constructor] + cls.add_constructor([]) + ## gnuplot.h: ns3::GnuplotDataset::GnuplotDataset(std::string title) [constructor] + cls.add_constructor([param('std::string', 'title')]) + ## gnuplot.h: void ns3::GnuplotDataset::SetStyle(ns3::GnuplotDataset::Style style) [member function] + cls.add_method('SetStyle', + 'void', + [param('ns3::GnuplotDataset::Style', 'style')]) + ## gnuplot.h: void ns3::GnuplotDataset::SetErrorBars(ns3::GnuplotDataset::ErrorBars errorBars) [member function] + cls.add_method('SetErrorBars', + 'void', + [param('ns3::GnuplotDataset::ErrorBars', 'errorBars')]) + ## gnuplot.h: void ns3::GnuplotDataset::Add(double x, double y) [member function] + cls.add_method('Add', + 'void', + [param('double', 'x'), param('double', 'y')]) + ## gnuplot.h: void ns3::GnuplotDataset::Add(double x, double y, double errorDelta) [member function] + cls.add_method('Add', + 'void', + [param('double', 'x'), param('double', 'y'), param('double', 'errorDelta')]) + return + +def register_Ns3GtkConfigStore_methods(root_module, cls): + ## gtk-config-store.h: ns3::GtkConfigStore::GtkConfigStore(ns3::GtkConfigStore const & arg0) [copy constructor] + cls.add_constructor([param('ns3::GtkConfigStore const &', 'arg0')]) + ## gtk-config-store.h: ns3::GtkConfigStore::GtkConfigStore() [constructor] + cls.add_constructor([]) + ## gtk-config-store.h: void ns3::GtkConfigStore::Configure() [member function] + cls.add_method('Configure', + 'void', + []) + return + +def register_Ns3ConfigStore_methods(root_module, cls): + ## config-store.h: ns3::ConfigStore::ConfigStore(ns3::ConfigStore const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ConfigStore const &', 'arg0')]) + ## config-store.h: static ns3::TypeId ns3::ConfigStore::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## config-store.h: ns3::TypeId ns3::ConfigStore::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## config-store.h: ns3::ConfigStore::ConfigStore() [constructor] + cls.add_constructor([]) + ## config-store.h: void ns3::ConfigStore::Configure() [member function] + cls.add_method('Configure', + 'void', + []) + return + +def register_Ns3FlowIdTag_methods(root_module, cls): + ## flow-id-tag.h: ns3::FlowIdTag::FlowIdTag(ns3::FlowIdTag const & arg0) [copy constructor] + cls.add_constructor([param('ns3::FlowIdTag const &', 'arg0')]) + ## flow-id-tag.h: static ns3::TypeId ns3::FlowIdTag::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## flow-id-tag.h: ns3::TypeId ns3::FlowIdTag::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## flow-id-tag.h: uint32_t ns3::FlowIdTag::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## flow-id-tag.h: void ns3::FlowIdTag::Serialize(ns3::TagBuffer buf) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::TagBuffer', 'buf')], + is_const=True, is_virtual=True) + ## flow-id-tag.h: void ns3::FlowIdTag::Deserialize(ns3::TagBuffer buf) [member function] + cls.add_method('Deserialize', + 'void', + [param('ns3::TagBuffer', 'buf')], + is_virtual=True) + ## flow-id-tag.h: void ns3::FlowIdTag::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## flow-id-tag.h: ns3::FlowIdTag::FlowIdTag() [constructor] + cls.add_constructor([]) + ## flow-id-tag.h: ns3::FlowIdTag::FlowIdTag(uint32_t flowId) [constructor] + cls.add_constructor([param('uint32_t', 'flowId')]) + ## flow-id-tag.h: void ns3::FlowIdTag::SetFlowId(uint32_t flowId) [member function] + cls.add_method('SetFlowId', + 'void', + [param('uint32_t', 'flowId')]) + ## flow-id-tag.h: uint32_t ns3::FlowIdTag::GetFlowId() const [member function] + cls.add_method('GetFlowId', + 'uint32_t', + [], + is_const=True) + ## flow-id-tag.h: static uint32_t ns3::FlowIdTag::AllocateFlowId() [member function] + cls.add_method('AllocateFlowId', + 'uint32_t', + [], + is_static=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_core.py b/bindings/python/ns3_module_core.py new file mode 100644 index 000000000..ef6df5af2 --- /dev/null +++ b/bindings/python/ns3_module_core.py @@ -0,0 +1,2182 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## log.h: ns3::LogLevel [enumeration] + module.add_enum('LogLevel', ['LOG_NONE', 'LOG_ERROR', 'LOG_LEVEL_ERROR', 'LOG_WARN', 'LOG_LEVEL_WARN', 'LOG_DEBUG', 'LOG_LEVEL_DEBUG', 'LOG_INFO', 'LOG_LEVEL_INFO', 'LOG_FUNCTION', 'LOG_LEVEL_FUNCTION', 'LOG_LOGIC', 'LOG_LEVEL_LOGIC', 'LOG_ALL', 'LOG_LEVEL_ALL', 'LOG_PREFIX_FUNC', 'LOG_PREFIX_TIME']) + ## attribute-list.h: ns3::AttributeList [class] + module.add_class('AttributeList') + ## callback.h: ns3::CallbackBase [class] + module.add_class('CallbackBase') + ## callback.h: ns3::CallbackImplBase [class] + module.add_class('CallbackImplBase', allow_subclassing=True, memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount')) + ## command-line.h: ns3::CommandLine [class] + module.add_class('CommandLine') + ## system-mutex.h: ns3::CriticalSection [class] + module.add_class('CriticalSection') + ## global-value.h: ns3::GlobalValue [class] + module.add_class('GlobalValue') + ## int-to-type.h: ns3::IntToType<0> [struct] + module.add_class('IntToType', template_parameters=['0']) + ## int-to-type.h: ns3::IntToType<0>::v_e [enumeration] + module.add_enum('v_e', ['value'], outer_class=root_module['ns3::IntToType< 0 >']) + ## int-to-type.h: ns3::IntToType<1> [struct] + module.add_class('IntToType', template_parameters=['1']) + ## int-to-type.h: ns3::IntToType<1>::v_e [enumeration] + module.add_enum('v_e', ['value'], outer_class=root_module['ns3::IntToType< 1 >']) + ## int-to-type.h: ns3::IntToType<2> [struct] + module.add_class('IntToType', template_parameters=['2']) + ## int-to-type.h: ns3::IntToType<2>::v_e [enumeration] + module.add_enum('v_e', ['value'], outer_class=root_module['ns3::IntToType< 2 >']) + ## int-to-type.h: ns3::IntToType<3> [struct] + module.add_class('IntToType', template_parameters=['3']) + ## int-to-type.h: ns3::IntToType<3>::v_e [enumeration] + module.add_enum('v_e', ['value'], outer_class=root_module['ns3::IntToType< 3 >']) + ## int-to-type.h: ns3::IntToType<4> [struct] + module.add_class('IntToType', template_parameters=['4']) + ## int-to-type.h: ns3::IntToType<4>::v_e [enumeration] + module.add_enum('v_e', ['value'], outer_class=root_module['ns3::IntToType< 4 >']) + ## int-to-type.h: ns3::IntToType<5> [struct] + module.add_class('IntToType', template_parameters=['5']) + ## int-to-type.h: ns3::IntToType<5>::v_e [enumeration] + module.add_enum('v_e', ['value'], outer_class=root_module['ns3::IntToType< 5 >']) + ## int-to-type.h: ns3::IntToType<6> [struct] + module.add_class('IntToType', template_parameters=['6']) + ## int-to-type.h: ns3::IntToType<6>::v_e [enumeration] + module.add_enum('v_e', ['value'], outer_class=root_module['ns3::IntToType< 6 >']) + ## object-base.h: ns3::ObjectBase [class] + module.add_class('ObjectBase', allow_subclassing=True) + ## object-factory.h: ns3::ObjectFactory [class] + module.add_class('ObjectFactory') + ## random-variable.h: ns3::RandomVariable [class] + module.add_class('RandomVariable') + ## ref-count-base.h: ns3::RefCountBase [class] + module.add_class('RefCountBase', automatic_type_narrowing=True, memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount')) + ## rng-stream.h: ns3::RngStream [class] + module.add_class('RngStream') + ## random-variable.h: ns3::SequentialVariable [class] + module.add_class('SequentialVariable', parent=root_module['ns3::RandomVariable']) + ## system-condition.h: ns3::SystemCondition [class] + module.add_class('SystemCondition') + ## system-mutex.h: ns3::SystemMutex [class] + module.add_class('SystemMutex') + ## system-thread.h: ns3::SystemThread [class] + module.add_class('SystemThread') + ## system-wall-clock-ms.h: ns3::SystemWallClockMs [class] + module.add_class('SystemWallClockMs') + ## trace-source-accessor.h: ns3::TraceSourceAccessor [class] + module.add_class('TraceSourceAccessor', allow_subclassing=True) + ## random-variable.h: ns3::TriangularVariable [class] + module.add_class('TriangularVariable', parent=root_module['ns3::RandomVariable']) + ## type-id.h: ns3::TypeId [class] + module.add_class('TypeId') + ## type-id.h: ns3::TypeId::AttributeFlag [enumeration] + module.add_enum('AttributeFlag', ['ATTR_GET', 'ATTR_SET', 'ATTR_CONSTRUCT', 'ATTR_SGC'], outer_class=root_module['ns3::TypeId']) + ## type-id.h: ns3::TypeId::AttributeInfo [struct] + module.add_class('AttributeInfo', outer_class=root_module['ns3::TypeId']) + ## random-variable.h: ns3::UniformVariable [class] + module.add_class('UniformVariable', parent=root_module['ns3::RandomVariable']) + ## attribute-list.h: ns3::UnsafeAttributeList [class] + module.add_class('UnsafeAttributeList') + ## random-variable.h: ns3::WeibullVariable [class] + module.add_class('WeibullVariable', parent=root_module['ns3::RandomVariable']) + ## empty.h: ns3::empty [class] + module.add_class('empty') + ## attribute.h: ns3::AttributeAccessor [class] + module.add_class('AttributeAccessor', parent=root_module['ns3::RefCountBase']) + ## attribute.h: ns3::AttributeChecker [class] + module.add_class('AttributeChecker', allow_subclassing=False, automatic_type_narrowing=True, parent=root_module['ns3::RefCountBase']) + ## attribute.h: ns3::AttributeValue [class] + module.add_class('AttributeValue', allow_subclassing=False, automatic_type_narrowing=True, parent=root_module['ns3::RefCountBase']) + ## boolean.h: ns3::BooleanChecker [class] + module.add_class('BooleanChecker', parent=root_module['ns3::AttributeChecker']) + ## boolean.h: ns3::BooleanValue [class] + module.add_class('BooleanValue', parent=root_module['ns3::AttributeValue']) + ## callback.h: ns3::CallbackChecker [class] + module.add_class('CallbackChecker', parent=root_module['ns3::AttributeChecker']) + ## callback.h: ns3::CallbackValue [class] + module.add_class('CallbackValue', parent=root_module['ns3::AttributeValue']) + ## random-variable.h: ns3::ConstantVariable [class] + module.add_class('ConstantVariable', parent=root_module['ns3::RandomVariable']) + ## random-variable.h: ns3::DeterministicVariable [class] + module.add_class('DeterministicVariable', parent=root_module['ns3::RandomVariable']) + ## double.h: ns3::DoubleValue [class] + module.add_class('DoubleValue', parent=root_module['ns3::AttributeValue']) + ## random-variable.h: ns3::EmpiricalVariable [class] + module.add_class('EmpiricalVariable', parent=root_module['ns3::RandomVariable']) + ## attribute.h: ns3::EmptyAttributeValue [class] + module.add_class('EmptyAttributeValue', parent=root_module['ns3::AttributeValue']) + ## enum.h: ns3::EnumChecker [class] + module.add_class('EnumChecker', parent=root_module['ns3::AttributeChecker']) + ## enum.h: ns3::EnumValue [class] + module.add_class('EnumValue', parent=root_module['ns3::AttributeValue']) + ## random-variable.h: ns3::ExponentialVariable [class] + module.add_class('ExponentialVariable', parent=root_module['ns3::RandomVariable']) + ## random-variable.h: ns3::IntEmpiricalVariable [class] + module.add_class('IntEmpiricalVariable', parent=root_module['ns3::EmpiricalVariable']) + ## integer.h: ns3::IntegerValue [class] + module.add_class('IntegerValue', parent=root_module['ns3::AttributeValue']) + ## random-variable.h: ns3::LogNormalVariable [class] + module.add_class('LogNormalVariable', parent=root_module['ns3::RandomVariable']) + ## random-variable.h: ns3::NormalVariable [class] + module.add_class('NormalVariable', parent=root_module['ns3::RandomVariable']) + ## object.h: ns3::Object [class] + module.add_class('Object', automatic_type_narrowing=True, parent=root_module['ns3::ObjectBase'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount')) + ## object.h: ns3::Object::AggregateIterator [class] + module.add_class('AggregateIterator', outer_class=root_module['ns3::Object']) + ## object-factory.h: ns3::ObjectFactoryChecker [class] + module.add_class('ObjectFactoryChecker', parent=root_module['ns3::AttributeChecker']) + ## object-factory.h: ns3::ObjectFactoryValue [class] + module.add_class('ObjectFactoryValue', parent=root_module['ns3::AttributeValue']) + ## object-vector.h: ns3::ObjectVectorAccessor [class] + module.add_class('ObjectVectorAccessor', parent=root_module['ns3::AttributeAccessor']) + ## object-vector.h: ns3::ObjectVectorChecker [class] + module.add_class('ObjectVectorChecker', parent=root_module['ns3::AttributeChecker']) + ## object-vector.h: ns3::ObjectVectorValue [class] + module.add_class('ObjectVectorValue', parent=root_module['ns3::AttributeValue']) + ## random-variable.h: ns3::ParetoVariable [class] + module.add_class('ParetoVariable', parent=root_module['ns3::RandomVariable']) + ## pointer.h: ns3::PointerChecker [class] + module.add_class('PointerChecker', parent=root_module['ns3::AttributeChecker']) + ## pointer.h: ns3::PointerValue [class] + module.add_class('PointerValue', parent=root_module['ns3::AttributeValue']) + ## random-variable.h: ns3::RandomVariableChecker [class] + module.add_class('RandomVariableChecker', parent=root_module['ns3::AttributeChecker']) + ## random-variable.h: ns3::RandomVariableValue [class] + module.add_class('RandomVariableValue', parent=root_module['ns3::AttributeValue']) + ## string.h: ns3::StringChecker [class] + module.add_class('StringChecker', parent=root_module['ns3::AttributeChecker']) + ## string.h: ns3::StringValue [class] + module.add_class('StringValue', parent=root_module['ns3::AttributeValue']) + ## type-id.h: ns3::TypeIdChecker [class] + module.add_class('TypeIdChecker', parent=root_module['ns3::AttributeChecker']) + ## type-id.h: ns3::TypeIdValue [class] + module.add_class('TypeIdValue', parent=root_module['ns3::AttributeValue']) + ## uinteger.h: ns3::UintegerValue [class] + module.add_class('UintegerValue', parent=root_module['ns3::AttributeValue']) + ## traced-value.h: ns3::TracedValue [class] + module.add_class('TracedValue', template_parameters=['unsigned int']) + ## traced-value.h: ns3::TracedValue [class] + root_module['ns3::TracedValue< unsigned int >'].implicitly_converts_to(root_module['ns3::IntegerValue']) + ## traced-value.h: ns3::TracedValue [class] + root_module['ns3::TracedValue< unsigned int >'].implicitly_converts_to(root_module['ns3::UintegerValue']) + ## traced-value.h: ns3::TracedValue [class] + root_module['ns3::TracedValue< unsigned int >'].implicitly_converts_to(root_module['ns3::BooleanValue']) + ## traced-value.h: ns3::TracedValue [class] + root_module['ns3::TracedValue< unsigned int >'].implicitly_converts_to(root_module['ns3::EnumValue']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + ## config.h: ns3::Config::MatchContainer [class] + module.add_class('MatchContainer') + module.add_container('std::vector< ns3::Ptr< ns3::Object > >', 'ns3::Ptr< ns3::Object >', container_type='vector') + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3AttributeList_methods(root_module, root_module['ns3::AttributeList']) + register_Ns3CallbackBase_methods(root_module, root_module['ns3::CallbackBase']) + register_Ns3CallbackImplBase_methods(root_module, root_module['ns3::CallbackImplBase']) + register_Ns3CommandLine_methods(root_module, root_module['ns3::CommandLine']) + register_Ns3CriticalSection_methods(root_module, root_module['ns3::CriticalSection']) + register_Ns3GlobalValue_methods(root_module, root_module['ns3::GlobalValue']) + register_Ns3IntToType__0_methods(root_module, root_module['ns3::IntToType< 0 >']) + register_Ns3IntToType__1_methods(root_module, root_module['ns3::IntToType< 1 >']) + register_Ns3IntToType__2_methods(root_module, root_module['ns3::IntToType< 2 >']) + register_Ns3IntToType__3_methods(root_module, root_module['ns3::IntToType< 3 >']) + register_Ns3IntToType__4_methods(root_module, root_module['ns3::IntToType< 4 >']) + register_Ns3IntToType__5_methods(root_module, root_module['ns3::IntToType< 5 >']) + register_Ns3IntToType__6_methods(root_module, root_module['ns3::IntToType< 6 >']) + register_Ns3ObjectBase_methods(root_module, root_module['ns3::ObjectBase']) + register_Ns3ObjectFactory_methods(root_module, root_module['ns3::ObjectFactory']) + register_Ns3RandomVariable_methods(root_module, root_module['ns3::RandomVariable']) + register_Ns3RefCountBase_methods(root_module, root_module['ns3::RefCountBase']) + register_Ns3RngStream_methods(root_module, root_module['ns3::RngStream']) + register_Ns3SequentialVariable_methods(root_module, root_module['ns3::SequentialVariable']) + register_Ns3SystemCondition_methods(root_module, root_module['ns3::SystemCondition']) + register_Ns3SystemMutex_methods(root_module, root_module['ns3::SystemMutex']) + register_Ns3SystemThread_methods(root_module, root_module['ns3::SystemThread']) + register_Ns3SystemWallClockMs_methods(root_module, root_module['ns3::SystemWallClockMs']) + register_Ns3TraceSourceAccessor_methods(root_module, root_module['ns3::TraceSourceAccessor']) + register_Ns3TriangularVariable_methods(root_module, root_module['ns3::TriangularVariable']) + register_Ns3TypeId_methods(root_module, root_module['ns3::TypeId']) + register_Ns3TypeIdAttributeInfo_methods(root_module, root_module['ns3::TypeId::AttributeInfo']) + register_Ns3UniformVariable_methods(root_module, root_module['ns3::UniformVariable']) + register_Ns3UnsafeAttributeList_methods(root_module, root_module['ns3::UnsafeAttributeList']) + register_Ns3WeibullVariable_methods(root_module, root_module['ns3::WeibullVariable']) + register_Ns3Empty_methods(root_module, root_module['ns3::empty']) + register_Ns3AttributeAccessor_methods(root_module, root_module['ns3::AttributeAccessor']) + register_Ns3AttributeChecker_methods(root_module, root_module['ns3::AttributeChecker']) + register_Ns3AttributeValue_methods(root_module, root_module['ns3::AttributeValue']) + register_Ns3BooleanChecker_methods(root_module, root_module['ns3::BooleanChecker']) + register_Ns3BooleanValue_methods(root_module, root_module['ns3::BooleanValue']) + register_Ns3CallbackChecker_methods(root_module, root_module['ns3::CallbackChecker']) + register_Ns3CallbackValue_methods(root_module, root_module['ns3::CallbackValue']) + register_Ns3ConstantVariable_methods(root_module, root_module['ns3::ConstantVariable']) + register_Ns3DeterministicVariable_methods(root_module, root_module['ns3::DeterministicVariable']) + register_Ns3DoubleValue_methods(root_module, root_module['ns3::DoubleValue']) + register_Ns3EmpiricalVariable_methods(root_module, root_module['ns3::EmpiricalVariable']) + register_Ns3EmptyAttributeValue_methods(root_module, root_module['ns3::EmptyAttributeValue']) + register_Ns3EnumChecker_methods(root_module, root_module['ns3::EnumChecker']) + register_Ns3EnumValue_methods(root_module, root_module['ns3::EnumValue']) + register_Ns3ExponentialVariable_methods(root_module, root_module['ns3::ExponentialVariable']) + register_Ns3IntEmpiricalVariable_methods(root_module, root_module['ns3::IntEmpiricalVariable']) + register_Ns3IntegerValue_methods(root_module, root_module['ns3::IntegerValue']) + register_Ns3LogNormalVariable_methods(root_module, root_module['ns3::LogNormalVariable']) + register_Ns3NormalVariable_methods(root_module, root_module['ns3::NormalVariable']) + register_Ns3Object_methods(root_module, root_module['ns3::Object']) + register_Ns3ObjectAggregateIterator_methods(root_module, root_module['ns3::Object::AggregateIterator']) + register_Ns3ObjectFactoryChecker_methods(root_module, root_module['ns3::ObjectFactoryChecker']) + register_Ns3ObjectFactoryValue_methods(root_module, root_module['ns3::ObjectFactoryValue']) + register_Ns3ObjectVectorAccessor_methods(root_module, root_module['ns3::ObjectVectorAccessor']) + register_Ns3ObjectVectorChecker_methods(root_module, root_module['ns3::ObjectVectorChecker']) + register_Ns3ObjectVectorValue_methods(root_module, root_module['ns3::ObjectVectorValue']) + register_Ns3ParetoVariable_methods(root_module, root_module['ns3::ParetoVariable']) + register_Ns3PointerChecker_methods(root_module, root_module['ns3::PointerChecker']) + register_Ns3PointerValue_methods(root_module, root_module['ns3::PointerValue']) + register_Ns3RandomVariableChecker_methods(root_module, root_module['ns3::RandomVariableChecker']) + register_Ns3RandomVariableValue_methods(root_module, root_module['ns3::RandomVariableValue']) + register_Ns3StringChecker_methods(root_module, root_module['ns3::StringChecker']) + register_Ns3StringValue_methods(root_module, root_module['ns3::StringValue']) + register_Ns3TypeIdChecker_methods(root_module, root_module['ns3::TypeIdChecker']) + register_Ns3TypeIdValue_methods(root_module, root_module['ns3::TypeIdValue']) + register_Ns3UintegerValue_methods(root_module, root_module['ns3::UintegerValue']) + register_Ns3TracedValue__Unsigned_int_methods(root_module, root_module['ns3::TracedValue< unsigned int >']) + register_Ns3ConfigMatchContainer_methods(root_module, root_module['ns3::Config::MatchContainer']) + return + +def register_Ns3AttributeList_methods(root_module, cls): + ## attribute-list.h: ns3::AttributeList::AttributeList() [constructor] + cls.add_constructor([]) + ## attribute-list.h: ns3::AttributeList::AttributeList(ns3::AttributeList const & o) [copy constructor] + cls.add_constructor([param('ns3::AttributeList const &', 'o')]) + ## attribute-list.h: void ns3::AttributeList::Set(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('Set', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## attribute-list.h: bool ns3::AttributeList::SetFailSafe(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetFailSafe', + 'bool', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## attribute-list.h: void ns3::AttributeList::SetWithTid(ns3::TypeId tid, std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetWithTid', + 'void', + [param('ns3::TypeId', 'tid'), param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## attribute-list.h: void ns3::AttributeList::Reset() [member function] + cls.add_method('Reset', + 'void', + []) + ## attribute-list.h: static ns3::AttributeList * ns3::AttributeList::GetGlobal() [member function] + cls.add_method('GetGlobal', + 'ns3::AttributeList *', + [], + is_static=True) + ## attribute-list.h: std::string ns3::AttributeList::SerializeToString() const [member function] + cls.add_method('SerializeToString', + 'std::string', + [], + is_const=True) + ## attribute-list.h: bool ns3::AttributeList::DeserializeFromString(std::string value) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value')]) + return + +def register_Ns3CallbackBase_methods(root_module, cls): + ## callback.h: ns3::CallbackBase::CallbackBase(ns3::CallbackBase const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CallbackBase const &', 'arg0')]) + ## callback.h: ns3::CallbackBase::CallbackBase() [constructor] + cls.add_constructor([]) + ## callback.h: ns3::Ptr ns3::CallbackBase::GetImpl() const [member function] + cls.add_method('GetImpl', + 'ns3::Ptr< ns3::CallbackImplBase >', + [], + is_const=True) + ## callback.h: ns3::CallbackBase::CallbackBase(ns3::Ptr impl) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::CallbackImplBase >', 'impl')], + visibility='protected') + return + +def register_Ns3CallbackImplBase_methods(root_module, cls): + ## callback.h: ns3::CallbackImplBase::CallbackImplBase(ns3::CallbackImplBase const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CallbackImplBase const &', 'arg0')]) + ## callback.h: ns3::CallbackImplBase::CallbackImplBase() [constructor] + cls.add_constructor([]) + ## callback.h: bool ns3::CallbackImplBase::IsEqual(ns3::Ptr other) const [member function] + cls.add_method('IsEqual', + 'bool', + [param('ns3::Ptr< ns3::CallbackImplBase const >', 'other')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3CommandLine_methods(root_module, cls): + ## command-line.h: ns3::CommandLine::CommandLine(ns3::CommandLine const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CommandLine const &', 'arg0')]) + ## command-line.h: ns3::CommandLine::CommandLine() [constructor] + cls.add_constructor([]) + return + +def register_Ns3CriticalSection_methods(root_module, cls): + ## system-mutex.h: ns3::CriticalSection::CriticalSection(ns3::CriticalSection const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CriticalSection const &', 'arg0')]) + ## system-mutex.h: ns3::CriticalSection::CriticalSection(ns3::SystemMutex & mutex) [constructor] + cls.add_constructor([param('ns3::SystemMutex &', 'mutex')]) + return + +def register_Ns3GlobalValue_methods(root_module, cls): + ## global-value.h: ns3::GlobalValue::GlobalValue(ns3::GlobalValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::GlobalValue const &', 'arg0')]) + ## global-value.h: ns3::GlobalValue::GlobalValue(std::string name, std::string help, ns3::AttributeValue const & initialValue, ns3::Ptr checker) [constructor] + cls.add_constructor([param('std::string', 'name'), param('std::string', 'help'), param('ns3::AttributeValue const &', 'initialValue'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')]) + ## global-value.h: std::string ns3::GlobalValue::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_const=True) + ## global-value.h: std::string ns3::GlobalValue::GetHelp() const [member function] + cls.add_method('GetHelp', + 'std::string', + [], + is_const=True) + ## global-value.h: void ns3::GlobalValue::GetValue(ns3::AttributeValue & value) const [member function] + cls.add_method('GetValue', + 'void', + [param('ns3::AttributeValue &', 'value')], + is_const=True) + ## global-value.h: ns3::Ptr ns3::GlobalValue::GetChecker() const [member function] + cls.add_method('GetChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + [], + is_const=True) + ## global-value.h: bool ns3::GlobalValue::SetValue(ns3::AttributeValue const & value) [member function] + cls.add_method('SetValue', + 'bool', + [param('ns3::AttributeValue const &', 'value')]) + ## global-value.h: static void ns3::GlobalValue::Bind(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('Bind', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')], + is_static=True) + ## global-value.h: static bool ns3::GlobalValue::BindFailSafe(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('BindFailSafe', + 'bool', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')], + is_static=True) + ## global-value.h: static __gnu_cxx::__normal_iterator > > ns3::GlobalValue::Begin() [member function] + cls.add_method('Begin', + '__gnu_cxx::__normal_iterator< ns3::GlobalValue * const *, std::vector< ns3::GlobalValue * > >', + [], + is_static=True) + ## global-value.h: static __gnu_cxx::__normal_iterator > > ns3::GlobalValue::End() [member function] + cls.add_method('End', + '__gnu_cxx::__normal_iterator< ns3::GlobalValue * const *, std::vector< ns3::GlobalValue * > >', + [], + is_static=True) + return + +def register_Ns3IntToType__0_methods(root_module, cls): + ## int-to-type.h: ns3::IntToType<0>::IntToType(ns3::IntToType<0> const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntToType< 0 > const &', 'arg0')]) + ## int-to-type.h: ns3::IntToType<0>::IntToType() [constructor] + cls.add_constructor([]) + return + +def register_Ns3IntToType__1_methods(root_module, cls): + ## int-to-type.h: ns3::IntToType<1>::IntToType(ns3::IntToType<1> const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntToType< 1 > const &', 'arg0')]) + ## int-to-type.h: ns3::IntToType<1>::IntToType() [constructor] + cls.add_constructor([]) + return + +def register_Ns3IntToType__2_methods(root_module, cls): + ## int-to-type.h: ns3::IntToType<2>::IntToType(ns3::IntToType<2> const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntToType< 2 > const &', 'arg0')]) + ## int-to-type.h: ns3::IntToType<2>::IntToType() [constructor] + cls.add_constructor([]) + return + +def register_Ns3IntToType__3_methods(root_module, cls): + ## int-to-type.h: ns3::IntToType<3>::IntToType(ns3::IntToType<3> const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntToType< 3 > const &', 'arg0')]) + ## int-to-type.h: ns3::IntToType<3>::IntToType() [constructor] + cls.add_constructor([]) + return + +def register_Ns3IntToType__4_methods(root_module, cls): + ## int-to-type.h: ns3::IntToType<4>::IntToType(ns3::IntToType<4> const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntToType< 4 > const &', 'arg0')]) + ## int-to-type.h: ns3::IntToType<4>::IntToType() [constructor] + cls.add_constructor([]) + return + +def register_Ns3IntToType__5_methods(root_module, cls): + ## int-to-type.h: ns3::IntToType<5>::IntToType(ns3::IntToType<5> const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntToType< 5 > const &', 'arg0')]) + ## int-to-type.h: ns3::IntToType<5>::IntToType() [constructor] + cls.add_constructor([]) + return + +def register_Ns3IntToType__6_methods(root_module, cls): + ## int-to-type.h: ns3::IntToType<6>::IntToType(ns3::IntToType<6> const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntToType< 6 > const &', 'arg0')]) + ## int-to-type.h: ns3::IntToType<6>::IntToType() [constructor] + cls.add_constructor([]) + return + +def register_Ns3ObjectBase_methods(root_module, cls): + ## object-base.h: ns3::ObjectBase::ObjectBase(ns3::ObjectBase const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ObjectBase const &', 'arg0')]) + ## object-base.h: ns3::ObjectBase::ObjectBase() [constructor] + cls.add_constructor([]) + ## object-base.h: static ns3::TypeId ns3::ObjectBase::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## object-base.h: ns3::TypeId ns3::ObjectBase::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## object-base.h: void ns3::ObjectBase::SetAttribute(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## object-base.h: bool ns3::ObjectBase::SetAttributeFailSafe(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetAttributeFailSafe', + 'bool', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## object-base.h: void ns3::ObjectBase::GetAttribute(std::string name, ns3::AttributeValue & value) const [member function] + cls.add_method('GetAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue &', 'value')], + is_const=True) + ## object-base.h: bool ns3::ObjectBase::GetAttributeFailSafe(std::string name, ns3::AttributeValue & attribute) const [member function] + cls.add_method('GetAttributeFailSafe', + 'bool', + [param('std::string', 'name'), param('ns3::AttributeValue &', 'attribute')], + is_const=True) + ## object-base.h: bool ns3::ObjectBase::TraceConnect(std::string name, std::string context, ns3::CallbackBase const & cb) [member function] + cls.add_method('TraceConnect', + 'bool', + [param('std::string', 'name'), param('std::string', 'context'), param('ns3::CallbackBase const &', 'cb')]) + ## object-base.h: bool ns3::ObjectBase::TraceConnectWithoutContext(std::string name, ns3::CallbackBase const & cb) [member function] + cls.add_method('TraceConnectWithoutContext', + 'bool', + [param('std::string', 'name'), param('ns3::CallbackBase const &', 'cb')]) + ## object-base.h: bool ns3::ObjectBase::TraceDisconnect(std::string name, std::string context, ns3::CallbackBase const & cb) [member function] + cls.add_method('TraceDisconnect', + 'bool', + [param('std::string', 'name'), param('std::string', 'context'), param('ns3::CallbackBase const &', 'cb')]) + ## object-base.h: bool ns3::ObjectBase::TraceDisconnectWithoutContext(std::string name, ns3::CallbackBase const & cb) [member function] + cls.add_method('TraceDisconnectWithoutContext', + 'bool', + [param('std::string', 'name'), param('ns3::CallbackBase const &', 'cb')]) + ## object-base.h: void ns3::ObjectBase::NotifyConstructionCompleted() [member function] + cls.add_method('NotifyConstructionCompleted', + 'void', + [], + visibility='protected', is_virtual=True) + ## object-base.h: void ns3::ObjectBase::ConstructSelf(ns3::AttributeList const & attributes) [member function] + cls.add_method('ConstructSelf', + 'void', + [param('ns3::AttributeList const &', 'attributes')], + visibility='protected') + return + +def register_Ns3ObjectFactory_methods(root_module, cls): + cls.add_output_stream_operator() + ## object-factory.h: ns3::ObjectFactory::ObjectFactory(ns3::ObjectFactory const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ObjectFactory const &', 'arg0')]) + ## object-factory.h: ns3::ObjectFactory::ObjectFactory() [constructor] + cls.add_constructor([]) + ## object-factory.h: ns3::Ptr ns3::ObjectFactory::Create() const [member function] + cls.add_method('Create', + 'ns3::Ptr< ns3::Object >', + [], + is_const=True) + ## object-factory.h: ns3::TypeId ns3::ObjectFactory::GetTypeId() const [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_const=True) + ## object-factory.h: void ns3::ObjectFactory::Set(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('Set', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## object-factory.h: void ns3::ObjectFactory::Set(ns3::AttributeList const & list) [member function] + cls.add_method('Set', + 'void', + [param('ns3::AttributeList const &', 'list')]) + ## object-factory.h: void ns3::ObjectFactory::SetTypeId(ns3::TypeId tid) [member function] + cls.add_method('SetTypeId', + 'void', + [param('ns3::TypeId', 'tid')]) + ## object-factory.h: void ns3::ObjectFactory::SetTypeId(char const * tid) [member function] + cls.add_method('SetTypeId', + 'void', + [param('char const *', 'tid')]) + ## object-factory.h: void ns3::ObjectFactory::SetTypeId(std::string tid) [member function] + cls.add_method('SetTypeId', + 'void', + [param('std::string', 'tid')]) + return + +def register_Ns3RandomVariable_methods(root_module, cls): + cls.add_output_stream_operator() + ## random-variable.h: ns3::RandomVariable::RandomVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::RandomVariable::RandomVariable(ns3::RandomVariable const & o) [copy constructor] + cls.add_constructor([param('ns3::RandomVariable const &', 'o')]) + ## random-variable.h: uint32_t ns3::RandomVariable::GetInteger() const [member function] + cls.add_method('GetInteger', + 'uint32_t', + [], + is_const=True) + ## random-variable.h: void ns3::RandomVariable::GetSeed(uint32_t * seed) const [member function] + cls.add_method('GetSeed', + 'void', + [param('uint32_t *', 'seed', direction=2, array_length=6)], + is_const=True) + ## random-variable.h: double ns3::RandomVariable::GetValue() const [member function] + cls.add_method('GetValue', + 'double', + [], + is_const=True) + ## random-variable.h: static void ns3::RandomVariable::SetRunNumber(uint32_t n) [member function] + cls.add_method('SetRunNumber', + 'void', + [param('uint32_t', 'n')], + is_static=True) + ## random-variable.h: static void ns3::RandomVariable::UseDevRandom(bool udr=true) [member function] + cls.add_method('UseDevRandom', + 'void', + [param('bool', 'udr', default_value='true')], + is_static=True) + ## random-variable.h: static void ns3::RandomVariable::UseGlobalSeed(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, uint32_t s4, uint32_t s5) [member function] + cls.add_method('UseGlobalSeed', + 'void', + [param('uint32_t', 's0'), param('uint32_t', 's1'), param('uint32_t', 's2'), param('uint32_t', 's3'), param('uint32_t', 's4'), param('uint32_t', 's5')], + is_static=True) + return + +def register_Ns3RefCountBase_methods(root_module, cls): + ## ref-count-base.h: ns3::RefCountBase::RefCountBase() [constructor] + cls.add_constructor([]) + ## ref-count-base.h: ns3::RefCountBase::RefCountBase(ns3::RefCountBase const & o) [copy constructor] + cls.add_constructor([param('ns3::RefCountBase const &', 'o')]) + return + +def register_Ns3RngStream_methods(root_module, cls): + ## rng-stream.h: ns3::RngStream::RngStream() [constructor] + cls.add_constructor([]) + ## rng-stream.h: ns3::RngStream::RngStream(ns3::RngStream const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RngStream const &', 'arg0')]) + ## rng-stream.h: void ns3::RngStream::InitializeStream() [member function] + cls.add_method('InitializeStream', + 'void', + []) + ## rng-stream.h: void ns3::RngStream::ResetStartStream() [member function] + cls.add_method('ResetStartStream', + 'void', + []) + ## rng-stream.h: void ns3::RngStream::ResetStartSubstream() [member function] + cls.add_method('ResetStartSubstream', + 'void', + []) + ## rng-stream.h: void ns3::RngStream::ResetNextSubstream() [member function] + cls.add_method('ResetNextSubstream', + 'void', + []) + ## rng-stream.h: void ns3::RngStream::ResetNthSubstream(uint32_t N) [member function] + cls.add_method('ResetNthSubstream', + 'void', + [param('uint32_t', 'N')]) + ## rng-stream.h: void ns3::RngStream::SetAntithetic(bool a) [member function] + cls.add_method('SetAntithetic', + 'void', + [param('bool', 'a')]) + ## rng-stream.h: void ns3::RngStream::IncreasedPrecis(bool incp) [member function] + cls.add_method('IncreasedPrecis', + 'void', + [param('bool', 'incp')]) + ## rng-stream.h: bool ns3::RngStream::SetSeeds(uint32_t const * seed) [member function] + cls.add_method('SetSeeds', + 'bool', + [param('uint32_t const *', 'seed')]) + ## rng-stream.h: void ns3::RngStream::AdvanceState(int32_t e, int32_t c) [member function] + cls.add_method('AdvanceState', + 'void', + [param('int32_t', 'e'), param('int32_t', 'c')]) + ## rng-stream.h: void ns3::RngStream::GetState(uint32_t * seed) const [member function] + cls.add_method('GetState', + 'void', + [param('uint32_t *', 'seed')], + is_const=True) + ## rng-stream.h: double ns3::RngStream::RandU01() [member function] + cls.add_method('RandU01', + 'double', + []) + ## rng-stream.h: int32_t ns3::RngStream::RandInt(int32_t i, int32_t j) [member function] + cls.add_method('RandInt', + 'int32_t', + [param('int32_t', 'i'), param('int32_t', 'j')]) + ## rng-stream.h: static bool ns3::RngStream::SetPackageSeed(uint32_t const * seed) [member function] + cls.add_method('SetPackageSeed', + 'bool', + [param('uint32_t const *', 'seed')], + is_static=True) + ## rng-stream.h: static bool ns3::RngStream::CheckSeed(uint32_t const * seed) [member function] + cls.add_method('CheckSeed', + 'bool', + [param('uint32_t const *', 'seed')], + is_static=True) + return + +def register_Ns3SequentialVariable_methods(root_module, cls): + ## random-variable.h: ns3::SequentialVariable::SequentialVariable(ns3::SequentialVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SequentialVariable const &', 'arg0')]) + ## random-variable.h: ns3::SequentialVariable::SequentialVariable(double f, double l, double i=1, uint32_t c=1) [constructor] + cls.add_constructor([param('double', 'f'), param('double', 'l'), param('double', 'i', default_value='1'), param('uint32_t', 'c', default_value='1')]) + ## random-variable.h: ns3::SequentialVariable::SequentialVariable(double f, double l, ns3::RandomVariable const & i, uint32_t c=1) [constructor] + cls.add_constructor([param('double', 'f'), param('double', 'l'), param('ns3::RandomVariable const &', 'i'), param('uint32_t', 'c', default_value='1')]) + return + +def register_Ns3SystemCondition_methods(root_module, cls): + ## system-condition.h: ns3::SystemCondition::SystemCondition(ns3::SystemCondition const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SystemCondition const &', 'arg0')]) + ## system-condition.h: ns3::SystemCondition::SystemCondition() [constructor] + cls.add_constructor([]) + ## system-condition.h: void ns3::SystemCondition::SetCondition(bool condition) [member function] + cls.add_method('SetCondition', + 'void', + [param('bool', 'condition')]) + ## system-condition.h: bool ns3::SystemCondition::GetCondition() [member function] + cls.add_method('GetCondition', + 'bool', + []) + ## system-condition.h: void ns3::SystemCondition::Signal() [member function] + cls.add_method('Signal', + 'void', + []) + ## system-condition.h: void ns3::SystemCondition::Broadcast() [member function] + cls.add_method('Broadcast', + 'void', + []) + ## system-condition.h: void ns3::SystemCondition::Wait() [member function] + cls.add_method('Wait', + 'void', + []) + ## system-condition.h: bool ns3::SystemCondition::TimedWait(uint64_t ns) [member function] + cls.add_method('TimedWait', + 'bool', + [param('uint64_t', 'ns')]) + return + +def register_Ns3SystemMutex_methods(root_module, cls): + ## system-mutex.h: ns3::SystemMutex::SystemMutex(ns3::SystemMutex const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SystemMutex const &', 'arg0')]) + ## system-mutex.h: ns3::SystemMutex::SystemMutex() [constructor] + cls.add_constructor([]) + ## system-mutex.h: void ns3::SystemMutex::Lock() [member function] + cls.add_method('Lock', + 'void', + []) + ## system-mutex.h: void ns3::SystemMutex::Unlock() [member function] + cls.add_method('Unlock', + 'void', + []) + return + +def register_Ns3SystemThread_methods(root_module, cls): + ## system-thread.h: ns3::SystemThread::SystemThread(ns3::SystemThread const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SystemThread const &', 'arg0')]) + ## system-thread.h: ns3::SystemThread::SystemThread(ns3::Callback callback) [constructor] + cls.add_constructor([param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')]) + ## system-thread.h: void ns3::SystemThread::Ref() const [member function] + cls.add_method('Ref', + 'void', + [], + is_const=True) + ## system-thread.h: void ns3::SystemThread::Unref() const [member function] + cls.add_method('Unref', + 'void', + [], + is_const=True) + ## system-thread.h: void ns3::SystemThread::Start() [member function] + cls.add_method('Start', + 'void', + []) + ## system-thread.h: void ns3::SystemThread::Join() [member function] + cls.add_method('Join', + 'void', + []) + ## system-thread.h: void ns3::SystemThread::Shutdown() [member function] + cls.add_method('Shutdown', + 'void', + []) + ## system-thread.h: bool ns3::SystemThread::Break() [member function] + cls.add_method('Break', + 'bool', + []) + return + +def register_Ns3SystemWallClockMs_methods(root_module, cls): + ## system-wall-clock-ms.h: ns3::SystemWallClockMs::SystemWallClockMs(ns3::SystemWallClockMs const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SystemWallClockMs const &', 'arg0')]) + ## system-wall-clock-ms.h: ns3::SystemWallClockMs::SystemWallClockMs() [constructor] + cls.add_constructor([]) + ## system-wall-clock-ms.h: void ns3::SystemWallClockMs::Start() [member function] + cls.add_method('Start', + 'void', + []) + ## system-wall-clock-ms.h: long long unsigned int ns3::SystemWallClockMs::End() [member function] + cls.add_method('End', + 'long long unsigned int', + []) + return + +def register_Ns3TraceSourceAccessor_methods(root_module, cls): + ## trace-source-accessor.h: ns3::TraceSourceAccessor::TraceSourceAccessor(ns3::TraceSourceAccessor const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TraceSourceAccessor const &', 'arg0')]) + ## trace-source-accessor.h: ns3::TraceSourceAccessor::TraceSourceAccessor() [constructor] + cls.add_constructor([]) + ## trace-source-accessor.h: void ns3::TraceSourceAccessor::Ref() const [member function] + cls.add_method('Ref', + 'void', + [], + is_const=True) + ## trace-source-accessor.h: void ns3::TraceSourceAccessor::Unref() const [member function] + cls.add_method('Unref', + 'void', + [], + is_const=True) + ## trace-source-accessor.h: bool ns3::TraceSourceAccessor::ConnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function] + cls.add_method('ConnectWithoutContext', + 'bool', + [param('ns3::ObjectBase *', 'obj', transfer_ownership=False), param('ns3::CallbackBase const &', 'cb')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## trace-source-accessor.h: bool ns3::TraceSourceAccessor::Connect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function] + cls.add_method('Connect', + 'bool', + [param('ns3::ObjectBase *', 'obj', transfer_ownership=False), param('std::string', 'context'), param('ns3::CallbackBase const &', 'cb')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## trace-source-accessor.h: bool ns3::TraceSourceAccessor::DisconnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function] + cls.add_method('DisconnectWithoutContext', + 'bool', + [param('ns3::ObjectBase *', 'obj', transfer_ownership=False), param('ns3::CallbackBase const &', 'cb')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## trace-source-accessor.h: bool ns3::TraceSourceAccessor::Disconnect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function] + cls.add_method('Disconnect', + 'bool', + [param('ns3::ObjectBase *', 'obj', transfer_ownership=False), param('std::string', 'context'), param('ns3::CallbackBase const &', 'cb')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3TriangularVariable_methods(root_module, cls): + ## random-variable.h: ns3::TriangularVariable::TriangularVariable(ns3::TriangularVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TriangularVariable const &', 'arg0')]) + ## random-variable.h: ns3::TriangularVariable::TriangularVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::TriangularVariable::TriangularVariable(double s, double l, double mean) [constructor] + cls.add_constructor([param('double', 's'), param('double', 'l'), param('double', 'mean')]) + ## random-variable.h: static double ns3::TriangularVariable::GetSingleValue(double s, double l, double mean) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 's'), param('double', 'l'), param('double', 'mean')], + is_static=True) + return + +def register_Ns3TypeId_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_binary_comparison_operator('<') + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('==') + ## type-id.h: ns3::TypeId::TypeId(ns3::TypeId const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TypeId const &', 'arg0')]) + ## type-id.h: ns3::TypeId::TypeId(char const * name) [constructor] + cls.add_constructor([param('char const *', 'name')]) + ## type-id.h: ns3::TypeId::TypeId() [constructor] + cls.add_constructor([]) + ## type-id.h: ns3::TypeId ns3::TypeId::AddAttribute(std::string name, std::string help, ns3::AttributeValue const & initialValue, ns3::Ptr accessor, ns3::Ptr checker) [member function] + cls.add_method('AddAttribute', + 'ns3::TypeId', + [param('std::string', 'name'), param('std::string', 'help'), param('ns3::AttributeValue const &', 'initialValue'), param('ns3::Ptr< ns3::AttributeAccessor const >', 'accessor'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')]) + ## type-id.h: ns3::TypeId ns3::TypeId::AddAttribute(std::string name, std::string help, uint32_t flags, ns3::AttributeValue const & initialValue, ns3::Ptr accessor, ns3::Ptr checker) [member function] + cls.add_method('AddAttribute', + 'ns3::TypeId', + [param('std::string', 'name'), param('std::string', 'help'), param('uint32_t', 'flags'), param('ns3::AttributeValue const &', 'initialValue'), param('ns3::Ptr< ns3::AttributeAccessor const >', 'accessor'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')]) + ## type-id.h: ns3::TypeId ns3::TypeId::AddTraceSource(std::string name, std::string help, ns3::Ptr accessor) [member function] + cls.add_method('AddTraceSource', + 'ns3::TypeId', + [param('std::string', 'name'), param('std::string', 'help'), param('ns3::Ptr< ns3::TraceSourceAccessor const >', 'accessor')]) + ## type-id.h: ns3::Ptr ns3::TypeId::GetAttributeAccessor(uint32_t i) const [member function] + cls.add_method('GetAttributeAccessor', + 'ns3::Ptr< ns3::AttributeAccessor const >', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: ns3::Ptr ns3::TypeId::GetAttributeChecker(uint32_t i) const [member function] + cls.add_method('GetAttributeChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: uint32_t ns3::TypeId::GetAttributeFlags(uint32_t i) const [member function] + cls.add_method('GetAttributeFlags', + 'uint32_t', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: std::string ns3::TypeId::GetAttributeFullName(uint32_t i) const [member function] + cls.add_method('GetAttributeFullName', + 'std::string', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: std::string ns3::TypeId::GetAttributeHelp(uint32_t i) const [member function] + cls.add_method('GetAttributeHelp', + 'std::string', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: ns3::Ptr ns3::TypeId::GetAttributeInitialValue(uint32_t i) const [member function] + cls.add_method('GetAttributeInitialValue', + 'ns3::Ptr< ns3::AttributeValue const >', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: uint32_t ns3::TypeId::GetAttributeN() const [member function] + cls.add_method('GetAttributeN', + 'uint32_t', + [], + is_const=True) + ## type-id.h: std::string ns3::TypeId::GetAttributeName(uint32_t i) const [member function] + cls.add_method('GetAttributeName', + 'std::string', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: ns3::Callback ns3::TypeId::GetConstructor() const [member function] + cls.add_method('GetConstructor', + 'ns3::Callback< ns3::ObjectBase *, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', + [], + is_const=True) + ## type-id.h: std::string ns3::TypeId::GetGroupName() const [member function] + cls.add_method('GetGroupName', + 'std::string', + [], + is_const=True) + ## type-id.h: std::string ns3::TypeId::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_const=True) + ## type-id.h: ns3::TypeId ns3::TypeId::GetParent() const [member function] + cls.add_method('GetParent', + 'ns3::TypeId', + [], + is_const=True) + ## type-id.h: static ns3::TypeId ns3::TypeId::GetRegistered(uint32_t i) [member function] + cls.add_method('GetRegistered', + 'ns3::TypeId', + [param('uint32_t', 'i')], + is_static=True) + ## type-id.h: static uint32_t ns3::TypeId::GetRegisteredN() [member function] + cls.add_method('GetRegisteredN', + 'uint32_t', + [], + is_static=True) + ## type-id.h: ns3::Ptr ns3::TypeId::GetTraceSourceAccessor(uint32_t i) const [member function] + cls.add_method('GetTraceSourceAccessor', + 'ns3::Ptr< ns3::TraceSourceAccessor const >', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: std::string ns3::TypeId::GetTraceSourceHelp(uint32_t i) const [member function] + cls.add_method('GetTraceSourceHelp', + 'std::string', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: uint32_t ns3::TypeId::GetTraceSourceN() const [member function] + cls.add_method('GetTraceSourceN', + 'uint32_t', + [], + is_const=True) + ## type-id.h: std::string ns3::TypeId::GetTraceSourceName(uint32_t i) const [member function] + cls.add_method('GetTraceSourceName', + 'std::string', + [param('uint32_t', 'i')], + is_const=True) + ## type-id.h: uint16_t ns3::TypeId::GetUid() const [member function] + cls.add_method('GetUid', + 'uint16_t', + [], + is_const=True) + ## type-id.h: bool ns3::TypeId::HasConstructor() const [member function] + cls.add_method('HasConstructor', + 'bool', + [], + is_const=True) + ## type-id.h: bool ns3::TypeId::HasParent() const [member function] + cls.add_method('HasParent', + 'bool', + [], + is_const=True) + ## type-id.h: ns3::TypeId ns3::TypeId::HideFromDocumentation() [member function] + cls.add_method('HideFromDocumentation', + 'ns3::TypeId', + []) + ## type-id.h: bool ns3::TypeId::IsChildOf(ns3::TypeId other) const [member function] + cls.add_method('IsChildOf', + 'bool', + [param('ns3::TypeId', 'other')], + is_const=True) + ## type-id.h: bool ns3::TypeId::LookupAttributeByName(std::string name, ns3::TypeId::AttributeInfo * info) const [member function] + cls.add_method('LookupAttributeByName', + 'bool', + [param('std::string', 'name'), param('ns3::TypeId::AttributeInfo *', 'info', transfer_ownership=False)], + is_const=True) + ## type-id.h: static ns3::TypeId ns3::TypeId::LookupByName(std::string name) [member function] + cls.add_method('LookupByName', + 'ns3::TypeId', + [param('std::string', 'name')], + is_static=True) + ## type-id.h: ns3::Ptr ns3::TypeId::LookupTraceSourceByName(std::string name) const [member function] + cls.add_method('LookupTraceSourceByName', + 'ns3::Ptr< ns3::TraceSourceAccessor const >', + [param('std::string', 'name')], + is_const=True) + ## type-id.h: bool ns3::TypeId::MustHideFromDocumentation() const [member function] + cls.add_method('MustHideFromDocumentation', + 'bool', + [], + is_const=True) + ## type-id.h: ns3::TypeId ns3::TypeId::SetGroupName(std::string groupName) [member function] + cls.add_method('SetGroupName', + 'ns3::TypeId', + [param('std::string', 'groupName')]) + ## type-id.h: ns3::TypeId ns3::TypeId::SetParent(ns3::TypeId tid) [member function] + cls.add_method('SetParent', + 'ns3::TypeId', + [param('ns3::TypeId', 'tid')]) + ## type-id.h: void ns3::TypeId::SetUid(uint16_t tid) [member function] + cls.add_method('SetUid', + 'void', + [param('uint16_t', 'tid')]) + return + +def register_Ns3TypeIdAttributeInfo_methods(root_module, cls): + ## type-id.h: ns3::TypeId::AttributeInfo::accessor [variable] + cls.add_instance_attribute('accessor', 'ns3::Ptr< ns3::AttributeAccessor const >', is_const=False) + ## type-id.h: ns3::TypeId::AttributeInfo::initialValue [variable] + cls.add_instance_attribute('initialValue', 'ns3::Ptr< ns3::AttributeValue const >', is_const=False) + ## type-id.h: ns3::TypeId::AttributeInfo::flags [variable] + cls.add_instance_attribute('flags', 'uint32_t', is_const=False) + ## type-id.h: ns3::TypeId::AttributeInfo::checker [variable] + cls.add_instance_attribute('checker', 'ns3::Ptr< ns3::AttributeChecker const >', is_const=False) + ## type-id.h: ns3::TypeId::AttributeInfo::AttributeInfo(ns3::TypeId::AttributeInfo const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TypeId::AttributeInfo const &', 'arg0')]) + ## type-id.h: ns3::TypeId::AttributeInfo::AttributeInfo() [constructor] + cls.add_constructor([]) + return + +def register_Ns3UniformVariable_methods(root_module, cls): + ## random-variable.h: ns3::UniformVariable::UniformVariable(ns3::UniformVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UniformVariable const &', 'arg0')]) + ## random-variable.h: ns3::UniformVariable::UniformVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::UniformVariable::UniformVariable(double s, double l) [constructor] + cls.add_constructor([param('double', 's'), param('double', 'l')]) + ## random-variable.h: static double ns3::UniformVariable::GetSingleValue(double s, double l) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 's'), param('double', 'l')], + is_static=True) + return + +def register_Ns3UnsafeAttributeList_methods(root_module, cls): + ## attribute-list.h: ns3::UnsafeAttributeList::UnsafeAttributeList() [constructor] + cls.add_constructor([]) + ## attribute-list.h: ns3::UnsafeAttributeList::UnsafeAttributeList(ns3::UnsafeAttributeList const & o) [copy constructor] + cls.add_constructor([param('ns3::UnsafeAttributeList const &', 'o')]) + ## attribute-list.h: void ns3::UnsafeAttributeList::Set(std::string name, ns3::AttributeValue const & param) [member function] + cls.add_method('Set', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'param')]) + ## attribute-list.h: ns3::AttributeList ns3::UnsafeAttributeList::GetSafe(std::string name) const [member function] + cls.add_method('GetSafe', + 'ns3::AttributeList', + [param('std::string', 'name')], + is_const=True) + return + +def register_Ns3WeibullVariable_methods(root_module, cls): + ## random-variable.h: ns3::WeibullVariable::WeibullVariable(ns3::WeibullVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WeibullVariable const &', 'arg0')]) + ## random-variable.h: ns3::WeibullVariable::WeibullVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::WeibullVariable::WeibullVariable(double m) [constructor] + cls.add_constructor([param('double', 'm')]) + ## random-variable.h: ns3::WeibullVariable::WeibullVariable(double m, double s) [constructor] + cls.add_constructor([param('double', 'm'), param('double', 's')]) + ## random-variable.h: ns3::WeibullVariable::WeibullVariable(double m, double s, double b) [constructor] + cls.add_constructor([param('double', 'm'), param('double', 's'), param('double', 'b')]) + ## random-variable.h: static double ns3::WeibullVariable::GetSingleValue(double m, double s, double b=0) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 'm'), param('double', 's'), param('double', 'b', default_value='0')], + is_static=True) + return + +def register_Ns3Empty_methods(root_module, cls): + ## empty.h: ns3::empty::empty(ns3::empty const & arg0) [copy constructor] + cls.add_constructor([param('ns3::empty const &', 'arg0')]) + ## empty.h: ns3::empty::empty() [constructor] + cls.add_constructor([]) + return + +def register_Ns3AttributeAccessor_methods(root_module, cls): + ## attribute.h: ns3::AttributeAccessor::AttributeAccessor(ns3::AttributeAccessor const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AttributeAccessor const &', 'arg0')]) + ## attribute.h: ns3::AttributeAccessor::AttributeAccessor() [constructor] + cls.add_constructor([]) + ## attribute.h: bool ns3::AttributeAccessor::Set(ns3::ObjectBase * object, ns3::AttributeValue const & value) const [member function] + cls.add_method('Set', + 'bool', + [param('ns3::ObjectBase *', 'object', transfer_ownership=False), param('ns3::AttributeValue const &', 'value')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: bool ns3::AttributeAccessor::Get(ns3::ObjectBase const * object, ns3::AttributeValue & attribute) const [member function] + cls.add_method('Get', + 'bool', + [param('ns3::ObjectBase const *', 'object'), param('ns3::AttributeValue &', 'attribute')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: bool ns3::AttributeAccessor::HasGetter() const [member function] + cls.add_method('HasGetter', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: bool ns3::AttributeAccessor::HasSetter() const [member function] + cls.add_method('HasSetter', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3AttributeChecker_methods(root_module, cls): + ## attribute.h: ns3::AttributeChecker::AttributeChecker(ns3::AttributeChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AttributeChecker const &', 'arg0')]) + ## attribute.h: ns3::AttributeChecker::AttributeChecker() [constructor] + cls.add_constructor([]) + ## attribute.h: bool ns3::AttributeChecker::Check(ns3::AttributeValue const & value) const [member function] + cls.add_method('Check', + 'bool', + [param('ns3::AttributeValue const &', 'value')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: std::string ns3::AttributeChecker::GetValueTypeName() const [member function] + cls.add_method('GetValueTypeName', + 'std::string', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: bool ns3::AttributeChecker::HasUnderlyingTypeInformation() const [member function] + cls.add_method('HasUnderlyingTypeInformation', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: std::string ns3::AttributeChecker::GetUnderlyingTypeInformation() const [member function] + cls.add_method('GetUnderlyingTypeInformation', + 'std::string', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: ns3::Ptr ns3::AttributeChecker::Create() const [member function] + cls.add_method('Create', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: bool ns3::AttributeChecker::Copy(ns3::AttributeValue const & source, ns3::AttributeValue & destination) const [member function] + cls.add_method('Copy', + 'bool', + [param('ns3::AttributeValue const &', 'source'), param('ns3::AttributeValue &', 'destination')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3AttributeValue_methods(root_module, cls): + ## attribute.h: ns3::AttributeValue::AttributeValue(ns3::AttributeValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AttributeValue const &', 'arg0')]) + ## attribute.h: ns3::AttributeValue::AttributeValue() [constructor] + cls.add_constructor([]) + ## attribute.h: ns3::Ptr ns3::AttributeValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: std::string ns3::AttributeValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## attribute.h: bool ns3::AttributeValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3BooleanChecker_methods(root_module, cls): + ## boolean.h: ns3::BooleanChecker::BooleanChecker(ns3::BooleanChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::BooleanChecker const &', 'arg0')]) + ## boolean.h: ns3::BooleanChecker::BooleanChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3BooleanValue_methods(root_module, cls): + cls.add_output_stream_operator() + ## boolean.h: ns3::BooleanValue::BooleanValue(ns3::BooleanValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::BooleanValue const &', 'arg0')]) + ## boolean.h: ns3::BooleanValue::BooleanValue() [constructor] + cls.add_constructor([]) + ## boolean.h: ns3::BooleanValue::BooleanValue(bool value) [constructor] + cls.add_constructor([param('bool', 'value')]) + ## boolean.h: ns3::Ptr ns3::BooleanValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## boolean.h: bool ns3::BooleanValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + ## boolean.h: bool ns3::BooleanValue::Get() const [member function] + cls.add_method('Get', + 'bool', + [], + is_const=True) + ## boolean.h: std::string ns3::BooleanValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## boolean.h: void ns3::BooleanValue::Set(bool value) [member function] + cls.add_method('Set', + 'void', + [param('bool', 'value')]) + return + +def register_Ns3CallbackChecker_methods(root_module, cls): + ## callback.h: ns3::CallbackChecker::CallbackChecker(ns3::CallbackChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CallbackChecker const &', 'arg0')]) + ## callback.h: ns3::CallbackChecker::CallbackChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3CallbackValue_methods(root_module, cls): + ## callback.h: ns3::CallbackValue::CallbackValue(ns3::CallbackValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CallbackValue const &', 'arg0')]) + ## callback.h: ns3::CallbackValue::CallbackValue() [constructor] + cls.add_constructor([]) + ## callback.h: ns3::CallbackValue::CallbackValue(ns3::CallbackBase const & base) [constructor] + cls.add_constructor([param('ns3::CallbackBase const &', 'base')]) + ## callback.h: void ns3::CallbackValue::Set(ns3::CallbackBase base) [member function] + cls.add_method('Set', + 'void', + [param('ns3::CallbackBase', 'base')]) + ## callback.h: ns3::Ptr ns3::CallbackValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## callback.h: std::string ns3::CallbackValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## callback.h: bool ns3::CallbackValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3ConstantVariable_methods(root_module, cls): + ## random-variable.h: ns3::ConstantVariable::ConstantVariable(ns3::ConstantVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ConstantVariable const &', 'arg0')]) + ## random-variable.h: ns3::ConstantVariable::ConstantVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::ConstantVariable::ConstantVariable(double c) [constructor] + cls.add_constructor([param('double', 'c')]) + ## random-variable.h: void ns3::ConstantVariable::SetConstant(double c) [member function] + cls.add_method('SetConstant', + 'void', + [param('double', 'c')]) + return + +def register_Ns3DeterministicVariable_methods(root_module, cls): + ## random-variable.h: ns3::DeterministicVariable::DeterministicVariable(ns3::DeterministicVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DeterministicVariable const &', 'arg0')]) + ## random-variable.h: ns3::DeterministicVariable::DeterministicVariable(double * d, uint32_t c) [constructor] + cls.add_constructor([param('double *', 'd'), param('uint32_t', 'c')]) + return + +def register_Ns3DoubleValue_methods(root_module, cls): + ## double.h: ns3::DoubleValue::DoubleValue(ns3::DoubleValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DoubleValue const &', 'arg0')]) + ## double.h: ns3::DoubleValue::DoubleValue() [constructor] + cls.add_constructor([]) + ## double.h: ns3::DoubleValue::DoubleValue(double const & value) [constructor] + cls.add_constructor([param('double const &', 'value')]) + ## double.h: void ns3::DoubleValue::Set(double const & value) [member function] + cls.add_method('Set', + 'void', + [param('double const &', 'value')]) + ## double.h: double ns3::DoubleValue::Get() const [member function] + cls.add_method('Get', + 'double', + [], + is_const=True) + ## double.h: ns3::Ptr ns3::DoubleValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## double.h: std::string ns3::DoubleValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## double.h: bool ns3::DoubleValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3EmpiricalVariable_methods(root_module, cls): + ## random-variable.h: ns3::EmpiricalVariable::EmpiricalVariable(ns3::EmpiricalVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EmpiricalVariable const &', 'arg0')]) + ## random-variable.h: ns3::EmpiricalVariable::EmpiricalVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: void ns3::EmpiricalVariable::CDF(double v, double c) [member function] + cls.add_method('CDF', + 'void', + [param('double', 'v'), param('double', 'c')]) + return + +def register_Ns3EmptyAttributeValue_methods(root_module, cls): + ## attribute.h: ns3::EmptyAttributeValue::EmptyAttributeValue(ns3::EmptyAttributeValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EmptyAttributeValue const &', 'arg0')]) + ## attribute.h: ns3::EmptyAttributeValue::EmptyAttributeValue() [constructor] + cls.add_constructor([]) + ## attribute.h: ns3::Ptr ns3::EmptyAttributeValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, visibility='private', is_virtual=True) + ## attribute.h: std::string ns3::EmptyAttributeValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, visibility='private', is_virtual=True) + ## attribute.h: bool ns3::EmptyAttributeValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + visibility='private', is_virtual=True) + return + +def register_Ns3EnumChecker_methods(root_module, cls): + ## enum.h: ns3::EnumChecker::EnumChecker(ns3::EnumChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EnumChecker const &', 'arg0')]) + ## enum.h: ns3::EnumChecker::EnumChecker() [constructor] + cls.add_constructor([]) + ## enum.h: void ns3::EnumChecker::AddDefault(int v, std::string name) [member function] + cls.add_method('AddDefault', + 'void', + [param('int', 'v'), param('std::string', 'name')]) + ## enum.h: void ns3::EnumChecker::Add(int v, std::string name) [member function] + cls.add_method('Add', + 'void', + [param('int', 'v'), param('std::string', 'name')]) + ## enum.h: bool ns3::EnumChecker::Check(ns3::AttributeValue const & value) const [member function] + cls.add_method('Check', + 'bool', + [param('ns3::AttributeValue const &', 'value')], + is_const=True, is_virtual=True) + ## enum.h: std::string ns3::EnumChecker::GetValueTypeName() const [member function] + cls.add_method('GetValueTypeName', + 'std::string', + [], + is_const=True, is_virtual=True) + ## enum.h: bool ns3::EnumChecker::HasUnderlyingTypeInformation() const [member function] + cls.add_method('HasUnderlyingTypeInformation', + 'bool', + [], + is_const=True, is_virtual=True) + ## enum.h: std::string ns3::EnumChecker::GetUnderlyingTypeInformation() const [member function] + cls.add_method('GetUnderlyingTypeInformation', + 'std::string', + [], + is_const=True, is_virtual=True) + ## enum.h: ns3::Ptr ns3::EnumChecker::Create() const [member function] + cls.add_method('Create', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## enum.h: bool ns3::EnumChecker::Copy(ns3::AttributeValue const & src, ns3::AttributeValue & dst) const [member function] + cls.add_method('Copy', + 'bool', + [param('ns3::AttributeValue const &', 'src'), param('ns3::AttributeValue &', 'dst')], + is_const=True, is_virtual=True) + return + +def register_Ns3EnumValue_methods(root_module, cls): + ## enum.h: ns3::EnumValue::EnumValue(ns3::EnumValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EnumValue const &', 'arg0')]) + ## enum.h: ns3::EnumValue::EnumValue() [constructor] + cls.add_constructor([]) + ## enum.h: ns3::EnumValue::EnumValue(int v) [constructor] + cls.add_constructor([param('int', 'v')]) + ## enum.h: void ns3::EnumValue::Set(int v) [member function] + cls.add_method('Set', + 'void', + [param('int', 'v')]) + ## enum.h: int ns3::EnumValue::Get() const [member function] + cls.add_method('Get', + 'int', + [], + is_const=True) + ## enum.h: ns3::Ptr ns3::EnumValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## enum.h: std::string ns3::EnumValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## enum.h: bool ns3::EnumValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3ExponentialVariable_methods(root_module, cls): + ## random-variable.h: ns3::ExponentialVariable::ExponentialVariable(ns3::ExponentialVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ExponentialVariable const &', 'arg0')]) + ## random-variable.h: ns3::ExponentialVariable::ExponentialVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::ExponentialVariable::ExponentialVariable(double m) [constructor] + cls.add_constructor([param('double', 'm')]) + ## random-variable.h: ns3::ExponentialVariable::ExponentialVariable(double m, double b) [constructor] + cls.add_constructor([param('double', 'm'), param('double', 'b')]) + ## random-variable.h: static double ns3::ExponentialVariable::GetSingleValue(double m, double b=0) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 'm'), param('double', 'b', default_value='0')], + is_static=True) + return + +def register_Ns3IntEmpiricalVariable_methods(root_module, cls): + ## random-variable.h: ns3::IntEmpiricalVariable::IntEmpiricalVariable(ns3::IntEmpiricalVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntEmpiricalVariable const &', 'arg0')]) + ## random-variable.h: ns3::IntEmpiricalVariable::IntEmpiricalVariable() [constructor] + cls.add_constructor([]) + return + +def register_Ns3IntegerValue_methods(root_module, cls): + ## integer.h: ns3::IntegerValue::IntegerValue(ns3::IntegerValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IntegerValue const &', 'arg0')]) + ## integer.h: ns3::IntegerValue::IntegerValue() [constructor] + cls.add_constructor([]) + ## integer.h: ns3::IntegerValue::IntegerValue(int64_t const & value) [constructor] + cls.add_constructor([param('int64_t const &', 'value')]) + ## integer.h: void ns3::IntegerValue::Set(int64_t const & value) [member function] + cls.add_method('Set', + 'void', + [param('int64_t const &', 'value')]) + ## integer.h: int64_t ns3::IntegerValue::Get() const [member function] + cls.add_method('Get', + 'int64_t', + [], + is_const=True) + ## integer.h: ns3::Ptr ns3::IntegerValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## integer.h: std::string ns3::IntegerValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## integer.h: bool ns3::IntegerValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3LogNormalVariable_methods(root_module, cls): + ## random-variable.h: ns3::LogNormalVariable::LogNormalVariable(ns3::LogNormalVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::LogNormalVariable const &', 'arg0')]) + ## random-variable.h: ns3::LogNormalVariable::LogNormalVariable(double mu, double sigma) [constructor] + cls.add_constructor([param('double', 'mu'), param('double', 'sigma')]) + ## random-variable.h: static double ns3::LogNormalVariable::GetSingleValue(double mu, double sigma) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 'mu'), param('double', 'sigma')], + is_static=True) + return + +def register_Ns3NormalVariable_methods(root_module, cls): + ## random-variable.h: ns3::NormalVariable::NormalVariable(ns3::NormalVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::NormalVariable const &', 'arg0')]) + ## random-variable.h: ns3::NormalVariable::NormalVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::NormalVariable::NormalVariable(double m, double v) [constructor] + cls.add_constructor([param('double', 'm'), param('double', 'v')]) + ## random-variable.h: ns3::NormalVariable::NormalVariable(double m, double v, double b) [constructor] + cls.add_constructor([param('double', 'm'), param('double', 'v'), param('double', 'b')]) + ## random-variable.h: static double ns3::NormalVariable::GetSingleValue(double m, double v) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 'm'), param('double', 'v')], + is_static=True) + ## random-variable.h: static double ns3::NormalVariable::GetSingleValue(double m, double v, double b) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 'm'), param('double', 'v'), param('double', 'b')], + is_static=True) + return + +def register_Ns3Object_methods(root_module, cls): + ## object.h: static ns3::TypeId ns3::Object::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## object.h: ns3::Object::Object() [constructor] + cls.add_constructor([]) + ## object.h: ns3::TypeId ns3::Object::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## object.h: ns3::Ptr ns3::Object::GetObject(ns3::TypeId tid) const [member function] + cls.add_method('GetObject', + 'ns3::Ptr< ns3::Object >', + [param('ns3::TypeId', 'tid')], + is_const=True, template_parameters=['ns3::Object'], custom_template_method_name='GetObject') + ## object.h: void ns3::Object::Dispose() [member function] + cls.add_method('Dispose', + 'void', + []) + ## object.h: void ns3::Object::AggregateObject(ns3::Ptr other) [member function] + cls.add_method('AggregateObject', + 'void', + [param('ns3::Ptr< ns3::Object >', 'other')]) + ## object.h: ns3::Object::AggregateIterator ns3::Object::GetAggregateIterator() const [member function] + cls.add_method('GetAggregateIterator', + 'ns3::Object::AggregateIterator', + [], + is_const=True) + ## object.h: void ns3::Object::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## object.h: ns3::Object::Object(ns3::Object const & o) [copy constructor] + cls.add_constructor([param('ns3::Object const &', 'o')], + visibility='protected') + return + +def register_Ns3ObjectAggregateIterator_methods(root_module, cls): + ## object.h: ns3::Object::AggregateIterator::AggregateIterator(ns3::Object::AggregateIterator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Object::AggregateIterator const &', 'arg0')]) + ## object.h: ns3::Object::AggregateIterator::AggregateIterator() [constructor] + cls.add_constructor([]) + ## object.h: bool ns3::Object::AggregateIterator::HasNext() const [member function] + cls.add_method('HasNext', + 'bool', + [], + is_const=True) + ## object.h: ns3::Ptr ns3::Object::AggregateIterator::Next() [member function] + cls.add_method('Next', + 'ns3::Ptr< ns3::Object const >', + []) + return + +def register_Ns3ObjectFactoryChecker_methods(root_module, cls): + ## object-factory.h: ns3::ObjectFactoryChecker::ObjectFactoryChecker(ns3::ObjectFactoryChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ObjectFactoryChecker const &', 'arg0')]) + ## object-factory.h: ns3::ObjectFactoryChecker::ObjectFactoryChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3ObjectFactoryValue_methods(root_module, cls): + ## object-factory.h: ns3::ObjectFactoryValue::ObjectFactoryValue(ns3::ObjectFactoryValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ObjectFactoryValue const &', 'arg0')]) + ## object-factory.h: ns3::ObjectFactoryValue::ObjectFactoryValue() [constructor] + cls.add_constructor([]) + ## object-factory.h: ns3::ObjectFactoryValue::ObjectFactoryValue(ns3::ObjectFactory const & value) [constructor] + cls.add_constructor([param('ns3::ObjectFactory const &', 'value')]) + ## object-factory.h: void ns3::ObjectFactoryValue::Set(ns3::ObjectFactory const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::ObjectFactory const &', 'value')]) + ## object-factory.h: ns3::ObjectFactory ns3::ObjectFactoryValue::Get() const [member function] + cls.add_method('Get', + 'ns3::ObjectFactory', + [], + is_const=True) + ## object-factory.h: ns3::Ptr ns3::ObjectFactoryValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## object-factory.h: std::string ns3::ObjectFactoryValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## object-factory.h: bool ns3::ObjectFactoryValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3ObjectVectorAccessor_methods(root_module, cls): + ## object-vector.h: ns3::ObjectVectorAccessor::ObjectVectorAccessor(ns3::ObjectVectorAccessor const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ObjectVectorAccessor const &', 'arg0')]) + ## object-vector.h: ns3::ObjectVectorAccessor::ObjectVectorAccessor() [constructor] + cls.add_constructor([]) + ## object-vector.h: bool ns3::ObjectVectorAccessor::Set(ns3::ObjectBase * object, ns3::AttributeValue const & value) const [member function] + cls.add_method('Set', + 'bool', + [param('ns3::ObjectBase *', 'object'), param('ns3::AttributeValue const &', 'value')], + is_const=True, is_virtual=True) + ## object-vector.h: bool ns3::ObjectVectorAccessor::Get(ns3::ObjectBase const * object, ns3::AttributeValue & value) const [member function] + cls.add_method('Get', + 'bool', + [param('ns3::ObjectBase const *', 'object'), param('ns3::AttributeValue &', 'value')], + is_const=True, is_virtual=True) + ## object-vector.h: bool ns3::ObjectVectorAccessor::HasGetter() const [member function] + cls.add_method('HasGetter', + 'bool', + [], + is_const=True, is_virtual=True) + ## object-vector.h: bool ns3::ObjectVectorAccessor::HasSetter() const [member function] + cls.add_method('HasSetter', + 'bool', + [], + is_const=True, is_virtual=True) + ## object-vector.h: bool ns3::ObjectVectorAccessor::DoGetN(ns3::ObjectBase const * object, uint32_t * n) const [member function] + cls.add_method('DoGetN', + 'bool', + [param('ns3::ObjectBase const *', 'object'), param('uint32_t *', 'n')], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## object-vector.h: ns3::Ptr ns3::ObjectVectorAccessor::DoGet(ns3::ObjectBase const * object, uint32_t i) const [member function] + cls.add_method('DoGet', + 'ns3::Ptr< ns3::Object >', + [param('ns3::ObjectBase const *', 'object'), param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3ObjectVectorChecker_methods(root_module, cls): + ## object-vector.h: ns3::ObjectVectorChecker::ObjectVectorChecker(ns3::ObjectVectorChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ObjectVectorChecker const &', 'arg0')]) + ## object-vector.h: ns3::ObjectVectorChecker::ObjectVectorChecker() [constructor] + cls.add_constructor([]) + ## object-vector.h: ns3::TypeId ns3::ObjectVectorChecker::GetItemTypeId() const [member function] + cls.add_method('GetItemTypeId', + 'ns3::TypeId', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3ObjectVectorValue_methods(root_module, cls): + ## object-vector.h: ns3::ObjectVectorValue::ObjectVectorValue(ns3::ObjectVectorValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ObjectVectorValue const &', 'arg0')]) + ## object-vector.h: ns3::ObjectVectorValue::ObjectVectorValue() [constructor] + cls.add_constructor([]) + ## object-vector.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::ObjectVectorValue::Begin() const [member function] + cls.add_method('Begin', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Object > const, std::vector< ns3::Ptr< ns3::Object > > >', + [], + is_const=True) + ## object-vector.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::ObjectVectorValue::End() const [member function] + cls.add_method('End', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Object > const, std::vector< ns3::Ptr< ns3::Object > > >', + [], + is_const=True) + ## object-vector.h: uint32_t ns3::ObjectVectorValue::GetN() const [member function] + cls.add_method('GetN', + 'uint32_t', + [], + is_const=True) + ## object-vector.h: ns3::Ptr ns3::ObjectVectorValue::Get(uint32_t i) const [member function] + cls.add_method('Get', + 'ns3::Ptr< ns3::Object >', + [param('uint32_t', 'i')], + is_const=True) + ## object-vector.h: ns3::Ptr ns3::ObjectVectorValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## object-vector.h: std::string ns3::ObjectVectorValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## object-vector.h: bool ns3::ObjectVectorValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3ParetoVariable_methods(root_module, cls): + ## random-variable.h: ns3::ParetoVariable::ParetoVariable(ns3::ParetoVariable const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ParetoVariable const &', 'arg0')]) + ## random-variable.h: ns3::ParetoVariable::ParetoVariable() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::ParetoVariable::ParetoVariable(double m) [constructor] + cls.add_constructor([param('double', 'm')]) + ## random-variable.h: ns3::ParetoVariable::ParetoVariable(double m, double s) [constructor] + cls.add_constructor([param('double', 'm'), param('double', 's')]) + ## random-variable.h: ns3::ParetoVariable::ParetoVariable(double m, double s, double b) [constructor] + cls.add_constructor([param('double', 'm'), param('double', 's'), param('double', 'b')]) + ## random-variable.h: static double ns3::ParetoVariable::GetSingleValue(double m, double s, double b=0) [member function] + cls.add_method('GetSingleValue', + 'double', + [param('double', 'm'), param('double', 's'), param('double', 'b', default_value='0')], + is_static=True) + return + +def register_Ns3PointerChecker_methods(root_module, cls): + ## pointer.h: ns3::PointerChecker::PointerChecker(ns3::PointerChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PointerChecker const &', 'arg0')]) + ## pointer.h: ns3::PointerChecker::PointerChecker() [constructor] + cls.add_constructor([]) + ## pointer.h: ns3::TypeId ns3::PointerChecker::GetPointeeTypeId() const [member function] + cls.add_method('GetPointeeTypeId', + 'ns3::TypeId', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3PointerValue_methods(root_module, cls): + ## pointer.h: ns3::PointerValue::PointerValue(ns3::PointerValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PointerValue const &', 'arg0')]) + ## pointer.h: ns3::PointerValue::PointerValue() [constructor] + cls.add_constructor([]) + ## pointer.h: ns3::PointerValue::PointerValue(ns3::Ptr object) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::Object >', 'object')]) + ## pointer.h: void ns3::PointerValue::SetObject(ns3::Ptr object) [member function] + cls.add_method('SetObject', + 'void', + [param('ns3::Ptr< ns3::Object >', 'object')]) + ## pointer.h: ns3::Ptr ns3::PointerValue::GetObject() const [member function] + cls.add_method('GetObject', + 'ns3::Ptr< ns3::Object >', + [], + is_const=True) + ## pointer.h: ns3::Ptr ns3::PointerValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## pointer.h: std::string ns3::PointerValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## pointer.h: bool ns3::PointerValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3RandomVariableChecker_methods(root_module, cls): + ## random-variable.h: ns3::RandomVariableChecker::RandomVariableChecker(ns3::RandomVariableChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomVariableChecker const &', 'arg0')]) + ## random-variable.h: ns3::RandomVariableChecker::RandomVariableChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3RandomVariableValue_methods(root_module, cls): + ## random-variable.h: ns3::RandomVariableValue::RandomVariableValue(ns3::RandomVariableValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomVariableValue const &', 'arg0')]) + ## random-variable.h: ns3::RandomVariableValue::RandomVariableValue() [constructor] + cls.add_constructor([]) + ## random-variable.h: ns3::RandomVariableValue::RandomVariableValue(ns3::RandomVariable const & value) [constructor] + cls.add_constructor([param('ns3::RandomVariable const &', 'value')]) + ## random-variable.h: void ns3::RandomVariableValue::Set(ns3::RandomVariable const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::RandomVariable const &', 'value')]) + ## random-variable.h: ns3::RandomVariable ns3::RandomVariableValue::Get() const [member function] + cls.add_method('Get', + 'ns3::RandomVariable', + [], + is_const=True) + ## random-variable.h: ns3::Ptr ns3::RandomVariableValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## random-variable.h: std::string ns3::RandomVariableValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## random-variable.h: bool ns3::RandomVariableValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3StringChecker_methods(root_module, cls): + ## string.h: ns3::StringChecker::StringChecker(ns3::StringChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::StringChecker const &', 'arg0')]) + ## string.h: ns3::StringChecker::StringChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3StringValue_methods(root_module, cls): + ## string.h: ns3::StringValue::StringValue(ns3::StringValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::StringValue const &', 'arg0')]) + ## string.h: ns3::StringValue::StringValue() [constructor] + cls.add_constructor([]) + ## string.h: ns3::StringValue::StringValue(std::string const & value) [constructor] + cls.add_constructor([param('std::string const &', 'value')]) + ## string.h: void ns3::StringValue::Set(std::string const & value) [member function] + cls.add_method('Set', + 'void', + [param('std::string const &', 'value')]) + ## string.h: std::string ns3::StringValue::Get() const [member function] + cls.add_method('Get', + 'std::string', + [], + is_const=True) + ## string.h: ns3::Ptr ns3::StringValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## string.h: std::string ns3::StringValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## string.h: bool ns3::StringValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3TypeIdChecker_methods(root_module, cls): + ## type-id.h: ns3::TypeIdChecker::TypeIdChecker(ns3::TypeIdChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TypeIdChecker const &', 'arg0')]) + ## type-id.h: ns3::TypeIdChecker::TypeIdChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3TypeIdValue_methods(root_module, cls): + ## type-id.h: ns3::TypeIdValue::TypeIdValue(ns3::TypeIdValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TypeIdValue const &', 'arg0')]) + ## type-id.h: ns3::TypeIdValue::TypeIdValue() [constructor] + cls.add_constructor([]) + ## type-id.h: ns3::TypeIdValue::TypeIdValue(ns3::TypeId const & value) [constructor] + cls.add_constructor([param('ns3::TypeId const &', 'value')]) + ## type-id.h: void ns3::TypeIdValue::Set(ns3::TypeId const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::TypeId const &', 'value')]) + ## type-id.h: ns3::TypeId ns3::TypeIdValue::Get() const [member function] + cls.add_method('Get', + 'ns3::TypeId', + [], + is_const=True) + ## type-id.h: ns3::Ptr ns3::TypeIdValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## type-id.h: std::string ns3::TypeIdValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## type-id.h: bool ns3::TypeIdValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3UintegerValue_methods(root_module, cls): + ## uinteger.h: ns3::UintegerValue::UintegerValue(ns3::UintegerValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UintegerValue const &', 'arg0')]) + ## uinteger.h: ns3::UintegerValue::UintegerValue() [constructor] + cls.add_constructor([]) + ## uinteger.h: ns3::UintegerValue::UintegerValue(uint64_t const & value) [constructor] + cls.add_constructor([param('uint64_t const &', 'value')]) + ## uinteger.h: void ns3::UintegerValue::Set(uint64_t const & value) [member function] + cls.add_method('Set', + 'void', + [param('uint64_t const &', 'value')]) + ## uinteger.h: uint64_t ns3::UintegerValue::Get() const [member function] + cls.add_method('Get', + 'uint64_t', + [], + is_const=True) + ## uinteger.h: ns3::Ptr ns3::UintegerValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## uinteger.h: std::string ns3::UintegerValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## uinteger.h: bool ns3::UintegerValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3TracedValue__Unsigned_int_methods(root_module, cls): + ## traced-value.h: ns3::TracedValue::TracedValue() [constructor] + cls.add_constructor([]) + ## traced-value.h: ns3::TracedValue::TracedValue(ns3::TracedValue const & o) [copy constructor] + cls.add_constructor([param('ns3::TracedValue< unsigned int > const &', 'o')]) + ## traced-value.h: ns3::TracedValue::TracedValue(unsigned int const & v) [constructor] + cls.add_constructor([param('unsigned int const &', 'v')]) + ## traced-value.h: ns3::TracedValue::TracedValue(ns3::IntegerValue const & value) [constructor] + cls.add_constructor([param('ns3::IntegerValue const &', 'value')]) + ## traced-value.h: ns3::TracedValue::TracedValue(ns3::UintegerValue const & value) [constructor] + cls.add_constructor([param('ns3::UintegerValue const &', 'value')]) + ## traced-value.h: ns3::TracedValue::TracedValue(ns3::BooleanValue const & value) [constructor] + cls.add_constructor([param('ns3::BooleanValue const &', 'value')]) + ## traced-value.h: ns3::TracedValue::TracedValue(ns3::EnumValue const & value) [constructor] + cls.add_constructor([param('ns3::EnumValue const &', 'value')]) + ## traced-value.h: void ns3::TracedValue::ConnectWithoutContext(ns3::CallbackBase const & cb) [member function] + cls.add_method('ConnectWithoutContext', + 'void', + [param('ns3::CallbackBase const &', 'cb')]) + ## traced-value.h: void ns3::TracedValue::Connect(ns3::CallbackBase const & cb, std::string path) [member function] + cls.add_method('Connect', + 'void', + [param('ns3::CallbackBase const &', 'cb'), param('std::string', 'path')]) + ## traced-value.h: void ns3::TracedValue::DisconnectWithoutContext(ns3::CallbackBase const & cb) [member function] + cls.add_method('DisconnectWithoutContext', + 'void', + [param('ns3::CallbackBase const &', 'cb')]) + ## traced-value.h: void ns3::TracedValue::Disconnect(ns3::CallbackBase const & cb, std::string path) [member function] + cls.add_method('Disconnect', + 'void', + [param('ns3::CallbackBase const &', 'cb'), param('std::string', 'path')]) + ## traced-value.h: void ns3::TracedValue::Set(unsigned int const & v) [member function] + cls.add_method('Set', + 'void', + [param('unsigned int const &', 'v')]) + ## traced-value.h: unsigned int ns3::TracedValue::Get() const [member function] + cls.add_method('Get', + 'unsigned int', + [], + is_const=True) + return + +def register_Ns3ConfigMatchContainer_methods(root_module, cls): + ## config.h: ns3::Config::MatchContainer::MatchContainer(ns3::Config::MatchContainer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Config::MatchContainer const &', 'arg0')]) + ## config.h: ns3::Config::MatchContainer::MatchContainer() [constructor] + cls.add_constructor([]) + ## config.h: ns3::Config::MatchContainer::MatchContainer(std::vector, std::allocator > > const & objects, std::vector > const & contexts, std::string path) [constructor] + cls.add_constructor([param('std::vector< ns3::Ptr< ns3::Object > > const &', 'objects'), param('std::vector< std::string > const &', 'contexts'), param('std::string', 'path')]) + ## config.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::Config::MatchContainer::Begin() const [member function] + cls.add_method('Begin', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Object > const, std::vector< ns3::Ptr< ns3::Object > > >', + [], + is_const=True) + ## config.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::Config::MatchContainer::End() const [member function] + cls.add_method('End', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Object > const, std::vector< ns3::Ptr< ns3::Object > > >', + [], + is_const=True) + ## config.h: uint32_t ns3::Config::MatchContainer::GetN() const [member function] + cls.add_method('GetN', + 'uint32_t', + [], + is_const=True) + ## config.h: ns3::Ptr ns3::Config::MatchContainer::Get(uint32_t i) const [member function] + cls.add_method('Get', + 'ns3::Ptr< ns3::Object >', + [param('uint32_t', 'i')], + is_const=True) + ## config.h: std::string ns3::Config::MatchContainer::GetMatchedPath(uint32_t i) const [member function] + cls.add_method('GetMatchedPath', + 'std::string', + [param('uint32_t', 'i')], + is_const=True) + ## config.h: std::string ns3::Config::MatchContainer::GetPath() const [member function] + cls.add_method('GetPath', + 'std::string', + [], + is_const=True) + ## config.h: void ns3::Config::MatchContainer::Set(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('Set', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## config.h: void ns3::Config::MatchContainer::Connect(std::string name, ns3::CallbackBase const & cb) [member function] + cls.add_method('Connect', + 'void', + [param('std::string', 'name'), param('ns3::CallbackBase const &', 'cb')]) + ## config.h: void ns3::Config::MatchContainer::ConnectWithoutContext(std::string name, ns3::CallbackBase const & cb) [member function] + cls.add_method('ConnectWithoutContext', + 'void', + [param('std::string', 'name'), param('ns3::CallbackBase const &', 'cb')]) + ## config.h: void ns3::Config::MatchContainer::Disconnect(std::string name, ns3::CallbackBase const & cb) [member function] + cls.add_method('Disconnect', + 'void', + [param('std::string', 'name'), param('ns3::CallbackBase const &', 'cb')]) + ## config.h: void ns3::Config::MatchContainer::DisconnectWithoutContext(std::string name, ns3::CallbackBase const & cb) [member function] + cls.add_method('DisconnectWithoutContext', + 'void', + [param('std::string', 'name'), param('ns3::CallbackBase const &', 'cb')]) + return + +def register_functions(root_module): + module = root_module + ## boolean.h: extern ns3::Ptr ns3::MakeBooleanChecker() [free function] + module.add_function('MakeBooleanChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['double']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['float']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['long long']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['int']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['short']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['signed char']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['unsigned long long']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['unsigned int']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['unsigned short']) + ## type-name.h: extern std::string ns3::TypeNameGet() [free function] + module.add_function('TypeNameGet', + 'std::string', + [], + template_parameters=['unsigned char']) + ## log.h: extern void ns3::LogComponentDisable(char const * name, ns3::LogLevel level) [free function] + module.add_function('LogComponentDisable', + 'void', + [param('char const *', 'name'), param('ns3::LogLevel', 'level')]) + ## string.h: extern ns3::Ptr ns3::MakeStringChecker() [free function] + module.add_function('MakeStringChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## ptr.h: extern ns3::Ptr ns3::Create() [free function] + module.add_function('Create', + 'ns3::Ptr< ns3::PointerValue >', + [], + template_parameters=['ns3::PointerValue']) + ## ptr.h: extern ns3::Ptr ns3::Create() [free function] + module.add_function('Create', + 'ns3::Ptr< ns3::ObjectVectorValue >', + [], + template_parameters=['ns3::ObjectVectorValue']) + ## log.h: extern void ns3::LogComponentEnableAll(ns3::LogLevel level) [free function] + module.add_function('LogComponentEnableAll', + 'void', + [param('ns3::LogLevel', 'level')]) + ## type-id.h: extern ns3::Ptr ns3::MakeTypeIdChecker() [free function] + module.add_function('MakeTypeIdChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## object-factory.h: extern ns3::Ptr ns3::MakeObjectFactoryChecker() [free function] + module.add_function('MakeObjectFactoryChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## log.h: extern void ns3::LogComponentDisableAll(ns3::LogLevel level) [free function] + module.add_function('LogComponentDisableAll', + 'void', + [param('ns3::LogLevel', 'level')]) + ## callback.h: extern ns3::Ptr ns3::MakeCallbackChecker() [free function] + module.add_function('MakeCallbackChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## breakpoint.h: extern void ns3::BreakpointFallback() [free function] + module.add_function('BreakpointFallback', + 'void', + []) + ## random-variable.h: extern ns3::Ptr ns3::MakeRandomVariableChecker() [free function] + module.add_function('MakeRandomVariableChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## log.h: extern void ns3::LogComponentEnable(char const * name, ns3::LogLevel level) [free function] + module.add_function('LogComponentEnable', + 'void', + [param('char const *', 'name'), param('ns3::LogLevel', 'level')]) + ## enum.h: extern ns3::Ptr ns3::MakeEnumChecker(int v1, std::string n1, int v2=0, std::string n2="", int v3=0, std::string n3="", int v4=0, std::string n4="", int v5=0, std::string n5="", int v6=0, std::string n6="", int v7=0, std::string n7="", int v8=0, std::string n8="", int v9=0, std::string n9="", int v10=0, std::string n10="", int v11=0, std::string n11="", int v12=0, std::string n12="") [free function] + module.add_function('MakeEnumChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + [param('int', 'v1'), param('std::string', 'n1'), param('int', 'v2', default_value='0'), param('std::string', 'n2', default_value='""'), param('int', 'v3', default_value='0'), param('std::string', 'n3', default_value='""'), param('int', 'v4', default_value='0'), param('std::string', 'n4', default_value='""'), param('int', 'v5', default_value='0'), param('std::string', 'n5', default_value='""'), param('int', 'v6', default_value='0'), param('std::string', 'n6', default_value='""'), param('int', 'v7', default_value='0'), param('std::string', 'n7', default_value='""'), param('int', 'v8', default_value='0'), param('std::string', 'n8', default_value='""'), param('int', 'v9', default_value='0'), param('std::string', 'n9', default_value='""'), param('int', 'v10', default_value='0'), param('std::string', 'n10', default_value='""'), param('int', 'v11', default_value='0'), param('std::string', 'n11', default_value='""'), param('int', 'v12', default_value='0'), param('std::string', 'n12', default_value='""')]) + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + ## uinteger.h: extern ns3::Ptr ns3::internal::MakeUintegerChecker(uint64_t min, uint64_t max, std::string name) [free function] + module.add_function('MakeUintegerChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + [param('uint64_t', 'min'), param('uint64_t', 'max'), param('std::string', 'name')]) + ## integer.h: extern ns3::Ptr ns3::internal::MakeIntegerChecker(int64_t min, int64_t max, std::string name) [free function] + module.add_function('MakeIntegerChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + [param('int64_t', 'min'), param('int64_t', 'max'), param('std::string', 'name')]) + ## double.h: extern ns3::Ptr ns3::internal::MakeDoubleChecker(double min, double max, std::string name) [free function] + module.add_function('MakeDoubleChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + [param('double', 'min'), param('double', 'max'), param('std::string', 'name')]) + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + ## config.h: extern bool ns3::Config::SetDefaultFailSafe(std::string name, ns3::AttributeValue const & value) [free function] + module.add_function('SetDefaultFailSafe', + 'bool', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## config.h: extern void ns3::Config::DisconnectWithoutContext(std::string path, ns3::CallbackBase const & cb) [free function] + module.add_function('DisconnectWithoutContext', + 'void', + [param('std::string', 'path'), param('ns3::CallbackBase const &', 'cb')]) + ## config.h: extern void ns3::Config::SetDefault(std::string name, ns3::AttributeValue const & value) [free function] + module.add_function('SetDefault', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## config.h: extern ns3::Config::MatchContainer ns3::Config::LookupMatches(std::string path) [free function] + module.add_function('LookupMatches', + 'ns3::Config::MatchContainer', + [param('std::string', 'path')]) + ## config.h: extern void ns3::Config::Connect(std::string path, ns3::CallbackBase const & cb) [free function] + module.add_function('Connect', + 'void', + [param('std::string', 'path'), param('ns3::CallbackBase const &', 'cb')]) + ## config.h: extern ns3::Ptr ns3::Config::GetRootNamespaceObject(uint32_t i) [free function] + module.add_function('GetRootNamespaceObject', + 'ns3::Ptr< ns3::Object >', + [param('uint32_t', 'i')]) + ## config.h: extern void ns3::Config::ConnectWithoutContext(std::string path, ns3::CallbackBase const & cb) [free function] + module.add_function('ConnectWithoutContext', + 'void', + [param('std::string', 'path'), param('ns3::CallbackBase const &', 'cb')]) + ## config.h: extern void ns3::Config::UnregisterRootNamespaceObject(ns3::Ptr obj) [free function] + module.add_function('UnregisterRootNamespaceObject', + 'void', + [param('ns3::Ptr< ns3::Object >', 'obj')]) + ## config.h: extern bool ns3::Config::SetGlobalFailSafe(std::string name, ns3::AttributeValue const & value) [free function] + module.add_function('SetGlobalFailSafe', + 'bool', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## config.h: extern void ns3::Config::Disconnect(std::string path, ns3::CallbackBase const & cb) [free function] + module.add_function('Disconnect', + 'void', + [param('std::string', 'path'), param('ns3::CallbackBase const &', 'cb')]) + ## config.h: extern uint32_t ns3::Config::GetRootNamespaceObjectN() [free function] + module.add_function('GetRootNamespaceObjectN', + 'uint32_t', + []) + ## config.h: extern void ns3::Config::Set(std::string path, ns3::AttributeValue const & value) [free function] + module.add_function('Set', + 'void', + [param('std::string', 'path'), param('ns3::AttributeValue const &', 'value')]) + ## config.h: extern void ns3::Config::SetGlobal(std::string name, ns3::AttributeValue const & value) [free function] + module.add_function('SetGlobal', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## config.h: extern void ns3::Config::RegisterRootNamespaceObject(ns3::Ptr obj) [free function] + module.add_function('RegisterRootNamespaceObject', + 'void', + [param('ns3::Ptr< ns3::Object >', 'obj')]) + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_csma.py b/bindings/python/ns3_module_csma.py new file mode 100644 index 000000000..ddcaae307 --- /dev/null +++ b/bindings/python/ns3_module_csma.py @@ -0,0 +1,437 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## csma-channel.h: ns3::WireState [enumeration] + module.add_enum('WireState', ['IDLE', 'TRANSMITTING', 'PROPAGATING']) + ## backoff.h: ns3::Backoff [class] + module.add_class('Backoff') + ## csma-channel.h: ns3::CsmaDeviceRec [class] + module.add_class('CsmaDeviceRec') + ## csma-channel.h: ns3::CsmaChannel [class] + module.add_class('CsmaChannel', parent=root_module['ns3::Channel']) + ## csma-net-device.h: ns3::CsmaNetDevice [class] + module.add_class('CsmaNetDevice', parent=root_module['ns3::NetDevice']) + ## csma-net-device.h: ns3::CsmaNetDevice::EncapsulationMode [enumeration] + module.add_enum('EncapsulationMode', ['ILLEGAL', 'DIX', 'LLC'], outer_class=root_module['ns3::CsmaNetDevice']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3Backoff_methods(root_module, root_module['ns3::Backoff']) + register_Ns3CsmaDeviceRec_methods(root_module, root_module['ns3::CsmaDeviceRec']) + register_Ns3CsmaChannel_methods(root_module, root_module['ns3::CsmaChannel']) + register_Ns3CsmaNetDevice_methods(root_module, root_module['ns3::CsmaNetDevice']) + return + +def register_Ns3Backoff_methods(root_module, cls): + ## backoff.h: ns3::Backoff::m_minSlots [variable] + cls.add_instance_attribute('m_minSlots', 'uint32_t', is_const=False) + ## backoff.h: ns3::Backoff::m_maxSlots [variable] + cls.add_instance_attribute('m_maxSlots', 'uint32_t', is_const=False) + ## backoff.h: ns3::Backoff::m_ceiling [variable] + cls.add_instance_attribute('m_ceiling', 'uint32_t', is_const=False) + ## backoff.h: ns3::Backoff::m_maxRetries [variable] + cls.add_instance_attribute('m_maxRetries', 'uint32_t', is_const=False) + ## backoff.h: ns3::Backoff::m_slotTime [variable] + cls.add_instance_attribute('m_slotTime', 'ns3::Time', is_const=False) + ## backoff.h: ns3::Backoff::Backoff(ns3::Backoff const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Backoff const &', 'arg0')]) + ## backoff.h: ns3::Backoff::Backoff() [constructor] + cls.add_constructor([]) + ## backoff.h: ns3::Backoff::Backoff(ns3::Time slotTime, uint32_t minSlots, uint32_t maxSlots, uint32_t ceiling, uint32_t maxRetries) [constructor] + cls.add_constructor([param('ns3::Time', 'slotTime'), param('uint32_t', 'minSlots'), param('uint32_t', 'maxSlots'), param('uint32_t', 'ceiling'), param('uint32_t', 'maxRetries')]) + ## backoff.h: ns3::Time ns3::Backoff::GetBackoffTime() [member function] + cls.add_method('GetBackoffTime', + 'ns3::Time', + []) + ## backoff.h: void ns3::Backoff::ResetBackoffTime() [member function] + cls.add_method('ResetBackoffTime', + 'void', + []) + ## backoff.h: bool ns3::Backoff::MaxRetriesReached() [member function] + cls.add_method('MaxRetriesReached', + 'bool', + []) + ## backoff.h: void ns3::Backoff::IncrNumRetries() [member function] + cls.add_method('IncrNumRetries', + 'void', + []) + return + +def register_Ns3CsmaDeviceRec_methods(root_module, cls): + ## csma-channel.h: ns3::CsmaDeviceRec::devicePtr [variable] + cls.add_instance_attribute('devicePtr', 'ns3::Ptr< ns3::CsmaNetDevice >', is_const=False) + ## csma-channel.h: ns3::CsmaDeviceRec::active [variable] + cls.add_instance_attribute('active', 'bool', is_const=False) + ## csma-channel.h: ns3::CsmaDeviceRec::CsmaDeviceRec(ns3::CsmaDeviceRec const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CsmaDeviceRec const &', 'arg0')]) + ## csma-channel.h: ns3::CsmaDeviceRec::CsmaDeviceRec() [constructor] + cls.add_constructor([]) + ## csma-channel.h: ns3::CsmaDeviceRec::CsmaDeviceRec(ns3::Ptr device) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::CsmaNetDevice >', 'device')]) + ## csma-channel.h: bool ns3::CsmaDeviceRec::IsActive() [member function] + cls.add_method('IsActive', + 'bool', + []) + return + +def register_Ns3CsmaChannel_methods(root_module, cls): + ## csma-channel.h: ns3::CsmaChannel::CsmaChannel(ns3::CsmaChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CsmaChannel const &', 'arg0')]) + ## csma-channel.h: static ns3::TypeId ns3::CsmaChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## csma-channel.h: ns3::CsmaChannel::CsmaChannel() [constructor] + cls.add_constructor([]) + ## csma-channel.h: int32_t ns3::CsmaChannel::Attach(ns3::Ptr device) [member function] + cls.add_method('Attach', + 'int32_t', + [param('ns3::Ptr< ns3::CsmaNetDevice >', 'device')]) + ## csma-channel.h: bool ns3::CsmaChannel::Detach(ns3::Ptr device) [member function] + cls.add_method('Detach', + 'bool', + [param('ns3::Ptr< ns3::CsmaNetDevice >', 'device')]) + ## csma-channel.h: bool ns3::CsmaChannel::Detach(uint32_t deviceId) [member function] + cls.add_method('Detach', + 'bool', + [param('uint32_t', 'deviceId')]) + ## csma-channel.h: bool ns3::CsmaChannel::Reattach(uint32_t deviceId) [member function] + cls.add_method('Reattach', + 'bool', + [param('uint32_t', 'deviceId')]) + ## csma-channel.h: bool ns3::CsmaChannel::Reattach(ns3::Ptr device) [member function] + cls.add_method('Reattach', + 'bool', + [param('ns3::Ptr< ns3::CsmaNetDevice >', 'device')]) + ## csma-channel.h: bool ns3::CsmaChannel::TransmitStart(ns3::Ptr p, uint32_t srcId) [member function] + cls.add_method('TransmitStart', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('uint32_t', 'srcId')]) + ## csma-channel.h: bool ns3::CsmaChannel::TransmitEnd() [member function] + cls.add_method('TransmitEnd', + 'bool', + []) + ## csma-channel.h: void ns3::CsmaChannel::PropagationCompleteEvent() [member function] + cls.add_method('PropagationCompleteEvent', + 'void', + []) + ## csma-channel.h: int32_t ns3::CsmaChannel::GetDeviceNum(ns3::Ptr device) [member function] + cls.add_method('GetDeviceNum', + 'int32_t', + [param('ns3::Ptr< ns3::CsmaNetDevice >', 'device')]) + ## csma-channel.h: ns3::WireState ns3::CsmaChannel::GetState() [member function] + cls.add_method('GetState', + 'ns3::WireState', + []) + ## csma-channel.h: bool ns3::CsmaChannel::IsBusy() [member function] + cls.add_method('IsBusy', + 'bool', + []) + ## csma-channel.h: bool ns3::CsmaChannel::IsActive(uint32_t deviceId) [member function] + cls.add_method('IsActive', + 'bool', + [param('uint32_t', 'deviceId')]) + ## csma-channel.h: uint32_t ns3::CsmaChannel::GetNumActDevices() [member function] + cls.add_method('GetNumActDevices', + 'uint32_t', + []) + ## csma-channel.h: uint32_t ns3::CsmaChannel::GetNDevices() const [member function] + cls.add_method('GetNDevices', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## csma-channel.h: ns3::Ptr ns3::CsmaChannel::GetDevice(uint32_t i) const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_const=True, is_virtual=True) + ## csma-channel.h: ns3::Ptr ns3::CsmaChannel::GetCsmaDevice(uint32_t i) const [member function] + cls.add_method('GetCsmaDevice', + 'ns3::Ptr< ns3::CsmaNetDevice >', + [param('uint32_t', 'i')], + is_const=True) + ## csma-channel.h: ns3::DataRate ns3::CsmaChannel::GetDataRate() [member function] + cls.add_method('GetDataRate', + 'ns3::DataRate', + [], + is_virtual=True) + ## csma-channel.h: ns3::Time ns3::CsmaChannel::GetDelay() [member function] + cls.add_method('GetDelay', + 'ns3::Time', + [], + is_virtual=True) + return + +def register_Ns3CsmaNetDevice_methods(root_module, cls): + ## csma-net-device.h: static ns3::TypeId ns3::CsmaNetDevice::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## csma-net-device.h: ns3::CsmaNetDevice::CsmaNetDevice() [constructor] + cls.add_constructor([]) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetInterframeGap(ns3::Time t) [member function] + cls.add_method('SetInterframeGap', + 'void', + [param('ns3::Time', 't')]) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetBackoffParams(ns3::Time slotTime, uint32_t minSlots, uint32_t maxSlots, uint32_t maxRetries, uint32_t ceiling) [member function] + cls.add_method('SetBackoffParams', + 'void', + [param('ns3::Time', 'slotTime'), param('uint32_t', 'minSlots'), param('uint32_t', 'maxSlots'), param('uint32_t', 'maxRetries'), param('uint32_t', 'ceiling')]) + ## csma-net-device.h: bool ns3::CsmaNetDevice::Attach(ns3::Ptr ch) [member function] + cls.add_method('Attach', + 'bool', + [param('ns3::Ptr< ns3::CsmaChannel >', 'ch')]) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetQueue(ns3::Ptr queue) [member function] + cls.add_method('SetQueue', + 'void', + [param('ns3::Ptr< ns3::Queue >', 'queue')]) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetReceiveErrorModel(ns3::Ptr em) [member function] + cls.add_method('SetReceiveErrorModel', + 'void', + [param('ns3::Ptr< ns3::ErrorModel >', 'em')]) + ## csma-net-device.h: void ns3::CsmaNetDevice::Receive(ns3::Ptr p, ns3::Ptr sender) [member function] + cls.add_method('Receive', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::CsmaNetDevice >', 'sender')]) + ## csma-net-device.h: bool ns3::CsmaNetDevice::IsSendEnabled() [member function] + cls.add_method('IsSendEnabled', + 'bool', + []) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetSendEnable(bool enable) [member function] + cls.add_method('SetSendEnable', + 'void', + [param('bool', 'enable')]) + ## csma-net-device.h: bool ns3::CsmaNetDevice::IsReceiveEnabled() [member function] + cls.add_method('IsReceiveEnabled', + 'bool', + []) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetReceiveEnable(bool enable) [member function] + cls.add_method('SetReceiveEnable', + 'void', + [param('bool', 'enable')]) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetAddress(ns3::Mac48Address addr) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Mac48Address', 'addr')]) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetFrameSize(uint16_t frameSize) [member function] + cls.add_method('SetFrameSize', + 'void', + [param('uint16_t', 'frameSize')]) + ## csma-net-device.h: uint16_t ns3::CsmaNetDevice::GetFrameSize() const [member function] + cls.add_method('GetFrameSize', + 'uint16_t', + [], + is_const=True) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetEncapsulationMode(ns3::CsmaNetDevice::EncapsulationMode mode) [member function] + cls.add_method('SetEncapsulationMode', + 'void', + [param('ns3::CsmaNetDevice::EncapsulationMode', 'mode')]) + ## csma-net-device.h: ns3::CsmaNetDevice::EncapsulationMode ns3::CsmaNetDevice::GetEncapsulationMode() [member function] + cls.add_method('GetEncapsulationMode', + 'ns3::CsmaNetDevice::EncapsulationMode', + []) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetName(std::string const name) [member function] + cls.add_method('SetName', + 'void', + [param('std::string const', 'name')], + is_virtual=True) + ## csma-net-device.h: std::string ns3::CsmaNetDevice::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetIfIndex(uint32_t const index) [member function] + cls.add_method('SetIfIndex', + 'void', + [param('uint32_t const', 'index')], + is_virtual=True) + ## csma-net-device.h: uint32_t ns3::CsmaNetDevice::GetIfIndex() const [member function] + cls.add_method('GetIfIndex', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: ns3::Ptr ns3::CsmaNetDevice::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::Channel >', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::SetMtu(uint16_t const mtu) [member function] + cls.add_method('SetMtu', + 'bool', + [param('uint16_t const', 'mtu')], + is_virtual=True) + ## csma-net-device.h: uint16_t ns3::CsmaNetDevice::GetMtu() const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: ns3::Address ns3::CsmaNetDevice::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::IsLinkUp() const [member function] + cls.add_method('IsLinkUp', + 'bool', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetLinkChangeCallback(ns3::Callback callback) [member function] + cls.add_method('SetLinkChangeCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: ns3::Address ns3::CsmaNetDevice::GetBroadcast() const [member function] + cls.add_method('GetBroadcast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: ns3::Address ns3::CsmaNetDevice::GetMulticast() const [member function] + cls.add_method('GetMulticast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: ns3::Address ns3::CsmaNetDevice::MakeMulticastAddress(ns3::Ipv4Address multicastGroup) const [member function] + cls.add_method('MakeMulticastAddress', + 'ns3::Address', + [param('ns3::Ipv4Address', 'multicastGroup')], + is_const=True, is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::IsPointToPoint() const [member function] + cls.add_method('IsPointToPoint', + 'bool', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::Send(ns3::Ptr packet, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('Send', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::SendFrom(ns3::Ptr packet, ns3::Address const & source, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('SendFrom', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'source'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## csma-net-device.h: ns3::Ptr ns3::CsmaNetDevice::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::NeedsArp() const [member function] + cls.add_method('NeedsArp', + 'bool', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::empty, ns3::empty> cb) [member function] + cls.add_method('SetReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::empty, ns3::empty >', 'cb')], + is_virtual=True) + ## csma-net-device.h: void ns3::CsmaNetDevice::SetPromiscReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> cb) [member function] + cls.add_method('SetPromiscReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'cb')], + is_virtual=True) + ## csma-net-device.h: bool ns3::CsmaNetDevice::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## csma-net-device.h: void ns3::CsmaNetDevice::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## csma-net-device.h: ns3::Ptr ns3::CsmaNetDevice::GetQueue() const [member function] + cls.add_method('GetQueue', + 'ns3::Ptr< ns3::Queue >', + [], + is_const=True, visibility='protected') + ## csma-net-device.h: void ns3::CsmaNetDevice::AddHeader(ns3::Ptr p, ns3::Mac48Address source, ns3::Mac48Address dest, uint16_t protocolNumber) [member function] + cls.add_method('AddHeader', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Mac48Address', 'source'), param('ns3::Mac48Address', 'dest'), param('uint16_t', 'protocolNumber')], + visibility='protected') + ## csma-net-device.h: bool ns3::CsmaNetDevice::ProcessHeader(ns3::Ptr p, uint16_t & param) [member function] + cls.add_method('ProcessHeader', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('uint16_t &', 'param')], + visibility='protected') + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_global_routing.py b/bindings/python/ns3_module_global_routing.py new file mode 100644 index 000000000..67de0a1ab --- /dev/null +++ b/bindings/python/ns3_module_global_routing.py @@ -0,0 +1,280 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## global-route-manager.h: ns3::GlobalRouteManager [class] + module.add_class('GlobalRouteManager') + ## global-router-interface.h: ns3::GlobalRoutingLSA [class] + module.add_class('GlobalRoutingLSA') + ## global-router-interface.h: ns3::GlobalRoutingLSA::LSType [enumeration] + module.add_enum('LSType', ['Unknown', 'RouterLSA', 'NetworkLSA', 'SummaryLSA', 'SummaryLSA_ASBR', 'ASExternalLSAs'], outer_class=root_module['ns3::GlobalRoutingLSA']) + ## global-router-interface.h: ns3::GlobalRoutingLSA::SPFStatus [enumeration] + module.add_enum('SPFStatus', ['LSA_SPF_NOT_EXPLORED', 'LSA_SPF_CANDIDATE', 'LSA_SPF_IN_SPFTREE'], outer_class=root_module['ns3::GlobalRoutingLSA']) + ## global-router-interface.h: ns3::GlobalRoutingLinkRecord [class] + module.add_class('GlobalRoutingLinkRecord') + ## global-router-interface.h: ns3::GlobalRoutingLinkRecord::LinkType [enumeration] + module.add_enum('LinkType', ['Unknown', 'PointToPoint', 'TransitNetwork', 'StubNetwork', 'VirtualLink'], outer_class=root_module['ns3::GlobalRoutingLinkRecord']) + ## global-router-interface.h: ns3::GlobalRouter [class] + module.add_class('GlobalRouter', is_singleton=True, parent=root_module['ns3::Object']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3GlobalRouteManager_methods(root_module, root_module['ns3::GlobalRouteManager']) + register_Ns3GlobalRoutingLSA_methods(root_module, root_module['ns3::GlobalRoutingLSA']) + register_Ns3GlobalRoutingLinkRecord_methods(root_module, root_module['ns3::GlobalRoutingLinkRecord']) + register_Ns3GlobalRouter_methods(root_module, root_module['ns3::GlobalRouter']) + return + +def register_Ns3GlobalRouteManager_methods(root_module, cls): + ## global-route-manager.h: static void ns3::GlobalRouteManager::PopulateRoutingTables() [member function] + cls.add_method('PopulateRoutingTables', + 'void', + [], + is_static=True) + ## global-route-manager.h: static uint32_t ns3::GlobalRouteManager::AllocateRouterId() [member function] + cls.add_method('AllocateRouterId', + 'uint32_t', + [], + is_static=True) + return + +def register_Ns3GlobalRoutingLSA_methods(root_module, cls): + cls.add_output_stream_operator() + ## global-router-interface.h: ns3::GlobalRoutingLSA::GlobalRoutingLSA() [constructor] + cls.add_constructor([]) + ## global-router-interface.h: ns3::GlobalRoutingLSA::GlobalRoutingLSA(ns3::GlobalRoutingLSA::SPFStatus status, ns3::Ipv4Address linkStateId, ns3::Ipv4Address advertisingRtr) [constructor] + cls.add_constructor([param('ns3::GlobalRoutingLSA::SPFStatus', 'status'), param('ns3::Ipv4Address', 'linkStateId'), param('ns3::Ipv4Address', 'advertisingRtr')]) + ## global-router-interface.h: ns3::GlobalRoutingLSA::GlobalRoutingLSA(ns3::GlobalRoutingLSA & lsa) [constructor] + cls.add_constructor([param('ns3::GlobalRoutingLSA &', 'lsa')]) + ## global-router-interface.h: uint32_t ns3::GlobalRoutingLSA::AddAttachedRouter(ns3::Ipv4Address addr) [member function] + cls.add_method('AddAttachedRouter', + 'uint32_t', + [param('ns3::Ipv4Address', 'addr')]) + ## global-router-interface.h: uint32_t ns3::GlobalRoutingLSA::AddLinkRecord(ns3::GlobalRoutingLinkRecord * lr) [member function] + cls.add_method('AddLinkRecord', + 'uint32_t', + [param('ns3::GlobalRoutingLinkRecord *', 'lr')]) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::ClearLinkRecords() [member function] + cls.add_method('ClearLinkRecords', + 'void', + []) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::CopyLinkRecords(ns3::GlobalRoutingLSA const & lsa) [member function] + cls.add_method('CopyLinkRecords', + 'void', + [param('ns3::GlobalRoutingLSA const &', 'lsa')]) + ## global-router-interface.h: ns3::Ipv4Address ns3::GlobalRoutingLSA::GetAdvertisingRouter() const [member function] + cls.add_method('GetAdvertisingRouter', + 'ns3::Ipv4Address', + [], + is_const=True) + ## global-router-interface.h: ns3::Ipv4Address ns3::GlobalRoutingLSA::GetAttachedRouter(uint32_t n) const [member function] + cls.add_method('GetAttachedRouter', + 'ns3::Ipv4Address', + [param('uint32_t', 'n')], + is_const=True) + ## global-router-interface.h: ns3::GlobalRoutingLSA::LSType ns3::GlobalRoutingLSA::GetLSType() const [member function] + cls.add_method('GetLSType', + 'ns3::GlobalRoutingLSA::LSType', + [], + is_const=True) + ## global-router-interface.h: ns3::GlobalRoutingLinkRecord * ns3::GlobalRoutingLSA::GetLinkRecord(uint32_t n) const [member function] + cls.add_method('GetLinkRecord', + 'ns3::GlobalRoutingLinkRecord *', + [param('uint32_t', 'n')], + is_const=True) + ## global-router-interface.h: ns3::Ipv4Address ns3::GlobalRoutingLSA::GetLinkStateId() const [member function] + cls.add_method('GetLinkStateId', + 'ns3::Ipv4Address', + [], + is_const=True) + ## global-router-interface.h: uint32_t ns3::GlobalRoutingLSA::GetNAttachedRouters() const [member function] + cls.add_method('GetNAttachedRouters', + 'uint32_t', + [], + is_const=True) + ## global-router-interface.h: uint32_t ns3::GlobalRoutingLSA::GetNLinkRecords() const [member function] + cls.add_method('GetNLinkRecords', + 'uint32_t', + [], + is_const=True) + ## global-router-interface.h: ns3::Ipv4Mask ns3::GlobalRoutingLSA::GetNetworkLSANetworkMask() const [member function] + cls.add_method('GetNetworkLSANetworkMask', + 'ns3::Ipv4Mask', + [], + is_const=True) + ## global-router-interface.h: ns3::GlobalRoutingLSA::SPFStatus ns3::GlobalRoutingLSA::GetStatus() const [member function] + cls.add_method('GetStatus', + 'ns3::GlobalRoutingLSA::SPFStatus', + [], + is_const=True) + ## global-router-interface.h: bool ns3::GlobalRoutingLSA::IsEmpty() const [member function] + cls.add_method('IsEmpty', + 'bool', + [], + is_const=True) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::SetAdvertisingRouter(ns3::Ipv4Address rtr) [member function] + cls.add_method('SetAdvertisingRouter', + 'void', + [param('ns3::Ipv4Address', 'rtr')]) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::SetLSType(ns3::GlobalRoutingLSA::LSType typ) [member function] + cls.add_method('SetLSType', + 'void', + [param('ns3::GlobalRoutingLSA::LSType', 'typ')]) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::SetLinkStateId(ns3::Ipv4Address addr) [member function] + cls.add_method('SetLinkStateId', + 'void', + [param('ns3::Ipv4Address', 'addr')]) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::SetNetworkLSANetworkMask(ns3::Ipv4Mask mask) [member function] + cls.add_method('SetNetworkLSANetworkMask', + 'void', + [param('ns3::Ipv4Mask', 'mask')]) + ## global-router-interface.h: void ns3::GlobalRoutingLSA::SetStatus(ns3::GlobalRoutingLSA::SPFStatus status) [member function] + cls.add_method('SetStatus', + 'void', + [param('ns3::GlobalRoutingLSA::SPFStatus', 'status')]) + return + +def register_Ns3GlobalRoutingLinkRecord_methods(root_module, cls): + ## global-router-interface.h: ns3::GlobalRoutingLinkRecord::GlobalRoutingLinkRecord(ns3::GlobalRoutingLinkRecord const & arg0) [copy constructor] + cls.add_constructor([param('ns3::GlobalRoutingLinkRecord const &', 'arg0')]) + ## global-router-interface.h: ns3::GlobalRoutingLinkRecord::GlobalRoutingLinkRecord() [constructor] + cls.add_constructor([]) + ## global-router-interface.h: ns3::GlobalRoutingLinkRecord::GlobalRoutingLinkRecord(ns3::GlobalRoutingLinkRecord::LinkType linkType, ns3::Ipv4Address linkId, ns3::Ipv4Address linkData, uint16_t metric) [constructor] + cls.add_constructor([param('ns3::GlobalRoutingLinkRecord::LinkType', 'linkType'), param('ns3::Ipv4Address', 'linkId'), param('ns3::Ipv4Address', 'linkData'), param('uint16_t', 'metric')]) + ## global-router-interface.h: ns3::Ipv4Address ns3::GlobalRoutingLinkRecord::GetLinkId() const [member function] + cls.add_method('GetLinkId', + 'ns3::Ipv4Address', + [], + is_const=True) + ## global-router-interface.h: void ns3::GlobalRoutingLinkRecord::SetLinkId(ns3::Ipv4Address addr) [member function] + cls.add_method('SetLinkId', + 'void', + [param('ns3::Ipv4Address', 'addr')]) + ## global-router-interface.h: ns3::Ipv4Address ns3::GlobalRoutingLinkRecord::GetLinkData() const [member function] + cls.add_method('GetLinkData', + 'ns3::Ipv4Address', + [], + is_const=True) + ## global-router-interface.h: void ns3::GlobalRoutingLinkRecord::SetLinkData(ns3::Ipv4Address addr) [member function] + cls.add_method('SetLinkData', + 'void', + [param('ns3::Ipv4Address', 'addr')]) + ## global-router-interface.h: ns3::GlobalRoutingLinkRecord::LinkType ns3::GlobalRoutingLinkRecord::GetLinkType() const [member function] + cls.add_method('GetLinkType', + 'ns3::GlobalRoutingLinkRecord::LinkType', + [], + is_const=True) + ## global-router-interface.h: void ns3::GlobalRoutingLinkRecord::SetLinkType(ns3::GlobalRoutingLinkRecord::LinkType linkType) [member function] + cls.add_method('SetLinkType', + 'void', + [param('ns3::GlobalRoutingLinkRecord::LinkType', 'linkType')]) + ## global-router-interface.h: uint16_t ns3::GlobalRoutingLinkRecord::GetMetric() const [member function] + cls.add_method('GetMetric', + 'uint16_t', + [], + is_const=True) + ## global-router-interface.h: void ns3::GlobalRoutingLinkRecord::SetMetric(uint16_t metric) [member function] + cls.add_method('SetMetric', + 'void', + [param('uint16_t', 'metric')]) + return + +def register_Ns3GlobalRouter_methods(root_module, cls): + ## global-router-interface.h: static ns3::TypeId ns3::GlobalRouter::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## global-router-interface.h: ns3::GlobalRouter::GlobalRouter() [constructor] + cls.add_constructor([]) + ## global-router-interface.h: ns3::Ipv4Address ns3::GlobalRouter::GetRouterId() const [member function] + cls.add_method('GetRouterId', + 'ns3::Ipv4Address', + [], + is_const=True) + ## global-router-interface.h: uint32_t ns3::GlobalRouter::DiscoverLSAs() [member function] + cls.add_method('DiscoverLSAs', + 'uint32_t', + []) + ## global-router-interface.h: uint32_t ns3::GlobalRouter::GetNumLSAs() const [member function] + cls.add_method('GetNumLSAs', + 'uint32_t', + [], + is_const=True) + ## global-router-interface.h: bool ns3::GlobalRouter::GetLSA(uint32_t n, ns3::GlobalRoutingLSA & lsa) const [member function] + cls.add_method('GetLSA', + 'bool', + [param('uint32_t', 'n'), param('ns3::GlobalRoutingLSA &', 'lsa')], + is_const=True) + ## global-router-interface.h: void ns3::GlobalRouter::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_helper.py b/bindings/python/ns3_module_helper.py new file mode 100644 index 000000000..4f4540086 --- /dev/null +++ b/bindings/python/ns3_module_helper.py @@ -0,0 +1,758 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## application-container.h: ns3::ApplicationContainer [class] + module.add_class('ApplicationContainer') + ## bridge-helper.h: ns3::BridgeHelper [class] + module.add_class('BridgeHelper', allow_subclassing=False) + ## csma-helper.h: ns3::CsmaHelper [class] + module.add_class('CsmaHelper', allow_subclassing=False) + ## internet-stack-helper.h: ns3::InternetStackHelper [class] + module.add_class('InternetStackHelper', allow_subclassing=False) + ## ipv4-address-helper.h: ns3::Ipv4AddressHelper [class] + module.add_class('Ipv4AddressHelper', allow_subclassing=False) + ## ipv4-interface-container.h: ns3::Ipv4InterfaceContainer [class] + module.add_class('Ipv4InterfaceContainer') + ## mobility-helper.h: ns3::MobilityHelper [class] + module.add_class('MobilityHelper', allow_subclassing=False) + ## net-device-container.h: ns3::NetDeviceContainer [class] + module.add_class('NetDeviceContainer') + ## node-container.h: ns3::NodeContainer [class] + module.add_class('NodeContainer') + ## ns2-mobility-helper.h: ns3::Ns2MobilityHelper [class] + module.add_class('Ns2MobilityHelper', allow_subclassing=False) + ## olsr-helper.h: ns3::OlsrHelper [class] + module.add_class('OlsrHelper', allow_subclassing=False) + ## on-off-helper.h: ns3::OnOffHelper [class] + module.add_class('OnOffHelper', allow_subclassing=False) + ## packet-sink-helper.h: ns3::PacketSinkHelper [class] + module.add_class('PacketSinkHelper', allow_subclassing=False) + ## packet-socket-helper.h: ns3::PacketSocketHelper [class] + module.add_class('PacketSocketHelper', allow_subclassing=False) + ## point-to-point-helper.h: ns3::PointToPointHelper [class] + module.add_class('PointToPointHelper', allow_subclassing=False) + ## static-multicast-route-helper.h: ns3::StaticMulticastRouteHelper [class] + module.add_class('StaticMulticastRouteHelper', allow_subclassing=False) + ## udp-echo-helper.h: ns3::UdpEchoClientHelper [class] + module.add_class('UdpEchoClientHelper', allow_subclassing=False) + ## udp-echo-helper.h: ns3::UdpEchoServerHelper [class] + module.add_class('UdpEchoServerHelper', allow_subclassing=False) + ## wifi-helper.h: ns3::WifiHelper [class] + module.add_class('WifiHelper', allow_subclassing=False) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3ApplicationContainer_methods(root_module, root_module['ns3::ApplicationContainer']) + register_Ns3BridgeHelper_methods(root_module, root_module['ns3::BridgeHelper']) + register_Ns3CsmaHelper_methods(root_module, root_module['ns3::CsmaHelper']) + register_Ns3InternetStackHelper_methods(root_module, root_module['ns3::InternetStackHelper']) + register_Ns3Ipv4AddressHelper_methods(root_module, root_module['ns3::Ipv4AddressHelper']) + register_Ns3Ipv4InterfaceContainer_methods(root_module, root_module['ns3::Ipv4InterfaceContainer']) + register_Ns3MobilityHelper_methods(root_module, root_module['ns3::MobilityHelper']) + register_Ns3NetDeviceContainer_methods(root_module, root_module['ns3::NetDeviceContainer']) + register_Ns3NodeContainer_methods(root_module, root_module['ns3::NodeContainer']) + register_Ns3Ns2MobilityHelper_methods(root_module, root_module['ns3::Ns2MobilityHelper']) + register_Ns3OlsrHelper_methods(root_module, root_module['ns3::OlsrHelper']) + register_Ns3OnOffHelper_methods(root_module, root_module['ns3::OnOffHelper']) + register_Ns3PacketSinkHelper_methods(root_module, root_module['ns3::PacketSinkHelper']) + register_Ns3PacketSocketHelper_methods(root_module, root_module['ns3::PacketSocketHelper']) + register_Ns3PointToPointHelper_methods(root_module, root_module['ns3::PointToPointHelper']) + register_Ns3StaticMulticastRouteHelper_methods(root_module, root_module['ns3::StaticMulticastRouteHelper']) + register_Ns3UdpEchoClientHelper_methods(root_module, root_module['ns3::UdpEchoClientHelper']) + register_Ns3UdpEchoServerHelper_methods(root_module, root_module['ns3::UdpEchoServerHelper']) + register_Ns3WifiHelper_methods(root_module, root_module['ns3::WifiHelper']) + return + +def register_Ns3ApplicationContainer_methods(root_module, cls): + ## application-container.h: ns3::ApplicationContainer::ApplicationContainer(ns3::ApplicationContainer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ApplicationContainer const &', 'arg0')]) + ## application-container.h: ns3::ApplicationContainer::ApplicationContainer() [constructor] + cls.add_constructor([]) + ## application-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::ApplicationContainer::Begin() const [member function] + cls.add_method('Begin', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Application > const, std::vector< ns3::Ptr< ns3::Application > > >', + [], + is_const=True) + ## application-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::ApplicationContainer::End() const [member function] + cls.add_method('End', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Application > const, std::vector< ns3::Ptr< ns3::Application > > >', + [], + is_const=True) + ## application-container.h: uint32_t ns3::ApplicationContainer::GetN() const [member function] + cls.add_method('GetN', + 'uint32_t', + [], + is_const=True) + ## application-container.h: ns3::Ptr ns3::ApplicationContainer::Get(uint32_t i) const [member function] + cls.add_method('Get', + 'ns3::Ptr< ns3::Application >', + [param('uint32_t', 'i')], + is_const=True) + ## application-container.h: void ns3::ApplicationContainer::Add(ns3::ApplicationContainer other) [member function] + cls.add_method('Add', + 'void', + [param('ns3::ApplicationContainer', 'other')]) + ## application-container.h: void ns3::ApplicationContainer::Add(ns3::Ptr application) [member function] + cls.add_method('Add', + 'void', + [param('ns3::Ptr< ns3::Application >', 'application')]) + ## application-container.h: void ns3::ApplicationContainer::Start(ns3::Time start) [member function] + cls.add_method('Start', + 'void', + [param('ns3::Time', 'start')]) + ## application-container.h: void ns3::ApplicationContainer::Stop(ns3::Time stop) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time', 'stop')]) + return + +def register_Ns3BridgeHelper_methods(root_module, cls): + ## bridge-helper.h: ns3::BridgeHelper::BridgeHelper(ns3::BridgeHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::BridgeHelper const &', 'arg0')]) + ## bridge-helper.h: ns3::BridgeHelper::BridgeHelper() [constructor] + cls.add_constructor([]) + ## bridge-helper.h: void ns3::BridgeHelper::SetDeviceAttribute(std::string n1, ns3::AttributeValue const & v1) [member function] + cls.add_method('SetDeviceAttribute', + 'void', + [param('std::string', 'n1'), param('ns3::AttributeValue const &', 'v1')]) + ## bridge-helper.h: ns3::NetDeviceContainer ns3::BridgeHelper::Install(ns3::Ptr node, ns3::NetDeviceContainer c) [member function] + cls.add_method('Install', + 'ns3::NetDeviceContainer', + [param('ns3::Ptr< ns3::Node >', 'node'), param('ns3::NetDeviceContainer', 'c')]) + return + +def register_Ns3CsmaHelper_methods(root_module, cls): + ## csma-helper.h: ns3::CsmaHelper::CsmaHelper(ns3::CsmaHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CsmaHelper const &', 'arg0')]) + ## csma-helper.h: ns3::CsmaHelper::CsmaHelper() [constructor] + cls.add_constructor([]) + ## csma-helper.h: void ns3::CsmaHelper::SetQueue(std::string type, std::string n1="", ns3::AttributeValue const & v1=ns3::EmptyAttributeValue(), std::string n2="", ns3::AttributeValue const & v2=ns3::EmptyAttributeValue(), std::string n3="", ns3::AttributeValue const & v3=ns3::EmptyAttributeValue(), std::string n4="", ns3::AttributeValue const & v4=ns3::EmptyAttributeValue()) [member function] + cls.add_method('SetQueue', + 'void', + [param('std::string', 'type'), param('std::string', 'n1', default_value='""'), param('ns3::AttributeValue const &', 'v1', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n2', default_value='""'), param('ns3::AttributeValue const &', 'v2', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n3', default_value='""'), param('ns3::AttributeValue const &', 'v3', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n4', default_value='""'), param('ns3::AttributeValue const &', 'v4', default_value='ns3::EmptyAttributeValue()')]) + ## csma-helper.h: void ns3::CsmaHelper::SetDeviceAttribute(std::string n1, ns3::AttributeValue const & v1) [member function] + cls.add_method('SetDeviceAttribute', + 'void', + [param('std::string', 'n1'), param('ns3::AttributeValue const &', 'v1')]) + ## csma-helper.h: void ns3::CsmaHelper::SetChannelAttribute(std::string n1, ns3::AttributeValue const & v1) [member function] + cls.add_method('SetChannelAttribute', + 'void', + [param('std::string', 'n1'), param('ns3::AttributeValue const &', 'v1')]) + ## csma-helper.h: void ns3::CsmaHelper::SetDeviceParameter(std::string n1, ns3::AttributeValue const & v1) [member function] + cls.add_method('SetDeviceParameter', + 'void', + [param('std::string', 'n1'), param('ns3::AttributeValue const &', 'v1')], + deprecated=True) + ## csma-helper.h: void ns3::CsmaHelper::SetChannelParameter(std::string n1, ns3::AttributeValue const & v1) [member function] + cls.add_method('SetChannelParameter', + 'void', + [param('std::string', 'n1'), param('ns3::AttributeValue const &', 'v1')], + deprecated=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnablePcap(std::string filename, uint32_t nodeid, uint32_t deviceid) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('uint32_t', 'nodeid'), param('uint32_t', 'deviceid')], + is_static=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnablePcap(std::string filename, ns3::NetDeviceContainer d) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('ns3::NetDeviceContainer', 'd')], + is_static=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnablePcap(std::string filename, ns3::NodeContainer n) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('ns3::NodeContainer', 'n')], + is_static=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnablePcapAll(std::string filename) [member function] + cls.add_method('EnablePcapAll', + 'void', + [param('std::string', 'filename')], + is_static=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnableAscii(std::ostream & os, uint32_t nodeid, uint32_t deviceid) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('uint32_t', 'nodeid'), param('uint32_t', 'deviceid')], + is_static=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnableAscii(std::ostream & os, ns3::NetDeviceContainer d) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('ns3::NetDeviceContainer', 'd')], + is_static=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnableAscii(std::ostream & os, ns3::NodeContainer n) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('ns3::NodeContainer', 'n')], + is_static=True) + ## csma-helper.h: static void ns3::CsmaHelper::EnableAsciiAll(std::ostream & os) [member function] + cls.add_method('EnableAsciiAll', + 'void', + [param('std::ostream &', 'os')], + is_static=True) + ## csma-helper.h: ns3::NetDeviceContainer ns3::CsmaHelper::Install(ns3::NodeContainer const & c) [member function] + cls.add_method('Install', + 'ns3::NetDeviceContainer', + [param('ns3::NodeContainer const &', 'c')]) + ## csma-helper.h: ns3::NetDeviceContainer ns3::CsmaHelper::Install(ns3::NodeContainer const & c, ns3::Ptr channel) [member function] + cls.add_method('Install', + 'ns3::NetDeviceContainer', + [param('ns3::NodeContainer const &', 'c'), param('ns3::Ptr< ns3::CsmaChannel >', 'channel')]) + ## csma-helper.h: void ns3::CsmaHelper::InstallStar(ns3::Ptr hub, ns3::NodeContainer spokes, ns3::NetDeviceContainer & hubDevices, ns3::NetDeviceContainer & spokeDevices) [member function] + cls.add_method('InstallStar', + 'void', + [param('ns3::Ptr< ns3::Node >', 'hub'), param('ns3::NodeContainer', 'spokes'), param('ns3::NetDeviceContainer &', 'hubDevices'), param('ns3::NetDeviceContainer &', 'spokeDevices')]) + return + +def register_Ns3InternetStackHelper_methods(root_module, cls): + ## internet-stack-helper.h: ns3::InternetStackHelper::InternetStackHelper(ns3::InternetStackHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::InternetStackHelper const &', 'arg0')]) + ## internet-stack-helper.h: ns3::InternetStackHelper::InternetStackHelper() [constructor] + cls.add_constructor([]) + ## internet-stack-helper.h: void ns3::InternetStackHelper::Install(ns3::NodeContainer c) [member function] + cls.add_method('Install', + 'void', + [param('ns3::NodeContainer', 'c')]) + ## internet-stack-helper.h: void ns3::InternetStackHelper::SetNscStack(std::string soname) [member function] + cls.add_method('SetNscStack', + 'void', + [param('std::string', 'soname')]) + ## internet-stack-helper.h: static void ns3::InternetStackHelper::EnablePcapAll(std::string filename) [member function] + cls.add_method('EnablePcapAll', + 'void', + [param('std::string', 'filename')], + is_static=True) + return + +def register_Ns3Ipv4AddressHelper_methods(root_module, cls): + ## ipv4-address-helper.h: ns3::Ipv4AddressHelper::Ipv4AddressHelper(ns3::Ipv4AddressHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4AddressHelper const &', 'arg0')]) + ## ipv4-address-helper.h: ns3::Ipv4AddressHelper::Ipv4AddressHelper() [constructor] + cls.add_constructor([]) + ## ipv4-address-helper.h: void ns3::Ipv4AddressHelper::SetBase(ns3::Ipv4Address network, ns3::Ipv4Mask mask, ns3::Ipv4Address base="0.0.0.1") [member function] + cls.add_method('SetBase', + 'void', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'mask'), param('ns3::Ipv4Address', 'base', default_value='"0.0.0.1"')]) + ## ipv4-address-helper.h: ns3::Ipv4Address ns3::Ipv4AddressHelper::NewNetwork() [member function] + cls.add_method('NewNetwork', + 'ns3::Ipv4Address', + []) + ## ipv4-address-helper.h: ns3::Ipv4Address ns3::Ipv4AddressHelper::NewAddress() [member function] + cls.add_method('NewAddress', + 'ns3::Ipv4Address', + []) + ## ipv4-address-helper.h: ns3::Ipv4InterfaceContainer ns3::Ipv4AddressHelper::Assign(ns3::NetDeviceContainer const & c) [member function] + cls.add_method('Assign', + 'ns3::Ipv4InterfaceContainer', + [param('ns3::NetDeviceContainer const &', 'c')]) + return + +def register_Ns3Ipv4InterfaceContainer_methods(root_module, cls): + ## ipv4-interface-container.h: ns3::Ipv4InterfaceContainer::Ipv4InterfaceContainer(ns3::Ipv4InterfaceContainer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4InterfaceContainer const &', 'arg0')]) + ## ipv4-interface-container.h: ns3::Ipv4InterfaceContainer::Ipv4InterfaceContainer() [constructor] + cls.add_constructor([]) + ## ipv4-interface-container.h: void ns3::Ipv4InterfaceContainer::Add(ns3::Ipv4InterfaceContainer other) [member function] + cls.add_method('Add', + 'void', + [param('ns3::Ipv4InterfaceContainer', 'other')]) + ## ipv4-interface-container.h: uint32_t ns3::Ipv4InterfaceContainer::GetN() const [member function] + cls.add_method('GetN', + 'uint32_t', + [], + is_const=True) + ## ipv4-interface-container.h: ns3::Ipv4Address ns3::Ipv4InterfaceContainer::GetAddress(uint32_t i) const [member function] + cls.add_method('GetAddress', + 'ns3::Ipv4Address', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-interface-container.h: void ns3::Ipv4InterfaceContainer::SetMetric(uint32_t i, uint16_t metric) [member function] + cls.add_method('SetMetric', + 'void', + [param('uint32_t', 'i'), param('uint16_t', 'metric')]) + ## ipv4-interface-container.h: void ns3::Ipv4InterfaceContainer::Add(ns3::Ptr ipv4, uint32_t interface) [member function] + cls.add_method('Add', + 'void', + [param('ns3::Ptr< ns3::Ipv4 >', 'ipv4'), param('uint32_t', 'interface')]) + return + +def register_Ns3MobilityHelper_methods(root_module, cls): + ## mobility-helper.h: ns3::MobilityHelper::MobilityHelper(ns3::MobilityHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::MobilityHelper const &', 'arg0')]) + ## mobility-helper.h: ns3::MobilityHelper::MobilityHelper() [constructor] + cls.add_constructor([]) + ## mobility-helper.h: void ns3::MobilityHelper::SetPositionAllocator(ns3::Ptr allocator) [member function] + cls.add_method('SetPositionAllocator', + 'void', + [param('ns3::Ptr< ns3::PositionAllocator >', 'allocator')]) + ## mobility-helper.h: void ns3::MobilityHelper::SetPositionAllocator(std::string type, std::string n1="", ns3::AttributeValue const & v1=ns3::EmptyAttributeValue(), std::string n2="", ns3::AttributeValue const & v2=ns3::EmptyAttributeValue(), std::string n3="", ns3::AttributeValue const & v3=ns3::EmptyAttributeValue(), std::string n4="", ns3::AttributeValue const & v4=ns3::EmptyAttributeValue(), std::string n5="", ns3::AttributeValue const & v5=ns3::EmptyAttributeValue(), std::string n6="", ns3::AttributeValue const & v6=ns3::EmptyAttributeValue(), std::string n7="", ns3::AttributeValue const & v7=ns3::EmptyAttributeValue(), std::string n8="", ns3::AttributeValue const & v8=ns3::EmptyAttributeValue(), std::string n9="", ns3::AttributeValue const & v9=ns3::EmptyAttributeValue()) [member function] + cls.add_method('SetPositionAllocator', + 'void', + [param('std::string', 'type'), param('std::string', 'n1', default_value='""'), param('ns3::AttributeValue const &', 'v1', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n2', default_value='""'), param('ns3::AttributeValue const &', 'v2', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n3', default_value='""'), param('ns3::AttributeValue const &', 'v3', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n4', default_value='""'), param('ns3::AttributeValue const &', 'v4', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n5', default_value='""'), param('ns3::AttributeValue const &', 'v5', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n6', default_value='""'), param('ns3::AttributeValue const &', 'v6', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n7', default_value='""'), param('ns3::AttributeValue const &', 'v7', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n8', default_value='""'), param('ns3::AttributeValue const &', 'v8', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n9', default_value='""'), param('ns3::AttributeValue const &', 'v9', default_value='ns3::EmptyAttributeValue()')]) + ## mobility-helper.h: void ns3::MobilityHelper::SetMobilityModel(std::string type, std::string n1="", ns3::AttributeValue const & v1=ns3::EmptyAttributeValue(), std::string n2="", ns3::AttributeValue const & v2=ns3::EmptyAttributeValue(), std::string n3="", ns3::AttributeValue const & v3=ns3::EmptyAttributeValue(), std::string n4="", ns3::AttributeValue const & v4=ns3::EmptyAttributeValue(), std::string n5="", ns3::AttributeValue const & v5=ns3::EmptyAttributeValue(), std::string n6="", ns3::AttributeValue const & v6=ns3::EmptyAttributeValue(), std::string n7="", ns3::AttributeValue const & v7=ns3::EmptyAttributeValue(), std::string n8="", ns3::AttributeValue const & v8=ns3::EmptyAttributeValue(), std::string n9="", ns3::AttributeValue const & v9=ns3::EmptyAttributeValue()) [member function] + cls.add_method('SetMobilityModel', + 'void', + [param('std::string', 'type'), param('std::string', 'n1', default_value='""'), param('ns3::AttributeValue const &', 'v1', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n2', default_value='""'), param('ns3::AttributeValue const &', 'v2', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n3', default_value='""'), param('ns3::AttributeValue const &', 'v3', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n4', default_value='""'), param('ns3::AttributeValue const &', 'v4', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n5', default_value='""'), param('ns3::AttributeValue const &', 'v5', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n6', default_value='""'), param('ns3::AttributeValue const &', 'v6', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n7', default_value='""'), param('ns3::AttributeValue const &', 'v7', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n8', default_value='""'), param('ns3::AttributeValue const &', 'v8', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n9', default_value='""'), param('ns3::AttributeValue const &', 'v9', default_value='ns3::EmptyAttributeValue()')]) + ## mobility-helper.h: void ns3::MobilityHelper::PushReferenceMobilityModel(ns3::Ptr reference) [member function] + cls.add_method('PushReferenceMobilityModel', + 'void', + [param('ns3::Ptr< ns3::Object >', 'reference')]) + ## mobility-helper.h: void ns3::MobilityHelper::PopReferenceMobilityModel() [member function] + cls.add_method('PopReferenceMobilityModel', + 'void', + []) + ## mobility-helper.h: std::string ns3::MobilityHelper::GetMobilityModelType() const [member function] + cls.add_method('GetMobilityModelType', + 'std::string', + [], + is_const=True) + ## mobility-helper.h: void ns3::MobilityHelper::Install(ns3::NodeContainer container) [member function] + cls.add_method('Install', + 'void', + [param('ns3::NodeContainer', 'container')]) + ## mobility-helper.h: void ns3::MobilityHelper::InstallAll() [member function] + cls.add_method('InstallAll', + 'void', + []) + ## mobility-helper.h: static void ns3::MobilityHelper::EnableAscii(std::ostream & os, uint32_t nodeid) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('uint32_t', 'nodeid')], + is_static=True) + ## mobility-helper.h: static void ns3::MobilityHelper::EnableAscii(std::ostream & os, ns3::NodeContainer n) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('ns3::NodeContainer', 'n')], + is_static=True) + ## mobility-helper.h: static void ns3::MobilityHelper::EnableAsciiAll(std::ostream & os) [member function] + cls.add_method('EnableAsciiAll', + 'void', + [param('std::ostream &', 'os')], + is_static=True) + return + +def register_Ns3NetDeviceContainer_methods(root_module, cls): + ## net-device-container.h: ns3::NetDeviceContainer::NetDeviceContainer(ns3::NetDeviceContainer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::NetDeviceContainer const &', 'arg0')]) + ## net-device-container.h: ns3::NetDeviceContainer::NetDeviceContainer() [constructor] + cls.add_constructor([]) + ## net-device-container.h: ns3::NetDeviceContainer::NetDeviceContainer(ns3::Ptr dev) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::NetDevice >', 'dev')]) + ## net-device-container.h: ns3::NetDeviceContainer::NetDeviceContainer(ns3::NetDeviceContainer const & a, ns3::NetDeviceContainer const & b) [constructor] + cls.add_constructor([param('ns3::NetDeviceContainer const &', 'a'), param('ns3::NetDeviceContainer const &', 'b')]) + ## net-device-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NetDeviceContainer::Begin() const [member function] + cls.add_method('Begin', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::NetDevice > const, std::vector< ns3::Ptr< ns3::NetDevice > > >', + [], + is_const=True) + ## net-device-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NetDeviceContainer::End() const [member function] + cls.add_method('End', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::NetDevice > const, std::vector< ns3::Ptr< ns3::NetDevice > > >', + [], + is_const=True) + ## net-device-container.h: uint32_t ns3::NetDeviceContainer::GetN() const [member function] + cls.add_method('GetN', + 'uint32_t', + [], + is_const=True) + ## net-device-container.h: ns3::Ptr ns3::NetDeviceContainer::Get(uint32_t i) const [member function] + cls.add_method('Get', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_const=True) + ## net-device-container.h: void ns3::NetDeviceContainer::Add(ns3::NetDeviceContainer other) [member function] + cls.add_method('Add', + 'void', + [param('ns3::NetDeviceContainer', 'other')]) + ## net-device-container.h: void ns3::NetDeviceContainer::Add(ns3::Ptr device) [member function] + cls.add_method('Add', + 'void', + [param('ns3::Ptr< ns3::NetDevice >', 'device')]) + return + +def register_Ns3NodeContainer_methods(root_module, cls): + ## node-container.h: ns3::NodeContainer::NodeContainer(ns3::NodeContainer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::NodeContainer const &', 'arg0')]) + ## node-container.h: ns3::NodeContainer::NodeContainer() [constructor] + cls.add_constructor([]) + ## node-container.h: ns3::NodeContainer::NodeContainer(ns3::Ptr node) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::Node >', 'node')]) + ## node-container.h: ns3::NodeContainer::NodeContainer(ns3::NodeContainer const & a, ns3::NodeContainer const & b) [constructor] + cls.add_constructor([param('ns3::NodeContainer const &', 'a'), param('ns3::NodeContainer const &', 'b')]) + ## node-container.h: ns3::NodeContainer::NodeContainer(ns3::NodeContainer const & a, ns3::NodeContainer const & b, ns3::NodeContainer const & c) [constructor] + cls.add_constructor([param('ns3::NodeContainer const &', 'a'), param('ns3::NodeContainer const &', 'b'), param('ns3::NodeContainer const &', 'c')]) + ## node-container.h: ns3::NodeContainer::NodeContainer(ns3::NodeContainer const & a, ns3::NodeContainer const & b, ns3::NodeContainer const & c, ns3::NodeContainer const & d) [constructor] + cls.add_constructor([param('ns3::NodeContainer const &', 'a'), param('ns3::NodeContainer const &', 'b'), param('ns3::NodeContainer const &', 'c'), param('ns3::NodeContainer const &', 'd')]) + ## node-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NodeContainer::Begin() const [member function] + cls.add_method('Begin', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Node > const, std::vector< ns3::Ptr< ns3::Node > > >', + [], + is_const=True) + ## node-container.h: __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NodeContainer::End() const [member function] + cls.add_method('End', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Node > const, std::vector< ns3::Ptr< ns3::Node > > >', + [], + is_const=True) + ## node-container.h: uint32_t ns3::NodeContainer::GetN() const [member function] + cls.add_method('GetN', + 'uint32_t', + [], + is_const=True) + ## node-container.h: ns3::Ptr ns3::NodeContainer::Get(uint32_t i) const [member function] + cls.add_method('Get', + 'ns3::Ptr< ns3::Node >', + [param('uint32_t', 'i')], + is_const=True) + ## node-container.h: void ns3::NodeContainer::Create(uint32_t n) [member function] + cls.add_method('Create', + 'void', + [param('uint32_t', 'n')]) + ## node-container.h: void ns3::NodeContainer::Add(ns3::NodeContainer other) [member function] + cls.add_method('Add', + 'void', + [param('ns3::NodeContainer', 'other')]) + ## node-container.h: void ns3::NodeContainer::Add(ns3::Ptr node) [member function] + cls.add_method('Add', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')]) + ## node-container.h: static ns3::NodeContainer ns3::NodeContainer::GetGlobal() [member function] + cls.add_method('GetGlobal', + 'ns3::NodeContainer', + [], + is_static=True) + return + +def register_Ns3Ns2MobilityHelper_methods(root_module, cls): + ## ns2-mobility-helper.h: ns3::Ns2MobilityHelper::Ns2MobilityHelper(ns3::Ns2MobilityHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ns2MobilityHelper const &', 'arg0')]) + ## ns2-mobility-helper.h: ns3::Ns2MobilityHelper::Ns2MobilityHelper(std::string filename) [constructor] + cls.add_constructor([param('std::string', 'filename')]) + ## ns2-mobility-helper.h: void ns3::Ns2MobilityHelper::Install() const [member function] + cls.add_method('Install', + 'void', + [], + is_const=True) + return + +def register_Ns3OlsrHelper_methods(root_module, cls): + ## olsr-helper.h: ns3::OlsrHelper::OlsrHelper(ns3::OlsrHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::OlsrHelper const &', 'arg0')]) + ## olsr-helper.h: ns3::OlsrHelper::OlsrHelper() [constructor] + cls.add_constructor([]) + ## olsr-helper.h: void ns3::OlsrHelper::SetAgent(std::string tid, std::string n0="", ns3::AttributeValue const & v0=ns3::EmptyAttributeValue(), std::string n1="", ns3::AttributeValue const & v1=ns3::EmptyAttributeValue(), std::string n2="", ns3::AttributeValue const & v2=ns3::EmptyAttributeValue(), std::string n3="", ns3::AttributeValue const & v3=ns3::EmptyAttributeValue(), std::string n4="", ns3::AttributeValue const & v4=ns3::EmptyAttributeValue(), std::string n5="", ns3::AttributeValue const & v5=ns3::EmptyAttributeValue(), std::string n6="", ns3::AttributeValue const & v6=ns3::EmptyAttributeValue(), std::string n7="", ns3::AttributeValue const & v7=ns3::EmptyAttributeValue()) [member function] + cls.add_method('SetAgent', + 'void', + [param('std::string', 'tid'), param('std::string', 'n0', default_value='""'), param('ns3::AttributeValue const &', 'v0', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n1', default_value='""'), param('ns3::AttributeValue const &', 'v1', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n2', default_value='""'), param('ns3::AttributeValue const &', 'v2', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n3', default_value='""'), param('ns3::AttributeValue const &', 'v3', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n4', default_value='""'), param('ns3::AttributeValue const &', 'v4', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n5', default_value='""'), param('ns3::AttributeValue const &', 'v5', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n6', default_value='""'), param('ns3::AttributeValue const &', 'v6', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n7', default_value='""'), param('ns3::AttributeValue const &', 'v7', default_value='ns3::EmptyAttributeValue()')]) + ## olsr-helper.h: void ns3::OlsrHelper::Install(ns3::NodeContainer container) [member function] + cls.add_method('Install', + 'void', + [param('ns3::NodeContainer', 'container')]) + ## olsr-helper.h: void ns3::OlsrHelper::Install(ns3::Ptr node) [member function] + cls.add_method('Install', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')]) + ## olsr-helper.h: void ns3::OlsrHelper::InstallAll() [member function] + cls.add_method('InstallAll', + 'void', + []) + return + +def register_Ns3OnOffHelper_methods(root_module, cls): + ## on-off-helper.h: ns3::OnOffHelper::OnOffHelper(ns3::OnOffHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::OnOffHelper const &', 'arg0')]) + ## on-off-helper.h: ns3::OnOffHelper::OnOffHelper(std::string protocol, ns3::Address address) [constructor] + cls.add_constructor([param('std::string', 'protocol'), param('ns3::Address', 'address')]) + ## on-off-helper.h: void ns3::OnOffHelper::SetAttribute(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## on-off-helper.h: ns3::ApplicationContainer ns3::OnOffHelper::Install(ns3::NodeContainer c) [member function] + cls.add_method('Install', + 'ns3::ApplicationContainer', + [param('ns3::NodeContainer', 'c')]) + return + +def register_Ns3PacketSinkHelper_methods(root_module, cls): + ## packet-sink-helper.h: ns3::PacketSinkHelper::PacketSinkHelper(ns3::PacketSinkHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketSinkHelper const &', 'arg0')]) + ## packet-sink-helper.h: ns3::PacketSinkHelper::PacketSinkHelper(std::string protocol, ns3::Address address) [constructor] + cls.add_constructor([param('std::string', 'protocol'), param('ns3::Address', 'address')]) + ## packet-sink-helper.h: void ns3::PacketSinkHelper::SetAttribute(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## packet-sink-helper.h: ns3::ApplicationContainer ns3::PacketSinkHelper::Install(ns3::NodeContainer c) [member function] + cls.add_method('Install', + 'ns3::ApplicationContainer', + [param('ns3::NodeContainer', 'c')]) + return + +def register_Ns3PacketSocketHelper_methods(root_module, cls): + ## packet-socket-helper.h: ns3::PacketSocketHelper::PacketSocketHelper(ns3::PacketSocketHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketSocketHelper const &', 'arg0')]) + ## packet-socket-helper.h: ns3::PacketSocketHelper::PacketSocketHelper() [constructor] + cls.add_constructor([]) + ## packet-socket-helper.h: void ns3::PacketSocketHelper::Install(ns3::NodeContainer c) [member function] + cls.add_method('Install', + 'void', + [param('ns3::NodeContainer', 'c')]) + return + +def register_Ns3PointToPointHelper_methods(root_module, cls): + ## point-to-point-helper.h: ns3::PointToPointHelper::PointToPointHelper(ns3::PointToPointHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PointToPointHelper const &', 'arg0')]) + ## point-to-point-helper.h: ns3::PointToPointHelper::PointToPointHelper() [constructor] + cls.add_constructor([]) + ## point-to-point-helper.h: void ns3::PointToPointHelper::SetQueue(std::string type, std::string n1="", ns3::AttributeValue const & v1=ns3::EmptyAttributeValue(), std::string n2="", ns3::AttributeValue const & v2=ns3::EmptyAttributeValue(), std::string n3="", ns3::AttributeValue const & v3=ns3::EmptyAttributeValue(), std::string n4="", ns3::AttributeValue const & v4=ns3::EmptyAttributeValue()) [member function] + cls.add_method('SetQueue', + 'void', + [param('std::string', 'type'), param('std::string', 'n1', default_value='""'), param('ns3::AttributeValue const &', 'v1', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n2', default_value='""'), param('ns3::AttributeValue const &', 'v2', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n3', default_value='""'), param('ns3::AttributeValue const &', 'v3', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n4', default_value='""'), param('ns3::AttributeValue const &', 'v4', default_value='ns3::EmptyAttributeValue()')]) + ## point-to-point-helper.h: void ns3::PointToPointHelper::SetDeviceAttribute(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetDeviceAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## point-to-point-helper.h: void ns3::PointToPointHelper::SetChannelAttribute(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetChannelAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## point-to-point-helper.h: void ns3::PointToPointHelper::SetDeviceParameter(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetDeviceParameter', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')], + deprecated=True) + ## point-to-point-helper.h: void ns3::PointToPointHelper::SetChannelParameter(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetChannelParameter', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')], + deprecated=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnablePcap(std::string filename, uint32_t nodeid, uint32_t deviceid) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('uint32_t', 'nodeid'), param('uint32_t', 'deviceid')], + is_static=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnablePcap(std::string filename, ns3::NetDeviceContainer d) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('ns3::NetDeviceContainer', 'd')], + is_static=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnablePcap(std::string filename, ns3::NodeContainer n) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('ns3::NodeContainer', 'n')], + is_static=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnablePcapAll(std::string filename) [member function] + cls.add_method('EnablePcapAll', + 'void', + [param('std::string', 'filename')], + is_static=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnableAscii(std::ostream & os, uint32_t nodeid, uint32_t deviceid) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('uint32_t', 'nodeid'), param('uint32_t', 'deviceid')], + is_static=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnableAscii(std::ostream & os, ns3::NetDeviceContainer d) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('ns3::NetDeviceContainer', 'd')], + is_static=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnableAscii(std::ostream & os, ns3::NodeContainer n) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('ns3::NodeContainer', 'n')], + is_static=True) + ## point-to-point-helper.h: static void ns3::PointToPointHelper::EnableAsciiAll(std::ostream & os) [member function] + cls.add_method('EnableAsciiAll', + 'void', + [param('std::ostream &', 'os')], + is_static=True) + ## point-to-point-helper.h: ns3::NetDeviceContainer ns3::PointToPointHelper::Install(ns3::NodeContainer c) [member function] + cls.add_method('Install', + 'ns3::NetDeviceContainer', + [param('ns3::NodeContainer', 'c')]) + ## point-to-point-helper.h: ns3::NetDeviceContainer ns3::PointToPointHelper::Install(ns3::Ptr a, ns3::Ptr b) [member function] + cls.add_method('Install', + 'ns3::NetDeviceContainer', + [param('ns3::Ptr< ns3::Node >', 'a'), param('ns3::Ptr< ns3::Node >', 'b')]) + ## point-to-point-helper.h: void ns3::PointToPointHelper::InstallStar(ns3::Ptr hub, ns3::NodeContainer spokes, ns3::NetDeviceContainer & hubDevices, ns3::NetDeviceContainer & spokeDevices) [member function] + cls.add_method('InstallStar', + 'void', + [param('ns3::Ptr< ns3::Node >', 'hub'), param('ns3::NodeContainer', 'spokes'), param('ns3::NetDeviceContainer &', 'hubDevices'), param('ns3::NetDeviceContainer &', 'spokeDevices')]) + return + +def register_Ns3StaticMulticastRouteHelper_methods(root_module, cls): + ## static-multicast-route-helper.h: ns3::StaticMulticastRouteHelper::StaticMulticastRouteHelper(ns3::StaticMulticastRouteHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::StaticMulticastRouteHelper const &', 'arg0')]) + ## static-multicast-route-helper.h: ns3::StaticMulticastRouteHelper::StaticMulticastRouteHelper() [constructor] + cls.add_constructor([]) + ## static-multicast-route-helper.h: void ns3::StaticMulticastRouteHelper::AddMulticastRoute(ns3::Ptr arg0, ns3::Ipv4Address source, ns3::Ipv4Address group, ns3::Ptr input, ns3::NetDeviceContainer output) [member function] + cls.add_method('AddMulticastRoute', + 'void', + [param('ns3::Ptr< ns3::Node >', 'arg0'), param('ns3::Ipv4Address', 'source'), param('ns3::Ipv4Address', 'group'), param('ns3::Ptr< ns3::NetDevice >', 'input'), param('ns3::NetDeviceContainer', 'output')]) + ## static-multicast-route-helper.h: void ns3::StaticMulticastRouteHelper::SetDefaultMulticastRoute(ns3::Ptr n, ns3::Ptr nd) [member function] + cls.add_method('SetDefaultMulticastRoute', + 'void', + [param('ns3::Ptr< ns3::Node >', 'n'), param('ns3::Ptr< ns3::NetDevice >', 'nd')]) + ## static-multicast-route-helper.h: void ns3::StaticMulticastRouteHelper::JoinMulticastGroup(ns3::Ptr n, ns3::Ipv4Address source, ns3::Ipv4Address group) [member function] + cls.add_method('JoinMulticastGroup', + 'void', + [param('ns3::Ptr< ns3::Node >', 'n'), param('ns3::Ipv4Address', 'source'), param('ns3::Ipv4Address', 'group')]) + return + +def register_Ns3UdpEchoClientHelper_methods(root_module, cls): + ## udp-echo-helper.h: ns3::UdpEchoClientHelper::UdpEchoClientHelper(ns3::UdpEchoClientHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UdpEchoClientHelper const &', 'arg0')]) + ## udp-echo-helper.h: ns3::UdpEchoClientHelper::UdpEchoClientHelper(ns3::Ipv4Address ip, uint16_t port) [constructor] + cls.add_constructor([param('ns3::Ipv4Address', 'ip'), param('uint16_t', 'port')]) + ## udp-echo-helper.h: void ns3::UdpEchoClientHelper::SetAttribute(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## udp-echo-helper.h: ns3::ApplicationContainer ns3::UdpEchoClientHelper::Install(ns3::NodeContainer c) [member function] + cls.add_method('Install', + 'ns3::ApplicationContainer', + [param('ns3::NodeContainer', 'c')]) + return + +def register_Ns3UdpEchoServerHelper_methods(root_module, cls): + ## udp-echo-helper.h: ns3::UdpEchoServerHelper::UdpEchoServerHelper(ns3::UdpEchoServerHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UdpEchoServerHelper const &', 'arg0')]) + ## udp-echo-helper.h: ns3::UdpEchoServerHelper::UdpEchoServerHelper(uint16_t port) [constructor] + cls.add_constructor([param('uint16_t', 'port')]) + ## udp-echo-helper.h: void ns3::UdpEchoServerHelper::SetAttribute(std::string name, ns3::AttributeValue const & value) [member function] + cls.add_method('SetAttribute', + 'void', + [param('std::string', 'name'), param('ns3::AttributeValue const &', 'value')]) + ## udp-echo-helper.h: ns3::ApplicationContainer ns3::UdpEchoServerHelper::Install(ns3::NodeContainer c) [member function] + cls.add_method('Install', + 'ns3::ApplicationContainer', + [param('ns3::NodeContainer', 'c')]) + return + +def register_Ns3WifiHelper_methods(root_module, cls): + ## wifi-helper.h: ns3::WifiHelper::WifiHelper(ns3::WifiHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiHelper const &', 'arg0')]) + ## wifi-helper.h: ns3::WifiHelper::WifiHelper() [constructor] + cls.add_constructor([]) + ## wifi-helper.h: void ns3::WifiHelper::SetRemoteStationManager(std::string type, std::string n0="", ns3::AttributeValue const & v0=ns3::EmptyAttributeValue(), std::string n1="", ns3::AttributeValue const & v1=ns3::EmptyAttributeValue(), std::string n2="", ns3::AttributeValue const & v2=ns3::EmptyAttributeValue(), std::string n3="", ns3::AttributeValue const & v3=ns3::EmptyAttributeValue(), std::string n4="", ns3::AttributeValue const & v4=ns3::EmptyAttributeValue(), std::string n5="", ns3::AttributeValue const & v5=ns3::EmptyAttributeValue(), std::string n6="", ns3::AttributeValue const & v6=ns3::EmptyAttributeValue(), std::string n7="", ns3::AttributeValue const & v7=ns3::EmptyAttributeValue()) [member function] + cls.add_method('SetRemoteStationManager', + 'void', + [param('std::string', 'type'), param('std::string', 'n0', default_value='""'), param('ns3::AttributeValue const &', 'v0', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n1', default_value='""'), param('ns3::AttributeValue const &', 'v1', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n2', default_value='""'), param('ns3::AttributeValue const &', 'v2', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n3', default_value='""'), param('ns3::AttributeValue const &', 'v3', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n4', default_value='""'), param('ns3::AttributeValue const &', 'v4', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n5', default_value='""'), param('ns3::AttributeValue const &', 'v5', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n6', default_value='""'), param('ns3::AttributeValue const &', 'v6', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n7', default_value='""'), param('ns3::AttributeValue const &', 'v7', default_value='ns3::EmptyAttributeValue()')]) + ## wifi-helper.h: void ns3::WifiHelper::SetMac(std::string type, std::string n0="", ns3::AttributeValue const & v0=ns3::EmptyAttributeValue(), std::string n1="", ns3::AttributeValue const & v1=ns3::EmptyAttributeValue(), std::string n2="", ns3::AttributeValue const & v2=ns3::EmptyAttributeValue(), std::string n3="", ns3::AttributeValue const & v3=ns3::EmptyAttributeValue(), std::string n4="", ns3::AttributeValue const & v4=ns3::EmptyAttributeValue(), std::string n5="", ns3::AttributeValue const & v5=ns3::EmptyAttributeValue(), std::string n6="", ns3::AttributeValue const & v6=ns3::EmptyAttributeValue(), std::string n7="", ns3::AttributeValue const & v7=ns3::EmptyAttributeValue()) [member function] + cls.add_method('SetMac', + 'void', + [param('std::string', 'type'), param('std::string', 'n0', default_value='""'), param('ns3::AttributeValue const &', 'v0', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n1', default_value='""'), param('ns3::AttributeValue const &', 'v1', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n2', default_value='""'), param('ns3::AttributeValue const &', 'v2', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n3', default_value='""'), param('ns3::AttributeValue const &', 'v3', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n4', default_value='""'), param('ns3::AttributeValue const &', 'v4', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n5', default_value='""'), param('ns3::AttributeValue const &', 'v5', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n6', default_value='""'), param('ns3::AttributeValue const &', 'v6', default_value='ns3::EmptyAttributeValue()'), param('std::string', 'n7', default_value='""'), param('ns3::AttributeValue const &', 'v7', default_value='ns3::EmptyAttributeValue()')]) + ## wifi-helper.h: void ns3::WifiHelper::SetPhyAttribute(std::string n0, ns3::AttributeValue const & v0) [member function] + cls.add_method('SetPhyAttribute', + 'void', + [param('std::string', 'n0'), param('ns3::AttributeValue const &', 'v0')]) + ## wifi-helper.h: static void ns3::WifiHelper::EnablePcap(std::string filename, uint32_t nodeid, uint32_t deviceid) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('uint32_t', 'nodeid'), param('uint32_t', 'deviceid')], + is_static=True) + ## wifi-helper.h: static void ns3::WifiHelper::EnablePcap(std::string filename, ns3::NetDeviceContainer d) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('ns3::NetDeviceContainer', 'd')], + is_static=True) + ## wifi-helper.h: static void ns3::WifiHelper::EnablePcap(std::string filename, ns3::NodeContainer n) [member function] + cls.add_method('EnablePcap', + 'void', + [param('std::string', 'filename'), param('ns3::NodeContainer', 'n')], + is_static=True) + ## wifi-helper.h: static void ns3::WifiHelper::EnablePcapAll(std::string filename) [member function] + cls.add_method('EnablePcapAll', + 'void', + [param('std::string', 'filename')], + is_static=True) + ## wifi-helper.h: static void ns3::WifiHelper::EnableAscii(std::ostream & os, uint32_t nodeid, uint32_t deviceid) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('uint32_t', 'nodeid'), param('uint32_t', 'deviceid')], + is_static=True) + ## wifi-helper.h: static void ns3::WifiHelper::EnableAscii(std::ostream & os, ns3::NetDeviceContainer d) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('ns3::NetDeviceContainer', 'd')], + is_static=True) + ## wifi-helper.h: static void ns3::WifiHelper::EnableAscii(std::ostream & os, ns3::NodeContainer n) [member function] + cls.add_method('EnableAscii', + 'void', + [param('std::ostream &', 'os'), param('ns3::NodeContainer', 'n')], + is_static=True) + ## wifi-helper.h: static void ns3::WifiHelper::EnableAsciiAll(std::ostream & os) [member function] + cls.add_method('EnableAsciiAll', + 'void', + [param('std::ostream &', 'os')], + is_static=True) + ## wifi-helper.h: ns3::NetDeviceContainer ns3::WifiHelper::Install(ns3::NodeContainer c) const [member function] + cls.add_method('Install', + 'ns3::NetDeviceContainer', + [param('ns3::NodeContainer', 'c')], + is_const=True) + ## wifi-helper.h: ns3::NetDeviceContainer ns3::WifiHelper::Install(ns3::NodeContainer c, ns3::Ptr channel) const [member function] + cls.add_method('Install', + 'ns3::NetDeviceContainer', + [param('ns3::NodeContainer', 'c'), param('ns3::Ptr< ns3::WifiChannel >', 'channel')], + is_const=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_internet_stack.py b/bindings/python/ns3_module_internet_stack.py new file mode 100644 index 000000000..439307348 --- /dev/null +++ b/bindings/python/ns3_module_internet_stack.py @@ -0,0 +1,662 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## tcp-header.h: ns3::TcpHeader [class] + module.add_class('TcpHeader', parent=root_module['ns3::Header']) + ## tcp-header.h: ns3::TcpHeader::Flags_t [enumeration] + module.add_enum('Flags_t', ['NONE', 'FIN', 'SYN', 'RST', 'PSH', 'ACK', 'URG'], outer_class=root_module['ns3::TcpHeader']) + ## udp-header.h: ns3::UdpHeader [class] + module.add_class('UdpHeader', parent=root_module['ns3::Header']) + ## ipv4-interface.h: ns3::Ipv4Interface [class] + module.add_class('Ipv4Interface', parent=root_module['ns3::Object']) + ## ipv4-l3-protocol.h: ns3::Ipv4L3Protocol [class] + module.add_class('Ipv4L3Protocol', parent=root_module['ns3::Object']) + ## ipv4-static-routing.h: ns3::Ipv4StaticRouting [class] + module.add_class('Ipv4StaticRouting', parent=root_module['ns3::Ipv4RoutingProtocol']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3TcpHeader_methods(root_module, root_module['ns3::TcpHeader']) + register_Ns3UdpHeader_methods(root_module, root_module['ns3::UdpHeader']) + register_Ns3Ipv4Interface_methods(root_module, root_module['ns3::Ipv4Interface']) + register_Ns3Ipv4L3Protocol_methods(root_module, root_module['ns3::Ipv4L3Protocol']) + register_Ns3Ipv4StaticRouting_methods(root_module, root_module['ns3::Ipv4StaticRouting']) + return + +def register_Ns3TcpHeader_methods(root_module, cls): + ## tcp-header.h: ns3::TcpHeader::TcpHeader(ns3::TcpHeader const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TcpHeader const &', 'arg0')]) + ## tcp-header.h: ns3::TcpHeader::TcpHeader() [constructor] + cls.add_constructor([]) + ## tcp-header.h: void ns3::TcpHeader::EnableChecksums() [member function] + cls.add_method('EnableChecksums', + 'void', + []) + ## tcp-header.h: void ns3::TcpHeader::SetSourcePort(uint16_t port) [member function] + cls.add_method('SetSourcePort', + 'void', + [param('uint16_t', 'port')]) + ## tcp-header.h: void ns3::TcpHeader::SetDestinationPort(uint16_t port) [member function] + cls.add_method('SetDestinationPort', + 'void', + [param('uint16_t', 'port')]) + ## tcp-header.h: void ns3::TcpHeader::SetSequenceNumber(SequenceNumber sequenceNumber) [member function] + cls.add_method('SetSequenceNumber', + 'void', + [param('SequenceNumber', 'sequenceNumber')]) + ## tcp-header.h: void ns3::TcpHeader::SetAckNumber(SequenceNumber ackNumber) [member function] + cls.add_method('SetAckNumber', + 'void', + [param('SequenceNumber', 'ackNumber')]) + ## tcp-header.h: void ns3::TcpHeader::SetLength(uint8_t length) [member function] + cls.add_method('SetLength', + 'void', + [param('uint8_t', 'length')]) + ## tcp-header.h: void ns3::TcpHeader::SetFlags(uint8_t flags) [member function] + cls.add_method('SetFlags', + 'void', + [param('uint8_t', 'flags')]) + ## tcp-header.h: void ns3::TcpHeader::SetWindowSize(uint16_t windowSize) [member function] + cls.add_method('SetWindowSize', + 'void', + [param('uint16_t', 'windowSize')]) + ## tcp-header.h: void ns3::TcpHeader::SetUrgentPointer(uint16_t urgentPointer) [member function] + cls.add_method('SetUrgentPointer', + 'void', + [param('uint16_t', 'urgentPointer')]) + ## tcp-header.h: uint16_t ns3::TcpHeader::GetSourcePort() const [member function] + cls.add_method('GetSourcePort', + 'uint16_t', + [], + is_const=True) + ## tcp-header.h: uint16_t ns3::TcpHeader::GetDestinationPort() const [member function] + cls.add_method('GetDestinationPort', + 'uint16_t', + [], + is_const=True) + ## tcp-header.h: SequenceNumber ns3::TcpHeader::GetSequenceNumber() const [member function] + cls.add_method('GetSequenceNumber', + 'SequenceNumber', + [], + is_const=True) + ## tcp-header.h: SequenceNumber ns3::TcpHeader::GetAckNumber() const [member function] + cls.add_method('GetAckNumber', + 'SequenceNumber', + [], + is_const=True) + ## tcp-header.h: uint8_t ns3::TcpHeader::GetLength() const [member function] + cls.add_method('GetLength', + 'uint8_t', + [], + is_const=True) + ## tcp-header.h: uint8_t ns3::TcpHeader::GetFlags() const [member function] + cls.add_method('GetFlags', + 'uint8_t', + [], + is_const=True) + ## tcp-header.h: uint16_t ns3::TcpHeader::GetWindowSize() const [member function] + cls.add_method('GetWindowSize', + 'uint16_t', + [], + is_const=True) + ## tcp-header.h: uint16_t ns3::TcpHeader::GetUrgentPointer() const [member function] + cls.add_method('GetUrgentPointer', + 'uint16_t', + [], + is_const=True) + ## tcp-header.h: void ns3::TcpHeader::InitializeChecksum(ns3::Ipv4Address source, ns3::Ipv4Address destination, uint8_t protocol) [member function] + cls.add_method('InitializeChecksum', + 'void', + [param('ns3::Ipv4Address', 'source'), param('ns3::Ipv4Address', 'destination'), param('uint8_t', 'protocol')]) + ## tcp-header.h: static ns3::TypeId ns3::TcpHeader::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## tcp-header.h: ns3::TypeId ns3::TcpHeader::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## tcp-header.h: void ns3::TcpHeader::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## tcp-header.h: uint32_t ns3::TcpHeader::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## tcp-header.h: void ns3::TcpHeader::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True, is_virtual=True) + ## tcp-header.h: uint32_t ns3::TcpHeader::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_virtual=True) + ## tcp-header.h: bool ns3::TcpHeader::IsChecksumOk() const [member function] + cls.add_method('IsChecksumOk', + 'bool', + [], + is_const=True) + return + +def register_Ns3UdpHeader_methods(root_module, cls): + ## udp-header.h: ns3::UdpHeader::UdpHeader(ns3::UdpHeader const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UdpHeader const &', 'arg0')]) + ## udp-header.h: ns3::UdpHeader::UdpHeader() [constructor] + cls.add_constructor([]) + ## udp-header.h: void ns3::UdpHeader::EnableChecksums() [member function] + cls.add_method('EnableChecksums', + 'void', + []) + ## udp-header.h: void ns3::UdpHeader::SetDestinationPort(uint16_t port) [member function] + cls.add_method('SetDestinationPort', + 'void', + [param('uint16_t', 'port')]) + ## udp-header.h: void ns3::UdpHeader::SetSourcePort(uint16_t port) [member function] + cls.add_method('SetSourcePort', + 'void', + [param('uint16_t', 'port')]) + ## udp-header.h: uint16_t ns3::UdpHeader::GetSourcePort() const [member function] + cls.add_method('GetSourcePort', + 'uint16_t', + [], + is_const=True) + ## udp-header.h: uint16_t ns3::UdpHeader::GetDestinationPort() const [member function] + cls.add_method('GetDestinationPort', + 'uint16_t', + [], + is_const=True) + ## udp-header.h: void ns3::UdpHeader::InitializeChecksum(ns3::Ipv4Address source, ns3::Ipv4Address destination, uint8_t protocol) [member function] + cls.add_method('InitializeChecksum', + 'void', + [param('ns3::Ipv4Address', 'source'), param('ns3::Ipv4Address', 'destination'), param('uint8_t', 'protocol')]) + ## udp-header.h: static ns3::TypeId ns3::UdpHeader::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## udp-header.h: ns3::TypeId ns3::UdpHeader::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## udp-header.h: void ns3::UdpHeader::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## udp-header.h: uint32_t ns3::UdpHeader::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## udp-header.h: void ns3::UdpHeader::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True, is_virtual=True) + ## udp-header.h: uint32_t ns3::UdpHeader::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_virtual=True) + ## udp-header.h: bool ns3::UdpHeader::IsChecksumOk() const [member function] + cls.add_method('IsChecksumOk', + 'bool', + [], + is_const=True) + return + +def register_Ns3Ipv4Interface_methods(root_module, cls): + ## ipv4-interface.h: ns3::Ipv4Interface::Ipv4Interface(ns3::Ipv4Interface const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4Interface const &', 'arg0')]) + ## ipv4-interface.h: static ns3::TypeId ns3::Ipv4Interface::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## ipv4-interface.h: ns3::Ipv4Interface::Ipv4Interface() [constructor] + cls.add_constructor([]) + ## ipv4-interface.h: ns3::Ptr ns3::Ipv4Interface::GetDevice() const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4-interface.h: void ns3::Ipv4Interface::SetAddress(ns3::Ipv4Address a) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Ipv4Address', 'a')]) + ## ipv4-interface.h: void ns3::Ipv4Interface::SetNetworkMask(ns3::Ipv4Mask mask) [member function] + cls.add_method('SetNetworkMask', + 'void', + [param('ns3::Ipv4Mask', 'mask')]) + ## ipv4-interface.h: ns3::Ipv4Address ns3::Ipv4Interface::GetBroadcast() const [member function] + cls.add_method('GetBroadcast', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-interface.h: ns3::Ipv4Mask ns3::Ipv4Interface::GetNetworkMask() const [member function] + cls.add_method('GetNetworkMask', + 'ns3::Ipv4Mask', + [], + is_const=True) + ## ipv4-interface.h: void ns3::Ipv4Interface::SetMetric(uint16_t metric) [member function] + cls.add_method('SetMetric', + 'void', + [param('uint16_t', 'metric')]) + ## ipv4-interface.h: uint16_t ns3::Ipv4Interface::GetMetric() const [member function] + cls.add_method('GetMetric', + 'uint16_t', + [], + is_const=True) + ## ipv4-interface.h: ns3::Ipv4Address ns3::Ipv4Interface::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-interface.h: uint16_t ns3::Ipv4Interface::GetMtu() const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [], + is_const=True) + ## ipv4-interface.h: bool ns3::Ipv4Interface::IsUp() const [member function] + cls.add_method('IsUp', + 'bool', + [], + is_const=True) + ## ipv4-interface.h: bool ns3::Ipv4Interface::IsDown() const [member function] + cls.add_method('IsDown', + 'bool', + [], + is_const=True) + ## ipv4-interface.h: void ns3::Ipv4Interface::SetUp() [member function] + cls.add_method('SetUp', + 'void', + []) + ## ipv4-interface.h: void ns3::Ipv4Interface::SetDown() [member function] + cls.add_method('SetDown', + 'void', + []) + ## ipv4-interface.h: void ns3::Ipv4Interface::Send(ns3::Ptr p, ns3::Ipv4Address dest) [member function] + cls.add_method('Send', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ipv4Address', 'dest')]) + ## ipv4-interface.h: void ns3::Ipv4Interface::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## ipv4-interface.h: void ns3::Ipv4Interface::SendTo(ns3::Ptr p, ns3::Ipv4Address dest) [member function] + cls.add_method('SendTo', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ipv4Address', 'dest')], + is_pure_virtual=True, visibility='private', is_virtual=True) + return + +def register_Ns3Ipv4L3Protocol_methods(root_module, cls): + ## ipv4-l3-protocol.h: ns3::Ipv4L3Protocol::PROT_NUMBER [variable] + cls.add_static_attribute('PROT_NUMBER', 'uint16_t const', is_const=True) + ## ipv4-l3-protocol.h: static ns3::TypeId ns3::Ipv4L3Protocol::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## ipv4-l3-protocol.h: ns3::Ipv4L3Protocol::Ipv4L3Protocol() [constructor] + cls.add_constructor([]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::Insert(ns3::Ptr protocol) [member function] + cls.add_method('Insert', + 'void', + [param('ns3::Ptr< ns3::Ipv4L4Protocol >', 'protocol')]) + ## ipv4-l3-protocol.h: ns3::Ptr ns3::Ipv4L3Protocol::GetProtocol(int protocolNumber) const [member function] + cls.add_method('GetProtocol', + 'ns3::Ptr< ns3::Ipv4L4Protocol >', + [param('int', 'protocolNumber')], + is_const=True) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::Remove(ns3::Ptr protocol) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::Ptr< ns3::Ipv4L4Protocol >', 'protocol')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetDefaultTtl(uint8_t ttl) [member function] + cls.add_method('SetDefaultTtl', + 'void', + [param('uint8_t', 'ttl')]) + ## ipv4-l3-protocol.h: ns3::Ptr ns3::Ipv4L3Protocol::FindInterfaceForDevice(ns3::Ptr device) [member function] + cls.add_method('FindInterfaceForDevice', + 'ns3::Ptr< ns3::Ipv4Interface >', + [param('ns3::Ptr< ns3::NetDevice const >', 'device')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::Receive(ns3::Ptr device, ns3::Ptr p, uint16_t protocol, ns3::Address const & from, ns3::Address const & to, ns3::NetDevice::PacketType packetType) [member function] + cls.add_method('Receive', + 'void', + [param('ns3::Ptr< ns3::NetDevice >', 'device'), param('ns3::Ptr< ns3::Packet const >', 'p'), param('uint16_t', 'protocol'), param('ns3::Address const &', 'from'), param('ns3::Address const &', 'to'), param('ns3::NetDevice::PacketType', 'packetType')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::Send(ns3::Ptr packet, ns3::Ipv4Address source, ns3::Ipv4Address destination, uint8_t protocol) [member function] + cls.add_method('Send', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Ipv4Address', 'source'), param('ns3::Ipv4Address', 'destination'), param('uint8_t', 'protocol')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::AddHostRouteTo(ns3::Ipv4Address dest, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('AddHostRouteTo', + 'void', + [param('ns3::Ipv4Address', 'dest'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::AddHostRouteTo(ns3::Ipv4Address dest, uint32_t interface) [member function] + cls.add_method('AddHostRouteTo', + 'void', + [param('ns3::Ipv4Address', 'dest'), param('uint32_t', 'interface')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::AddNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('AddNetworkRouteTo', + 'void', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::AddNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, uint32_t interface) [member function] + cls.add_method('AddNetworkRouteTo', + 'void', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('uint32_t', 'interface')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetDefaultRoute(ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('SetDefaultRoute', + 'void', + [param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::Lookup(ns3::Ipv4Header const & ipHeader, ns3::Ptr packet, ns3::Callback,const ns3::Ipv4Header&,ns3::empty,ns3::empty> routeReply) [member function] + cls.add_method('Lookup', + 'void', + [param('ns3::Ipv4Header const &', 'ipHeader'), param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Callback< void, bool, ns3::Ipv4Route const &, ns3::Ptr< ns3::Packet >, ns3::Ipv4Header const &, ns3::empty, ns3::empty >', 'routeReply')]) + ## ipv4-l3-protocol.h: uint32_t ns3::Ipv4L3Protocol::GetNRoutes() [member function] + cls.add_method('GetNRoutes', + 'uint32_t', + []) + ## ipv4-l3-protocol.h: ns3::Ipv4Route * ns3::Ipv4L3Protocol::GetRoute(uint32_t i) [member function] + cls.add_method('GetRoute', + 'ns3::Ipv4Route *', + [param('uint32_t', 'i')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::RemoveRoute(uint32_t i) [member function] + cls.add_method('RemoveRoute', + 'void', + [param('uint32_t', 'i')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::AddMulticastRoute(ns3::Ipv4Address origin, ns3::Ipv4Address group, uint32_t inputInterface, std::vector > outputInterfaces) [member function] + cls.add_method('AddMulticastRoute', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group'), param('uint32_t', 'inputInterface'), param('std::vector< unsigned int >', 'outputInterfaces')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetDefaultMulticastRoute(uint32_t onputInterface) [member function] + cls.add_method('SetDefaultMulticastRoute', + 'void', + [param('uint32_t', 'onputInterface')]) + ## ipv4-l3-protocol.h: uint32_t ns3::Ipv4L3Protocol::GetNMulticastRoutes() const [member function] + cls.add_method('GetNMulticastRoutes', + 'uint32_t', + [], + is_const=True) + ## ipv4-l3-protocol.h: ns3::Ipv4MulticastRoute * ns3::Ipv4L3Protocol::GetMulticastRoute(uint32_t i) const [member function] + cls.add_method('GetMulticastRoute', + 'ns3::Ipv4MulticastRoute *', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::RemoveMulticastRoute(ns3::Ipv4Address origin, ns3::Ipv4Address group, uint32_t inputInterface) [member function] + cls.add_method('RemoveMulticastRoute', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group'), param('uint32_t', 'inputInterface')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::RemoveMulticastRoute(uint32_t i) [member function] + cls.add_method('RemoveMulticastRoute', + 'void', + [param('uint32_t', 'i')]) + ## ipv4-l3-protocol.h: uint32_t ns3::Ipv4L3Protocol::AddInterface(ns3::Ptr device) [member function] + cls.add_method('AddInterface', + 'uint32_t', + [param('ns3::Ptr< ns3::NetDevice >', 'device')]) + ## ipv4-l3-protocol.h: ns3::Ptr ns3::Ipv4L3Protocol::GetInterface(uint32_t i) const [member function] + cls.add_method('GetInterface', + 'ns3::Ptr< ns3::Ipv4Interface >', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-l3-protocol.h: uint32_t ns3::Ipv4L3Protocol::GetNInterfaces() const [member function] + cls.add_method('GetNInterfaces', + 'uint32_t', + [], + is_const=True) + ## ipv4-l3-protocol.h: uint32_t ns3::Ipv4L3Protocol::FindInterfaceForAddr(ns3::Ipv4Address addr) const [member function] + cls.add_method('FindInterfaceForAddr', + 'uint32_t', + [param('ns3::Ipv4Address', 'addr')], + is_const=True) + ## ipv4-l3-protocol.h: uint32_t ns3::Ipv4L3Protocol::FindInterfaceForAddr(ns3::Ipv4Address addr, ns3::Ipv4Mask mask) const [member function] + cls.add_method('FindInterfaceForAddr', + 'uint32_t', + [param('ns3::Ipv4Address', 'addr'), param('ns3::Ipv4Mask', 'mask')], + is_const=True) + ## ipv4-l3-protocol.h: int32_t ns3::Ipv4L3Protocol::FindInterfaceIndexForDevice(ns3::Ptr device) const [member function] + cls.add_method('FindInterfaceIndexForDevice', + 'int32_t', + [param('ns3::Ptr< ns3::NetDevice >', 'device')], + is_const=True) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::JoinMulticastGroup(ns3::Ipv4Address origin, ns3::Ipv4Address group) [member function] + cls.add_method('JoinMulticastGroup', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::LeaveMulticastGroup(ns3::Ipv4Address origin, ns3::Ipv4Address group) [member function] + cls.add_method('LeaveMulticastGroup', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetAddress(uint32_t i, ns3::Ipv4Address address) [member function] + cls.add_method('SetAddress', + 'void', + [param('uint32_t', 'i'), param('ns3::Ipv4Address', 'address')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetNetworkMask(uint32_t i, ns3::Ipv4Mask mask) [member function] + cls.add_method('SetNetworkMask', + 'void', + [param('uint32_t', 'i'), param('ns3::Ipv4Mask', 'mask')]) + ## ipv4-l3-protocol.h: ns3::Ipv4Mask ns3::Ipv4L3Protocol::GetNetworkMask(uint32_t t) const [member function] + cls.add_method('GetNetworkMask', + 'ns3::Ipv4Mask', + [param('uint32_t', 't')], + is_const=True) + ## ipv4-l3-protocol.h: ns3::Ipv4Address ns3::Ipv4L3Protocol::GetAddress(uint32_t i) const [member function] + cls.add_method('GetAddress', + 'ns3::Ipv4Address', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetMetric(uint32_t i, uint16_t metric) [member function] + cls.add_method('SetMetric', + 'void', + [param('uint32_t', 'i'), param('uint16_t', 'metric')]) + ## ipv4-l3-protocol.h: uint16_t ns3::Ipv4L3Protocol::GetMetric(uint32_t i) const [member function] + cls.add_method('GetMetric', + 'uint16_t', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-l3-protocol.h: bool ns3::Ipv4L3Protocol::GetIfIndexForDestination(ns3::Ipv4Address destination, uint32_t & ifIndex) const [member function] + cls.add_method('GetIfIndexForDestination', + 'bool', + [param('ns3::Ipv4Address', 'destination'), param('uint32_t &', 'ifIndex')], + is_const=True) + ## ipv4-l3-protocol.h: uint16_t ns3::Ipv4L3Protocol::GetMtu(uint32_t i) const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-l3-protocol.h: bool ns3::Ipv4L3Protocol::IsUp(uint32_t i) const [member function] + cls.add_method('IsUp', + 'bool', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetUp(uint32_t i) [member function] + cls.add_method('SetUp', + 'void', + [param('uint32_t', 'i')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::SetDown(uint32_t i) [member function] + cls.add_method('SetDown', + 'void', + [param('uint32_t', 'i')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::AddRoutingProtocol(ns3::Ptr routingProtocol, int priority) [member function] + cls.add_method('AddRoutingProtocol', + 'void', + [param('ns3::Ptr< ns3::Ipv4RoutingProtocol >', 'routingProtocol'), param('int', 'priority')]) + ## ipv4-l3-protocol.h: void ns3::Ipv4L3Protocol::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3Ipv4StaticRouting_methods(root_module, cls): + ## ipv4-static-routing.h: ns3::Ipv4StaticRouting::Ipv4StaticRouting(ns3::Ipv4StaticRouting const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4StaticRouting const &', 'arg0')]) + ## ipv4-static-routing.h: ns3::Ipv4StaticRouting::Ipv4StaticRouting() [constructor] + cls.add_constructor([]) + ## ipv4-static-routing.h: bool ns3::Ipv4StaticRouting::RequestRoute(uint32_t ifIndex, ns3::Ipv4Header const & ipHeader, ns3::Ptr packet, ns3::Callback,const ns3::Ipv4Header&,ns3::empty,ns3::empty> routeReply) [member function] + cls.add_method('RequestRoute', + 'bool', + [param('uint32_t', 'ifIndex'), param('ns3::Ipv4Header const &', 'ipHeader'), param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Callback< void, bool, ns3::Ipv4Route const &, ns3::Ptr< ns3::Packet >, ns3::Ipv4Header const &, ns3::empty, ns3::empty >', 'routeReply')], + is_virtual=True) + ## ipv4-static-routing.h: bool ns3::Ipv4StaticRouting::RequestIfIndex(ns3::Ipv4Address destination, uint32_t & ifIndex) [member function] + cls.add_method('RequestIfIndex', + 'bool', + [param('ns3::Ipv4Address', 'destination'), param('uint32_t &', 'ifIndex')], + is_virtual=True) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::AddHostRouteTo(ns3::Ipv4Address dest, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('AddHostRouteTo', + 'void', + [param('ns3::Ipv4Address', 'dest'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::AddHostRouteTo(ns3::Ipv4Address dest, uint32_t interface) [member function] + cls.add_method('AddHostRouteTo', + 'void', + [param('ns3::Ipv4Address', 'dest'), param('uint32_t', 'interface')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::AddNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('AddNetworkRouteTo', + 'void', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::AddNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, uint32_t interface) [member function] + cls.add_method('AddNetworkRouteTo', + 'void', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('uint32_t', 'interface')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::SetDefaultRoute(ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('SetDefaultRoute', + 'void', + [param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')]) + ## ipv4-static-routing.h: uint32_t ns3::Ipv4StaticRouting::GetNRoutes() [member function] + cls.add_method('GetNRoutes', + 'uint32_t', + []) + ## ipv4-static-routing.h: ns3::Ipv4Route * ns3::Ipv4StaticRouting::GetDefaultRoute() [member function] + cls.add_method('GetDefaultRoute', + 'ns3::Ipv4Route *', + []) + ## ipv4-static-routing.h: ns3::Ipv4Route * ns3::Ipv4StaticRouting::GetRoute(uint32_t i) [member function] + cls.add_method('GetRoute', + 'ns3::Ipv4Route *', + [param('uint32_t', 'i')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::RemoveRoute(uint32_t i) [member function] + cls.add_method('RemoveRoute', + 'void', + [param('uint32_t', 'i')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::AddMulticastRoute(ns3::Ipv4Address origin, ns3::Ipv4Address group, uint32_t inputInterface, std::vector > outputInterfaces) [member function] + cls.add_method('AddMulticastRoute', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group'), param('uint32_t', 'inputInterface'), param('std::vector< unsigned int >', 'outputInterfaces')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::SetDefaultMulticastRoute(uint32_t outputInterface) [member function] + cls.add_method('SetDefaultMulticastRoute', + 'void', + [param('uint32_t', 'outputInterface')]) + ## ipv4-static-routing.h: uint32_t ns3::Ipv4StaticRouting::GetNMulticastRoutes() const [member function] + cls.add_method('GetNMulticastRoutes', + 'uint32_t', + [], + is_const=True) + ## ipv4-static-routing.h: ns3::Ipv4MulticastRoute * ns3::Ipv4StaticRouting::GetMulticastRoute(uint32_t i) const [member function] + cls.add_method('GetMulticastRoute', + 'ns3::Ipv4MulticastRoute *', + [param('uint32_t', 'i')], + is_const=True) + ## ipv4-static-routing.h: ns3::Ipv4MulticastRoute * ns3::Ipv4StaticRouting::GetDefaultMulticastRoute() const [member function] + cls.add_method('GetDefaultMulticastRoute', + 'ns3::Ipv4MulticastRoute *', + [], + is_const=True) + ## ipv4-static-routing.h: bool ns3::Ipv4StaticRouting::RemoveMulticastRoute(ns3::Ipv4Address origin, ns3::Ipv4Address group, uint32_t inputInterface) [member function] + cls.add_method('RemoveMulticastRoute', + 'bool', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group'), param('uint32_t', 'inputInterface')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::RemoveMulticastRoute(uint32_t index) [member function] + cls.add_method('RemoveMulticastRoute', + 'void', + [param('uint32_t', 'index')]) + ## ipv4-static-routing.h: void ns3::Ipv4StaticRouting::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + ## internet-stack.h: extern void ns3::AddInternetStack(ns3::Ptr node) [free function] + module.add_function('AddInternetStack', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')]) + ## internet-stack.h: extern void ns3::AddNscInternetStack(ns3::Ptr node, std::string const & soname) [free function] + module.add_function('AddNscInternetStack', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node'), param('std::string const &', 'soname')]) + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_mobility.py b/bindings/python/ns3_module_mobility.py new file mode 100644 index 000000000..0b3cbb75e --- /dev/null +++ b/bindings/python/ns3_module_mobility.py @@ -0,0 +1,724 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## rectangle.h: ns3::Rectangle [class] + module.add_class('Rectangle') + ## rectangle.h: ns3::Rectangle::Side [enumeration] + module.add_enum('Side', ['RIGHT', 'LEFT', 'TOP', 'BOTTOM'], outer_class=root_module['ns3::Rectangle']) + ## static-speed-helper.h: ns3::StaticSpeedHelper [class] + module.add_class('StaticSpeedHelper', allow_subclassing=False) + ## vector.h: ns3::Vector [class] + module.add_class('Vector') + ## position-allocator.h: ns3::PositionAllocator [class] + module.add_class('PositionAllocator', parent=root_module['ns3::Object']) + ## position-allocator.h: ns3::RandomDiscPositionAllocator [class] + module.add_class('RandomDiscPositionAllocator', parent=root_module['ns3::PositionAllocator']) + ## position-allocator.h: ns3::RandomRectanglePositionAllocator [class] + module.add_class('RandomRectanglePositionAllocator', parent=root_module['ns3::PositionAllocator']) + ## rectangle.h: ns3::RectangleChecker [class] + module.add_class('RectangleChecker', parent=root_module['ns3::AttributeChecker']) + ## rectangle.h: ns3::RectangleValue [class] + module.add_class('RectangleValue', parent=root_module['ns3::AttributeValue']) + ## vector.h: ns3::VectorChecker [class] + module.add_class('VectorChecker', parent=root_module['ns3::AttributeChecker']) + ## vector.h: ns3::VectorValue [class] + module.add_class('VectorValue', parent=root_module['ns3::AttributeValue']) + ## position-allocator.h: ns3::GridPositionAllocator [class] + module.add_class('GridPositionAllocator', parent=root_module['ns3::PositionAllocator']) + ## position-allocator.h: ns3::GridPositionAllocator::LayoutType [enumeration] + module.add_enum('LayoutType', ['ROW_FIRST', 'COLUMN_FIRST'], outer_class=root_module['ns3::GridPositionAllocator']) + ## position-allocator.h: ns3::ListPositionAllocator [class] + module.add_class('ListPositionAllocator', parent=root_module['ns3::PositionAllocator']) + ## mobility-model.h: ns3::MobilityModel [class] + module.add_class('MobilityModel', parent=root_module['ns3::Object']) + ## random-direction-2d-mobility-model.h: ns3::RandomDirection2dMobilityModel [class] + module.add_class('RandomDirection2dMobilityModel', parent=root_module['ns3::MobilityModel']) + ## random-walk-2d-mobility-model.h: ns3::RandomWalk2dMobilityModel [class] + module.add_class('RandomWalk2dMobilityModel', parent=root_module['ns3::MobilityModel']) + ## random-walk-2d-mobility-model.h: ns3::RandomWalk2dMobilityModel::Mode [enumeration] + module.add_enum('Mode', ['MODE_DISTANCE', 'MODE_TIME'], outer_class=root_module['ns3::RandomWalk2dMobilityModel']) + ## random-waypoint-mobility-model.h: ns3::RandomWaypointMobilityModel [class] + module.add_class('RandomWaypointMobilityModel', parent=root_module['ns3::MobilityModel']) + ## static-mobility-model.h: ns3::StaticMobilityModel [class] + module.add_class('StaticMobilityModel', parent=root_module['ns3::MobilityModel']) + ## static-speed-mobility-model.h: ns3::StaticSpeedMobilityModel [class] + module.add_class('StaticSpeedMobilityModel', parent=root_module['ns3::MobilityModel']) + ## hierarchical-mobility-model.h: ns3::HierarchicalMobilityModel [class] + module.add_class('HierarchicalMobilityModel', parent=root_module['ns3::MobilityModel']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3Rectangle_methods(root_module, root_module['ns3::Rectangle']) + register_Ns3StaticSpeedHelper_methods(root_module, root_module['ns3::StaticSpeedHelper']) + register_Ns3Vector_methods(root_module, root_module['ns3::Vector']) + register_Ns3PositionAllocator_methods(root_module, root_module['ns3::PositionAllocator']) + register_Ns3RandomDiscPositionAllocator_methods(root_module, root_module['ns3::RandomDiscPositionAllocator']) + register_Ns3RandomRectanglePositionAllocator_methods(root_module, root_module['ns3::RandomRectanglePositionAllocator']) + register_Ns3RectangleChecker_methods(root_module, root_module['ns3::RectangleChecker']) + register_Ns3RectangleValue_methods(root_module, root_module['ns3::RectangleValue']) + register_Ns3VectorChecker_methods(root_module, root_module['ns3::VectorChecker']) + register_Ns3VectorValue_methods(root_module, root_module['ns3::VectorValue']) + register_Ns3GridPositionAllocator_methods(root_module, root_module['ns3::GridPositionAllocator']) + register_Ns3ListPositionAllocator_methods(root_module, root_module['ns3::ListPositionAllocator']) + register_Ns3MobilityModel_methods(root_module, root_module['ns3::MobilityModel']) + register_Ns3RandomDirection2dMobilityModel_methods(root_module, root_module['ns3::RandomDirection2dMobilityModel']) + register_Ns3RandomWalk2dMobilityModel_methods(root_module, root_module['ns3::RandomWalk2dMobilityModel']) + register_Ns3RandomWaypointMobilityModel_methods(root_module, root_module['ns3::RandomWaypointMobilityModel']) + register_Ns3StaticMobilityModel_methods(root_module, root_module['ns3::StaticMobilityModel']) + register_Ns3StaticSpeedMobilityModel_methods(root_module, root_module['ns3::StaticSpeedMobilityModel']) + register_Ns3HierarchicalMobilityModel_methods(root_module, root_module['ns3::HierarchicalMobilityModel']) + return + +def register_Ns3Rectangle_methods(root_module, cls): + cls.add_output_stream_operator() + ## rectangle.h: ns3::Rectangle::Rectangle(ns3::Rectangle const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Rectangle const &', 'arg0')]) + ## rectangle.h: ns3::Rectangle::Rectangle(double _xMin, double _xMax, double _yMin, double _yMax) [constructor] + cls.add_constructor([param('double', '_xMin'), param('double', '_xMax'), param('double', '_yMin'), param('double', '_yMax')]) + ## rectangle.h: ns3::Rectangle::Rectangle() [constructor] + cls.add_constructor([]) + ## rectangle.h: ns3::Vector ns3::Rectangle::CalculateIntersection(ns3::Vector const & current, ns3::Vector const & speed) const [member function] + cls.add_method('CalculateIntersection', + 'ns3::Vector', + [param('ns3::Vector const &', 'current'), param('ns3::Vector const &', 'speed')], + is_const=True) + ## rectangle.h: ns3::Rectangle::Side ns3::Rectangle::GetClosestSide(ns3::Vector const & position) const [member function] + cls.add_method('GetClosestSide', + 'ns3::Rectangle::Side', + [param('ns3::Vector const &', 'position')], + is_const=True) + ## rectangle.h: bool ns3::Rectangle::IsInside(ns3::Vector const & position) const [member function] + cls.add_method('IsInside', + 'bool', + [param('ns3::Vector const &', 'position')], + is_const=True) + ## rectangle.h: ns3::Rectangle::xMax [variable] + cls.add_instance_attribute('xMax', 'double', is_const=False) + ## rectangle.h: ns3::Rectangle::xMin [variable] + cls.add_instance_attribute('xMin', 'double', is_const=False) + ## rectangle.h: ns3::Rectangle::yMax [variable] + cls.add_instance_attribute('yMax', 'double', is_const=False) + ## rectangle.h: ns3::Rectangle::yMin [variable] + cls.add_instance_attribute('yMin', 'double', is_const=False) + return + +def register_Ns3StaticSpeedHelper_methods(root_module, cls): + ## static-speed-helper.h: ns3::StaticSpeedHelper::StaticSpeedHelper(ns3::StaticSpeedHelper const & arg0) [copy constructor] + cls.add_constructor([param('ns3::StaticSpeedHelper const &', 'arg0')]) + ## static-speed-helper.h: ns3::StaticSpeedHelper::StaticSpeedHelper() [constructor] + cls.add_constructor([]) + ## static-speed-helper.h: ns3::StaticSpeedHelper::StaticSpeedHelper(ns3::Vector const & position) [constructor] + cls.add_constructor([param('ns3::Vector const &', 'position')]) + ## static-speed-helper.h: ns3::StaticSpeedHelper::StaticSpeedHelper(ns3::Vector const & position, ns3::Vector const & vel) [constructor] + cls.add_constructor([param('ns3::Vector const &', 'position'), param('ns3::Vector const &', 'vel')]) + ## static-speed-helper.h: void ns3::StaticSpeedHelper::SetPosition(ns3::Vector const & position) [member function] + cls.add_method('SetPosition', + 'void', + [param('ns3::Vector const &', 'position')]) + ## static-speed-helper.h: ns3::Vector ns3::StaticSpeedHelper::GetCurrentPosition() const [member function] + cls.add_method('GetCurrentPosition', + 'ns3::Vector', + [], + is_const=True) + ## static-speed-helper.h: ns3::Vector ns3::StaticSpeedHelper::GetVelocity() const [member function] + cls.add_method('GetVelocity', + 'ns3::Vector', + [], + is_const=True) + ## static-speed-helper.h: void ns3::StaticSpeedHelper::SetVelocity(ns3::Vector const & vel) [member function] + cls.add_method('SetVelocity', + 'void', + [param('ns3::Vector const &', 'vel')]) + ## static-speed-helper.h: void ns3::StaticSpeedHelper::Pause() [member function] + cls.add_method('Pause', + 'void', + []) + ## static-speed-helper.h: void ns3::StaticSpeedHelper::Unpause() [member function] + cls.add_method('Unpause', + 'void', + []) + ## static-speed-helper.h: void ns3::StaticSpeedHelper::UpdateWithBounds(ns3::Rectangle const & rectangle) const [member function] + cls.add_method('UpdateWithBounds', + 'void', + [param('ns3::Rectangle const &', 'rectangle')], + is_const=True) + ## static-speed-helper.h: void ns3::StaticSpeedHelper::Update() const [member function] + cls.add_method('Update', + 'void', + [], + is_const=True) + return + +def register_Ns3Vector_methods(root_module, cls): + cls.add_output_stream_operator() + ## vector.h: ns3::Vector::Vector(ns3::Vector const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Vector const &', 'arg0')]) + ## vector.h: ns3::Vector::Vector(double _x, double _y, double _z) [constructor] + cls.add_constructor([param('double', '_x'), param('double', '_y'), param('double', '_z')]) + ## vector.h: ns3::Vector::Vector() [constructor] + cls.add_constructor([]) + ## vector.h: ns3::Vector::x [variable] + cls.add_instance_attribute('x', 'double', is_const=False) + ## vector.h: ns3::Vector::y [variable] + cls.add_instance_attribute('y', 'double', is_const=False) + ## vector.h: ns3::Vector::z [variable] + cls.add_instance_attribute('z', 'double', is_const=False) + return + +def register_Ns3PositionAllocator_methods(root_module, cls): + ## position-allocator.h: ns3::PositionAllocator::PositionAllocator(ns3::PositionAllocator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PositionAllocator const &', 'arg0')]) + ## position-allocator.h: static ns3::TypeId ns3::PositionAllocator::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## position-allocator.h: ns3::PositionAllocator::PositionAllocator() [constructor] + cls.add_constructor([]) + ## position-allocator.h: ns3::Vector ns3::PositionAllocator::GetNext() const [member function] + cls.add_method('GetNext', + 'ns3::Vector', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3RandomDiscPositionAllocator_methods(root_module, cls): + ## position-allocator.h: ns3::RandomDiscPositionAllocator::RandomDiscPositionAllocator(ns3::RandomDiscPositionAllocator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomDiscPositionAllocator const &', 'arg0')]) + ## position-allocator.h: static ns3::TypeId ns3::RandomDiscPositionAllocator::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## position-allocator.h: ns3::RandomDiscPositionAllocator::RandomDiscPositionAllocator() [constructor] + cls.add_constructor([]) + ## position-allocator.h: void ns3::RandomDiscPositionAllocator::SetTheta(ns3::RandomVariable theta) [member function] + cls.add_method('SetTheta', + 'void', + [param('ns3::RandomVariable', 'theta')]) + ## position-allocator.h: void ns3::RandomDiscPositionAllocator::SetRho(ns3::RandomVariable rho) [member function] + cls.add_method('SetRho', + 'void', + [param('ns3::RandomVariable', 'rho')]) + ## position-allocator.h: void ns3::RandomDiscPositionAllocator::SetX(double x) [member function] + cls.add_method('SetX', + 'void', + [param('double', 'x')]) + ## position-allocator.h: void ns3::RandomDiscPositionAllocator::SetY(double y) [member function] + cls.add_method('SetY', + 'void', + [param('double', 'y')]) + ## position-allocator.h: ns3::Vector ns3::RandomDiscPositionAllocator::GetNext() const [member function] + cls.add_method('GetNext', + 'ns3::Vector', + [], + is_const=True, is_virtual=True) + return + +def register_Ns3RandomRectanglePositionAllocator_methods(root_module, cls): + ## position-allocator.h: ns3::RandomRectanglePositionAllocator::RandomRectanglePositionAllocator(ns3::RandomRectanglePositionAllocator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomRectanglePositionAllocator const &', 'arg0')]) + ## position-allocator.h: static ns3::TypeId ns3::RandomRectanglePositionAllocator::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## position-allocator.h: ns3::RandomRectanglePositionAllocator::RandomRectanglePositionAllocator() [constructor] + cls.add_constructor([]) + ## position-allocator.h: void ns3::RandomRectanglePositionAllocator::SetX(ns3::RandomVariable x) [member function] + cls.add_method('SetX', + 'void', + [param('ns3::RandomVariable', 'x')]) + ## position-allocator.h: void ns3::RandomRectanglePositionAllocator::SetY(ns3::RandomVariable y) [member function] + cls.add_method('SetY', + 'void', + [param('ns3::RandomVariable', 'y')]) + ## position-allocator.h: ns3::Vector ns3::RandomRectanglePositionAllocator::GetNext() const [member function] + cls.add_method('GetNext', + 'ns3::Vector', + [], + is_const=True, is_virtual=True) + return + +def register_Ns3RectangleChecker_methods(root_module, cls): + ## rectangle.h: ns3::RectangleChecker::RectangleChecker(ns3::RectangleChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RectangleChecker const &', 'arg0')]) + ## rectangle.h: ns3::RectangleChecker::RectangleChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3RectangleValue_methods(root_module, cls): + ## rectangle.h: ns3::RectangleValue::RectangleValue(ns3::RectangleValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RectangleValue const &', 'arg0')]) + ## rectangle.h: ns3::RectangleValue::RectangleValue() [constructor] + cls.add_constructor([]) + ## rectangle.h: ns3::RectangleValue::RectangleValue(ns3::Rectangle const & value) [constructor] + cls.add_constructor([param('ns3::Rectangle const &', 'value')]) + ## rectangle.h: void ns3::RectangleValue::Set(ns3::Rectangle const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Rectangle const &', 'value')]) + ## rectangle.h: ns3::Rectangle ns3::RectangleValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Rectangle', + [], + is_const=True) + ## rectangle.h: ns3::Ptr ns3::RectangleValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## rectangle.h: std::string ns3::RectangleValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## rectangle.h: bool ns3::RectangleValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3VectorChecker_methods(root_module, cls): + ## vector.h: ns3::VectorChecker::VectorChecker(ns3::VectorChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::VectorChecker const &', 'arg0')]) + ## vector.h: ns3::VectorChecker::VectorChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3VectorValue_methods(root_module, cls): + ## vector.h: ns3::VectorValue::VectorValue(ns3::VectorValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::VectorValue const &', 'arg0')]) + ## vector.h: ns3::VectorValue::VectorValue() [constructor] + cls.add_constructor([]) + ## vector.h: ns3::VectorValue::VectorValue(ns3::Vector const & value) [constructor] + cls.add_constructor([param('ns3::Vector const &', 'value')]) + ## vector.h: void ns3::VectorValue::Set(ns3::Vector const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Vector const &', 'value')]) + ## vector.h: ns3::Vector ns3::VectorValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Vector', + [], + is_const=True) + ## vector.h: ns3::Ptr ns3::VectorValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## vector.h: std::string ns3::VectorValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## vector.h: bool ns3::VectorValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3GridPositionAllocator_methods(root_module, cls): + ## position-allocator.h: ns3::GridPositionAllocator::GridPositionAllocator(ns3::GridPositionAllocator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::GridPositionAllocator const &', 'arg0')]) + ## position-allocator.h: static ns3::TypeId ns3::GridPositionAllocator::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## position-allocator.h: ns3::GridPositionAllocator::GridPositionAllocator() [constructor] + cls.add_constructor([]) + ## position-allocator.h: void ns3::GridPositionAllocator::SetMinX(double xMin) [member function] + cls.add_method('SetMinX', + 'void', + [param('double', 'xMin')]) + ## position-allocator.h: void ns3::GridPositionAllocator::SetMinY(double yMin) [member function] + cls.add_method('SetMinY', + 'void', + [param('double', 'yMin')]) + ## position-allocator.h: void ns3::GridPositionAllocator::SetDeltaX(double deltaX) [member function] + cls.add_method('SetDeltaX', + 'void', + [param('double', 'deltaX')]) + ## position-allocator.h: void ns3::GridPositionAllocator::SetDeltaY(double deltaY) [member function] + cls.add_method('SetDeltaY', + 'void', + [param('double', 'deltaY')]) + ## position-allocator.h: void ns3::GridPositionAllocator::SetN(uint32_t n) [member function] + cls.add_method('SetN', + 'void', + [param('uint32_t', 'n')]) + ## position-allocator.h: void ns3::GridPositionAllocator::SetLayoutType(ns3::GridPositionAllocator::LayoutType layoutType) [member function] + cls.add_method('SetLayoutType', + 'void', + [param('ns3::GridPositionAllocator::LayoutType', 'layoutType')]) + ## position-allocator.h: double ns3::GridPositionAllocator::GetMinX() const [member function] + cls.add_method('GetMinX', + 'double', + [], + is_const=True) + ## position-allocator.h: double ns3::GridPositionAllocator::GetMinY() const [member function] + cls.add_method('GetMinY', + 'double', + [], + is_const=True) + ## position-allocator.h: double ns3::GridPositionAllocator::GetDeltaX() const [member function] + cls.add_method('GetDeltaX', + 'double', + [], + is_const=True) + ## position-allocator.h: double ns3::GridPositionAllocator::GetDeltaY() const [member function] + cls.add_method('GetDeltaY', + 'double', + [], + is_const=True) + ## position-allocator.h: uint32_t ns3::GridPositionAllocator::GetN() const [member function] + cls.add_method('GetN', + 'uint32_t', + [], + is_const=True) + ## position-allocator.h: ns3::GridPositionAllocator::LayoutType ns3::GridPositionAllocator::GetLayoutType() const [member function] + cls.add_method('GetLayoutType', + 'ns3::GridPositionAllocator::LayoutType', + [], + is_const=True) + ## position-allocator.h: ns3::Vector ns3::GridPositionAllocator::GetNext() const [member function] + cls.add_method('GetNext', + 'ns3::Vector', + [], + is_const=True, is_virtual=True) + return + +def register_Ns3ListPositionAllocator_methods(root_module, cls): + ## position-allocator.h: ns3::ListPositionAllocator::ListPositionAllocator(ns3::ListPositionAllocator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ListPositionAllocator const &', 'arg0')]) + ## position-allocator.h: static ns3::TypeId ns3::ListPositionAllocator::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## position-allocator.h: ns3::ListPositionAllocator::ListPositionAllocator() [constructor] + cls.add_constructor([]) + ## position-allocator.h: void ns3::ListPositionAllocator::Add(ns3::Vector v) [member function] + cls.add_method('Add', + 'void', + [param('ns3::Vector', 'v')]) + ## position-allocator.h: ns3::Vector ns3::ListPositionAllocator::GetNext() const [member function] + cls.add_method('GetNext', + 'ns3::Vector', + [], + is_const=True, is_virtual=True) + return + +def register_Ns3MobilityModel_methods(root_module, cls): + ## mobility-model.h: ns3::MobilityModel::MobilityModel(ns3::MobilityModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::MobilityModel const &', 'arg0')]) + ## mobility-model.h: static ns3::TypeId ns3::MobilityModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## mobility-model.h: ns3::MobilityModel::MobilityModel() [constructor] + cls.add_constructor([]) + ## mobility-model.h: ns3::Vector ns3::MobilityModel::GetPosition() const [member function] + cls.add_method('GetPosition', + 'ns3::Vector', + [], + is_const=True) + ## mobility-model.h: void ns3::MobilityModel::SetPosition(ns3::Vector const & position) [member function] + cls.add_method('SetPosition', + 'void', + [param('ns3::Vector const &', 'position')]) + ## mobility-model.h: ns3::Vector ns3::MobilityModel::GetVelocity() const [member function] + cls.add_method('GetVelocity', + 'ns3::Vector', + [], + is_const=True) + ## mobility-model.h: double ns3::MobilityModel::GetDistanceFrom(ns3::Ptr position) const [member function] + cls.add_method('GetDistanceFrom', + 'double', + [param('ns3::Ptr< ns3::MobilityModel const >', 'position')], + is_const=True) + ## mobility-model.h: void ns3::MobilityModel::NotifyCourseChange() const [member function] + cls.add_method('NotifyCourseChange', + 'void', + [], + is_const=True, visibility='protected') + ## mobility-model.h: ns3::Vector ns3::MobilityModel::DoGetPosition() const [member function] + cls.add_method('DoGetPosition', + 'ns3::Vector', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## mobility-model.h: void ns3::MobilityModel::DoSetPosition(ns3::Vector const & position) [member function] + cls.add_method('DoSetPosition', + 'void', + [param('ns3::Vector const &', 'position')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## mobility-model.h: ns3::Vector ns3::MobilityModel::DoGetVelocity() const [member function] + cls.add_method('DoGetVelocity', + 'ns3::Vector', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3RandomDirection2dMobilityModel_methods(root_module, cls): + ## random-direction-2d-mobility-model.h: ns3::RandomDirection2dMobilityModel::RandomDirection2dMobilityModel(ns3::RandomDirection2dMobilityModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomDirection2dMobilityModel const &', 'arg0')]) + ## random-direction-2d-mobility-model.h: static ns3::TypeId ns3::RandomDirection2dMobilityModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## random-direction-2d-mobility-model.h: ns3::RandomDirection2dMobilityModel::RandomDirection2dMobilityModel() [constructor] + cls.add_constructor([]) + ## random-direction-2d-mobility-model.h: void ns3::RandomDirection2dMobilityModel::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + ## random-direction-2d-mobility-model.h: ns3::Vector ns3::RandomDirection2dMobilityModel::DoGetPosition() const [member function] + cls.add_method('DoGetPosition', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + ## random-direction-2d-mobility-model.h: void ns3::RandomDirection2dMobilityModel::DoSetPosition(ns3::Vector const & position) [member function] + cls.add_method('DoSetPosition', + 'void', + [param('ns3::Vector const &', 'position')], + visibility='private', is_virtual=True) + ## random-direction-2d-mobility-model.h: ns3::Vector ns3::RandomDirection2dMobilityModel::DoGetVelocity() const [member function] + cls.add_method('DoGetVelocity', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3RandomWalk2dMobilityModel_methods(root_module, cls): + ## random-walk-2d-mobility-model.h: ns3::RandomWalk2dMobilityModel::RandomWalk2dMobilityModel(ns3::RandomWalk2dMobilityModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomWalk2dMobilityModel const &', 'arg0')]) + ## random-walk-2d-mobility-model.h: static ns3::TypeId ns3::RandomWalk2dMobilityModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## random-walk-2d-mobility-model.h: ns3::RandomWalk2dMobilityModel::RandomWalk2dMobilityModel() [constructor] + cls.add_constructor([]) + ## random-walk-2d-mobility-model.h: void ns3::RandomWalk2dMobilityModel::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + ## random-walk-2d-mobility-model.h: ns3::Vector ns3::RandomWalk2dMobilityModel::DoGetPosition() const [member function] + cls.add_method('DoGetPosition', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + ## random-walk-2d-mobility-model.h: void ns3::RandomWalk2dMobilityModel::DoSetPosition(ns3::Vector const & position) [member function] + cls.add_method('DoSetPosition', + 'void', + [param('ns3::Vector const &', 'position')], + visibility='private', is_virtual=True) + ## random-walk-2d-mobility-model.h: ns3::Vector ns3::RandomWalk2dMobilityModel::DoGetVelocity() const [member function] + cls.add_method('DoGetVelocity', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3RandomWaypointMobilityModel_methods(root_module, cls): + ## random-waypoint-mobility-model.h: ns3::RandomWaypointMobilityModel::RandomWaypointMobilityModel(ns3::RandomWaypointMobilityModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomWaypointMobilityModel const &', 'arg0')]) + ## random-waypoint-mobility-model.h: static ns3::TypeId ns3::RandomWaypointMobilityModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## random-waypoint-mobility-model.h: ns3::RandomWaypointMobilityModel::RandomWaypointMobilityModel() [constructor] + cls.add_constructor([]) + ## random-waypoint-mobility-model.h: ns3::Vector ns3::RandomWaypointMobilityModel::DoGetPosition() const [member function] + cls.add_method('DoGetPosition', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + ## random-waypoint-mobility-model.h: void ns3::RandomWaypointMobilityModel::DoSetPosition(ns3::Vector const & position) [member function] + cls.add_method('DoSetPosition', + 'void', + [param('ns3::Vector const &', 'position')], + visibility='private', is_virtual=True) + ## random-waypoint-mobility-model.h: ns3::Vector ns3::RandomWaypointMobilityModel::DoGetVelocity() const [member function] + cls.add_method('DoGetVelocity', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3StaticMobilityModel_methods(root_module, cls): + ## static-mobility-model.h: ns3::StaticMobilityModel::StaticMobilityModel(ns3::StaticMobilityModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::StaticMobilityModel const &', 'arg0')]) + ## static-mobility-model.h: static ns3::TypeId ns3::StaticMobilityModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## static-mobility-model.h: ns3::StaticMobilityModel::StaticMobilityModel() [constructor] + cls.add_constructor([]) + ## static-mobility-model.h: ns3::Vector ns3::StaticMobilityModel::DoGetPosition() const [member function] + cls.add_method('DoGetPosition', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + ## static-mobility-model.h: void ns3::StaticMobilityModel::DoSetPosition(ns3::Vector const & position) [member function] + cls.add_method('DoSetPosition', + 'void', + [param('ns3::Vector const &', 'position')], + visibility='private', is_virtual=True) + ## static-mobility-model.h: ns3::Vector ns3::StaticMobilityModel::DoGetVelocity() const [member function] + cls.add_method('DoGetVelocity', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3StaticSpeedMobilityModel_methods(root_module, cls): + ## static-speed-mobility-model.h: ns3::StaticSpeedMobilityModel::StaticSpeedMobilityModel(ns3::StaticSpeedMobilityModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::StaticSpeedMobilityModel const &', 'arg0')]) + ## static-speed-mobility-model.h: static ns3::TypeId ns3::StaticSpeedMobilityModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## static-speed-mobility-model.h: ns3::StaticSpeedMobilityModel::StaticSpeedMobilityModel() [constructor] + cls.add_constructor([]) + ## static-speed-mobility-model.h: void ns3::StaticSpeedMobilityModel::SetVelocity(ns3::Vector const & speed) [member function] + cls.add_method('SetVelocity', + 'void', + [param('ns3::Vector const &', 'speed')]) + ## static-speed-mobility-model.h: ns3::Vector ns3::StaticSpeedMobilityModel::DoGetPosition() const [member function] + cls.add_method('DoGetPosition', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + ## static-speed-mobility-model.h: void ns3::StaticSpeedMobilityModel::DoSetPosition(ns3::Vector const & position) [member function] + cls.add_method('DoSetPosition', + 'void', + [param('ns3::Vector const &', 'position')], + visibility='private', is_virtual=True) + ## static-speed-mobility-model.h: ns3::Vector ns3::StaticSpeedMobilityModel::DoGetVelocity() const [member function] + cls.add_method('DoGetVelocity', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3HierarchicalMobilityModel_methods(root_module, cls): + ## hierarchical-mobility-model.h: ns3::HierarchicalMobilityModel::HierarchicalMobilityModel(ns3::HierarchicalMobilityModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::HierarchicalMobilityModel const &', 'arg0')]) + ## hierarchical-mobility-model.h: static ns3::TypeId ns3::HierarchicalMobilityModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## hierarchical-mobility-model.h: ns3::HierarchicalMobilityModel::HierarchicalMobilityModel() [constructor] + cls.add_constructor([]) + ## hierarchical-mobility-model.h: ns3::Ptr ns3::HierarchicalMobilityModel::GetChild() const [member function] + cls.add_method('GetChild', + 'ns3::Ptr< ns3::MobilityModel >', + [], + is_const=True) + ## hierarchical-mobility-model.h: ns3::Ptr ns3::HierarchicalMobilityModel::GetParent() const [member function] + cls.add_method('GetParent', + 'ns3::Ptr< ns3::MobilityModel >', + [], + is_const=True) + ## hierarchical-mobility-model.h: ns3::Vector ns3::HierarchicalMobilityModel::DoGetPosition() const [member function] + cls.add_method('DoGetPosition', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + ## hierarchical-mobility-model.h: void ns3::HierarchicalMobilityModel::DoSetPosition(ns3::Vector const & position) [member function] + cls.add_method('DoSetPosition', + 'void', + [param('ns3::Vector const &', 'position')], + visibility='private', is_virtual=True) + ## hierarchical-mobility-model.h: ns3::Vector ns3::HierarchicalMobilityModel::DoGetVelocity() const [member function] + cls.add_method('DoGetVelocity', + 'ns3::Vector', + [], + is_const=True, visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + ## rectangle.h: extern ns3::Ptr ns3::MakeRectangleChecker() [free function] + module.add_function('MakeRectangleChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## vector.h: extern double ns3::CalculateDistance(ns3::Vector const & a, ns3::Vector const & b) [free function] + module.add_function('CalculateDistance', + 'double', + [param('ns3::Vector const &', 'a'), param('ns3::Vector const &', 'b')]) + ## vector.h: extern ns3::Ptr ns3::MakeVectorChecker() [free function] + module.add_function('MakeVectorChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_node.py b/bindings/python/ns3_module_node.py new file mode 100644 index 000000000..805e8747e --- /dev/null +++ b/bindings/python/ns3_module_node.py @@ -0,0 +1,2646 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## ethernet-header.h: ns3::ethernet_header_t [enumeration] + module.add_enum('ethernet_header_t', ['LENGTH', 'VLAN', 'QINQ']) + ## address.h: ns3::Address [class] + module.add_class('Address') + ## address.h: ns3::Address::MaxSize_e [enumeration] + module.add_enum('MaxSize_e', ['MAX_SIZE'], outer_class=root_module['ns3::Address']) + ## inet-socket-address.h: ns3::InetSocketAddress [class] + module.add_class('InetSocketAddress') + ## inet-socket-address.h: ns3::InetSocketAddress [class] + root_module['ns3::InetSocketAddress'].implicitly_converts_to(root_module['ns3::Address']) + ## ipv4-address.h: ns3::Ipv4Address [class] + module.add_class('Ipv4Address') + ## ipv4-address.h: ns3::Ipv4Address [class] + root_module['ns3::Ipv4Address'].implicitly_converts_to(root_module['ns3::Address']) + ## ipv4-address-generator.h: ns3::Ipv4AddressGenerator [class] + module.add_class('Ipv4AddressGenerator') + ## ipv4-address.h: ns3::Ipv4Mask [class] + module.add_class('Ipv4Mask') + ## ipv4-route.h: ns3::Ipv4MulticastRoute [class] + module.add_class('Ipv4MulticastRoute') + ## ipv4-route.h: ns3::Ipv4Route [class] + module.add_class('Ipv4Route') + ## mac48-address.h: ns3::Mac48Address [class] + module.add_class('Mac48Address') + ## mac48-address.h: ns3::Mac48Address [class] + root_module['ns3::Mac48Address'].implicitly_converts_to(root_module['ns3::Address']) + ## mac64-address.h: ns3::Mac64Address [class] + module.add_class('Mac64Address') + ## mac64-address.h: ns3::Mac64Address [class] + root_module['ns3::Mac64Address'].implicitly_converts_to(root_module['ns3::Address']) + ## node-list.h: ns3::NodeList [class] + module.add_class('NodeList') + ## packet-socket-address.h: ns3::PacketSocketAddress [class] + module.add_class('PacketSocketAddress') + ## packet-socket-address.h: ns3::PacketSocketAddress [class] + root_module['ns3::PacketSocketAddress'].implicitly_converts_to(root_module['ns3::Address']) + ## ipv4-address.h: ns3::Ipv4AddressChecker [class] + module.add_class('Ipv4AddressChecker', parent=root_module['ns3::AttributeChecker']) + ## ipv4-address.h: ns3::Ipv4AddressValue [class] + module.add_class('Ipv4AddressValue', parent=root_module['ns3::AttributeValue']) + ## ipv4-header.h: ns3::Ipv4Header [class] + module.add_class('Ipv4Header', parent=root_module['ns3::Header']) + ## ipv4-address.h: ns3::Ipv4MaskChecker [class] + module.add_class('Ipv4MaskChecker', parent=root_module['ns3::AttributeChecker']) + ## ipv4-address.h: ns3::Ipv4MaskValue [class] + module.add_class('Ipv4MaskValue', parent=root_module['ns3::AttributeValue']) + ## llc-snap-header.h: ns3::LlcSnapHeader [class] + module.add_class('LlcSnapHeader', parent=root_module['ns3::Header']) + ## mac48-address.h: ns3::Mac48AddressChecker [class] + module.add_class('Mac48AddressChecker', parent=root_module['ns3::AttributeChecker']) + ## mac48-address.h: ns3::Mac48AddressValue [class] + module.add_class('Mac48AddressValue', parent=root_module['ns3::AttributeValue']) + ## queue.h: ns3::Queue [class] + module.add_class('Queue', parent=root_module['ns3::Object']) + ## socket.h: ns3::Socket [class] + module.add_class('Socket', parent=root_module['ns3::Object']) + ## socket.h: ns3::Socket::SocketErrno [enumeration] + module.add_enum('SocketErrno', ['ERROR_NOTERROR', 'ERROR_ISCONN', 'ERROR_NOTCONN', 'ERROR_MSGSIZE', 'ERROR_AGAIN', 'ERROR_SHUTDOWN', 'ERROR_OPNOTSUPP', 'ERROR_AFNOSUPPORT', 'ERROR_INVAL', 'ERROR_BADF', 'ERROR_NOROUTETOHOST', 'SOCKET_ERRNO_LAST'], outer_class=root_module['ns3::Socket']) + ## socket.h: ns3::SocketAddressTag [class] + module.add_class('SocketAddressTag', parent=root_module['ns3::Tag']) + ## socket-factory.h: ns3::SocketFactory [class] + module.add_class('SocketFactory', parent=root_module['ns3::Object']) + ## socket.h: ns3::SocketIpTtlTag [class] + module.add_class('SocketIpTtlTag', parent=root_module['ns3::Tag']) + ## tcp-socket.h: ns3::TcpSocket [class] + module.add_class('TcpSocket', parent=root_module['ns3::Socket']) + ## tcp-socket-factory.h: ns3::TcpSocketFactory [class] + module.add_class('TcpSocketFactory', parent=root_module['ns3::SocketFactory']) + ## udp-socket.h: ns3::UdpSocket [class] + module.add_class('UdpSocket', parent=root_module['ns3::Socket']) + ## udp-socket-factory.h: ns3::UdpSocketFactory [class] + module.add_class('UdpSocketFactory', parent=root_module['ns3::SocketFactory']) + ## address.h: ns3::AddressChecker [class] + module.add_class('AddressChecker', parent=root_module['ns3::AttributeChecker']) + ## address.h: ns3::AddressValue [class] + module.add_class('AddressValue', parent=root_module['ns3::AttributeValue']) + ## application.h: ns3::Application [class] + module.add_class('Application', parent=root_module['ns3::Object']) + ## channel.h: ns3::Channel [class] + module.add_class('Channel', parent=root_module['ns3::Object']) + ## drop-tail-queue.h: ns3::DropTailQueue [class] + module.add_class('DropTailQueue', parent=root_module['ns3::Queue']) + ## ethernet-header.h: ns3::EthernetHeader [class] + module.add_class('EthernetHeader', parent=root_module['ns3::Header']) + ## ethernet-trailer.h: ns3::EthernetTrailer [class] + module.add_class('EthernetTrailer', parent=root_module['ns3::Trailer']) + ## ipv4.h: ns3::Ipv4 [class] + module.add_class('Ipv4', parent=root_module['ns3::Object']) + ## ipv4.h: ns3::Ipv4RoutingProtocol [class] + module.add_class('Ipv4RoutingProtocol', parent=root_module['ns3::Object']) + ## net-device.h: ns3::NetDevice [class] + module.add_class('NetDevice', parent=root_module['ns3::Object']) + ## net-device.h: ns3::NetDevice::PacketType [enumeration] + module.add_enum('PacketType', ['PACKET_HOST', 'PACKET_BROADCAST', 'PACKET_MULTICAST', 'PACKET_OTHERHOST'], outer_class=root_module['ns3::NetDevice']) + ## node.h: ns3::Node [class] + module.add_class('Node', parent=root_module['ns3::Object']) + ## packet-socket-factory.h: ns3::PacketSocketFactory [class] + module.add_class('PacketSocketFactory', parent=root_module['ns3::SocketFactory']) + ## simple-channel.h: ns3::SimpleChannel [class] + module.add_class('SimpleChannel', parent=root_module['ns3::Channel']) + ## simple-net-device.h: ns3::SimpleNetDevice [class] + module.add_class('SimpleNetDevice', parent=root_module['ns3::NetDevice']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + module.add_container('std::vector< ns3::Ipv4Address >', 'ns3::Ipv4Address', container_type='vector') + +def register_methods(root_module): + register_Ns3Address_methods(root_module, root_module['ns3::Address']) + register_Ns3InetSocketAddress_methods(root_module, root_module['ns3::InetSocketAddress']) + register_Ns3Ipv4Address_methods(root_module, root_module['ns3::Ipv4Address']) + register_Ns3Ipv4AddressGenerator_methods(root_module, root_module['ns3::Ipv4AddressGenerator']) + register_Ns3Ipv4Mask_methods(root_module, root_module['ns3::Ipv4Mask']) + register_Ns3Ipv4MulticastRoute_methods(root_module, root_module['ns3::Ipv4MulticastRoute']) + register_Ns3Ipv4Route_methods(root_module, root_module['ns3::Ipv4Route']) + register_Ns3Mac48Address_methods(root_module, root_module['ns3::Mac48Address']) + register_Ns3Mac64Address_methods(root_module, root_module['ns3::Mac64Address']) + register_Ns3NodeList_methods(root_module, root_module['ns3::NodeList']) + register_Ns3PacketSocketAddress_methods(root_module, root_module['ns3::PacketSocketAddress']) + register_Ns3Ipv4AddressChecker_methods(root_module, root_module['ns3::Ipv4AddressChecker']) + register_Ns3Ipv4AddressValue_methods(root_module, root_module['ns3::Ipv4AddressValue']) + register_Ns3Ipv4Header_methods(root_module, root_module['ns3::Ipv4Header']) + register_Ns3Ipv4MaskChecker_methods(root_module, root_module['ns3::Ipv4MaskChecker']) + register_Ns3Ipv4MaskValue_methods(root_module, root_module['ns3::Ipv4MaskValue']) + register_Ns3LlcSnapHeader_methods(root_module, root_module['ns3::LlcSnapHeader']) + register_Ns3Mac48AddressChecker_methods(root_module, root_module['ns3::Mac48AddressChecker']) + register_Ns3Mac48AddressValue_methods(root_module, root_module['ns3::Mac48AddressValue']) + register_Ns3Queue_methods(root_module, root_module['ns3::Queue']) + register_Ns3Socket_methods(root_module, root_module['ns3::Socket']) + register_Ns3SocketAddressTag_methods(root_module, root_module['ns3::SocketAddressTag']) + register_Ns3SocketFactory_methods(root_module, root_module['ns3::SocketFactory']) + register_Ns3SocketIpTtlTag_methods(root_module, root_module['ns3::SocketIpTtlTag']) + register_Ns3TcpSocket_methods(root_module, root_module['ns3::TcpSocket']) + register_Ns3TcpSocketFactory_methods(root_module, root_module['ns3::TcpSocketFactory']) + register_Ns3UdpSocket_methods(root_module, root_module['ns3::UdpSocket']) + register_Ns3UdpSocketFactory_methods(root_module, root_module['ns3::UdpSocketFactory']) + register_Ns3AddressChecker_methods(root_module, root_module['ns3::AddressChecker']) + register_Ns3AddressValue_methods(root_module, root_module['ns3::AddressValue']) + register_Ns3Application_methods(root_module, root_module['ns3::Application']) + register_Ns3Channel_methods(root_module, root_module['ns3::Channel']) + register_Ns3DropTailQueue_methods(root_module, root_module['ns3::DropTailQueue']) + register_Ns3EthernetHeader_methods(root_module, root_module['ns3::EthernetHeader']) + register_Ns3EthernetTrailer_methods(root_module, root_module['ns3::EthernetTrailer']) + register_Ns3Ipv4_methods(root_module, root_module['ns3::Ipv4']) + register_Ns3Ipv4RoutingProtocol_methods(root_module, root_module['ns3::Ipv4RoutingProtocol']) + register_Ns3NetDevice_methods(root_module, root_module['ns3::NetDevice']) + register_Ns3Node_methods(root_module, root_module['ns3::Node']) + register_Ns3PacketSocketFactory_methods(root_module, root_module['ns3::PacketSocketFactory']) + register_Ns3SimpleChannel_methods(root_module, root_module['ns3::SimpleChannel']) + register_Ns3SimpleNetDevice_methods(root_module, root_module['ns3::SimpleNetDevice']) + return + +def register_Ns3Address_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_binary_comparison_operator('<') + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('==') + ## address.h: ns3::Address::Address() [constructor] + cls.add_constructor([]) + ## address.h: ns3::Address::Address(uint8_t type, uint8_t const * buffer, uint8_t len) [constructor] + cls.add_constructor([param('uint8_t', 'type'), param('uint8_t const *', 'buffer'), param('uint8_t', 'len')]) + ## address.h: ns3::Address::Address(ns3::Address const & address) [copy constructor] + cls.add_constructor([param('ns3::Address const &', 'address')]) + ## address.h: bool ns3::Address::CheckCompatible(uint8_t type, uint8_t len) const [member function] + cls.add_method('CheckCompatible', + 'bool', + [param('uint8_t', 'type'), param('uint8_t', 'len')], + is_const=True) + ## address.h: uint32_t ns3::Address::CopyAllFrom(uint8_t const * buffer, uint8_t len) [member function] + cls.add_method('CopyAllFrom', + 'uint32_t', + [param('uint8_t const *', 'buffer'), param('uint8_t', 'len')]) + ## address.h: uint32_t ns3::Address::CopyAllTo(uint8_t * buffer, uint8_t len) const [member function] + cls.add_method('CopyAllTo', + 'uint32_t', + [param('uint8_t *', 'buffer'), param('uint8_t', 'len')], + is_const=True) + ## address.h: uint32_t ns3::Address::CopyFrom(uint8_t const * buffer, uint8_t len) [member function] + cls.add_method('CopyFrom', + 'uint32_t', + [param('uint8_t const *', 'buffer'), param('uint8_t', 'len')]) + ## address.h: uint32_t ns3::Address::CopyTo(uint8_t * buffer) const [member function] + cls.add_method('CopyTo', + 'uint32_t', + [param('uint8_t *', 'buffer')], + is_const=True) + ## address.h: void ns3::Address::Deserialize(ns3::TagBuffer buffer) [member function] + cls.add_method('Deserialize', + 'void', + [param('ns3::TagBuffer', 'buffer')]) + ## address.h: uint8_t ns3::Address::GetLength() const [member function] + cls.add_method('GetLength', + 'uint8_t', + [], + is_const=True) + ## address.h: uint32_t ns3::Address::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## address.h: bool ns3::Address::IsInvalid() const [member function] + cls.add_method('IsInvalid', + 'bool', + [], + is_const=True) + ## address.h: bool ns3::Address::IsMatchingType(uint8_t type) const [member function] + cls.add_method('IsMatchingType', + 'bool', + [param('uint8_t', 'type')], + is_const=True) + ## address.h: static uint8_t ns3::Address::Register() [member function] + cls.add_method('Register', + 'uint8_t', + [], + is_static=True) + ## address.h: void ns3::Address::Serialize(ns3::TagBuffer buffer) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::TagBuffer', 'buffer')], + is_const=True) + return + +def register_Ns3InetSocketAddress_methods(root_module, cls): + ## inet-socket-address.h: ns3::InetSocketAddress::InetSocketAddress(ns3::InetSocketAddress const & arg0) [copy constructor] + cls.add_constructor([param('ns3::InetSocketAddress const &', 'arg0')]) + ## inet-socket-address.h: ns3::InetSocketAddress::InetSocketAddress(ns3::Ipv4Address ipv4, uint16_t port) [constructor] + cls.add_constructor([param('ns3::Ipv4Address', 'ipv4'), param('uint16_t', 'port')]) + ## inet-socket-address.h: ns3::InetSocketAddress::InetSocketAddress(ns3::Ipv4Address ipv4) [constructor] + cls.add_constructor([param('ns3::Ipv4Address', 'ipv4')]) + ## inet-socket-address.h: ns3::InetSocketAddress::InetSocketAddress(uint16_t port) [constructor] + cls.add_constructor([param('uint16_t', 'port')]) + ## inet-socket-address.h: ns3::InetSocketAddress::InetSocketAddress(char const * ipv4, uint16_t port) [constructor] + cls.add_constructor([param('char const *', 'ipv4'), param('uint16_t', 'port')]) + ## inet-socket-address.h: ns3::InetSocketAddress::InetSocketAddress(char const * ipv4) [constructor] + cls.add_constructor([param('char const *', 'ipv4')]) + ## inet-socket-address.h: uint16_t ns3::InetSocketAddress::GetPort() const [member function] + cls.add_method('GetPort', + 'uint16_t', + [], + is_const=True) + ## inet-socket-address.h: ns3::Ipv4Address ns3::InetSocketAddress::GetIpv4() const [member function] + cls.add_method('GetIpv4', + 'ns3::Ipv4Address', + [], + is_const=True) + ## inet-socket-address.h: void ns3::InetSocketAddress::SetPort(uint16_t port) [member function] + cls.add_method('SetPort', + 'void', + [param('uint16_t', 'port')]) + ## inet-socket-address.h: void ns3::InetSocketAddress::SetIpv4(ns3::Ipv4Address address) [member function] + cls.add_method('SetIpv4', + 'void', + [param('ns3::Ipv4Address', 'address')]) + ## inet-socket-address.h: static bool ns3::InetSocketAddress::IsMatchingType(ns3::Address const & address) [member function] + cls.add_method('IsMatchingType', + 'bool', + [param('ns3::Address const &', 'address')], + is_static=True) + ## inet-socket-address.h: static ns3::InetSocketAddress ns3::InetSocketAddress::ConvertFrom(ns3::Address const & address) [member function] + cls.add_method('ConvertFrom', + 'ns3::InetSocketAddress', + [param('ns3::Address const &', 'address')], + is_static=True) + return + +def register_Ns3Ipv4Address_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_binary_comparison_operator('<') + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('==') + ## ipv4-address.h: ns3::Ipv4Address::Ipv4Address(ns3::Ipv4Address const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4Address const &', 'arg0')]) + ## ipv4-address.h: ns3::Ipv4Address::Ipv4Address() [constructor] + cls.add_constructor([]) + ## ipv4-address.h: ns3::Ipv4Address::Ipv4Address(uint32_t address) [constructor] + cls.add_constructor([param('uint32_t', 'address')]) + ## ipv4-address.h: ns3::Ipv4Address::Ipv4Address(char const * address) [constructor] + cls.add_constructor([param('char const *', 'address')]) + ## ipv4-address.h: ns3::Ipv4Address ns3::Ipv4Address::CombineMask(ns3::Ipv4Mask const & mask) const [member function] + cls.add_method('CombineMask', + 'ns3::Ipv4Address', + [param('ns3::Ipv4Mask const &', 'mask')], + is_const=True) + ## ipv4-address.h: static ns3::Ipv4Address ns3::Ipv4Address::ConvertFrom(ns3::Address const & address) [member function] + cls.add_method('ConvertFrom', + 'ns3::Ipv4Address', + [param('ns3::Address const &', 'address')], + is_static=True) + ## ipv4-address.h: static ns3::Ipv4Address ns3::Ipv4Address::Deserialize(uint8_t const * buf) [member function] + cls.add_method('Deserialize', + 'ns3::Ipv4Address', + [param('uint8_t const *', 'buf')], + is_static=True) + ## ipv4-address.h: uint32_t ns3::Ipv4Address::Get() const [member function] + cls.add_method('Get', + 'uint32_t', + [], + is_const=True) + ## ipv4-address.h: static ns3::Ipv4Address ns3::Ipv4Address::GetAny() [member function] + cls.add_method('GetAny', + 'ns3::Ipv4Address', + [], + is_static=True) + ## ipv4-address.h: static ns3::Ipv4Address ns3::Ipv4Address::GetBroadcast() [member function] + cls.add_method('GetBroadcast', + 'ns3::Ipv4Address', + [], + is_static=True) + ## ipv4-address.h: static ns3::Ipv4Address ns3::Ipv4Address::GetLoopback() [member function] + cls.add_method('GetLoopback', + 'ns3::Ipv4Address', + [], + is_static=True) + ## ipv4-address.h: ns3::Ipv4Address ns3::Ipv4Address::GetSubnetDirectedBroadcast(ns3::Ipv4Mask const & mask) const [member function] + cls.add_method('GetSubnetDirectedBroadcast', + 'ns3::Ipv4Address', + [param('ns3::Ipv4Mask const &', 'mask')], + is_const=True) + ## ipv4-address.h: static ns3::Ipv4Address ns3::Ipv4Address::GetZero() [member function] + cls.add_method('GetZero', + 'ns3::Ipv4Address', + [], + is_static=True) + ## ipv4-address.h: bool ns3::Ipv4Address::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True) + ## ipv4-address.h: bool ns3::Ipv4Address::IsEqual(ns3::Ipv4Address const & other) const [member function] + cls.add_method('IsEqual', + 'bool', + [param('ns3::Ipv4Address const &', 'other')], + is_const=True) + ## ipv4-address.h: static bool ns3::Ipv4Address::IsMatchingType(ns3::Address const & address) [member function] + cls.add_method('IsMatchingType', + 'bool', + [param('ns3::Address const &', 'address')], + is_static=True) + ## ipv4-address.h: bool ns3::Ipv4Address::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_const=True) + ## ipv4-address.h: bool ns3::Ipv4Address::IsSubnetDirectedBroadcast(ns3::Ipv4Mask const & mask) const [member function] + cls.add_method('IsSubnetDirectedBroadcast', + 'bool', + [param('ns3::Ipv4Mask const &', 'mask')], + is_const=True) + ## ipv4-address.h: void ns3::Ipv4Address::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## ipv4-address.h: void ns3::Ipv4Address::Serialize(uint8_t * buf) const [member function] + cls.add_method('Serialize', + 'void', + [param('uint8_t *', 'buf')], + is_const=True) + ## ipv4-address.h: void ns3::Ipv4Address::Set(uint32_t address) [member function] + cls.add_method('Set', + 'void', + [param('uint32_t', 'address')]) + ## ipv4-address.h: void ns3::Ipv4Address::Set(char const * address) [member function] + cls.add_method('Set', + 'void', + [param('char const *', 'address')]) + return + +def register_Ns3Ipv4AddressGenerator_methods(root_module, cls): + ## ipv4-address-generator.h: ns3::Ipv4AddressGenerator::Ipv4AddressGenerator(ns3::Ipv4AddressGenerator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4AddressGenerator const &', 'arg0')]) + ## ipv4-address-generator.h: ns3::Ipv4AddressGenerator::Ipv4AddressGenerator() [constructor] + cls.add_constructor([]) + ## ipv4-address-generator.h: static void ns3::Ipv4AddressGenerator::Init(ns3::Ipv4Address const net, ns3::Ipv4Mask const mask, ns3::Ipv4Address const addr="0.0.0.1") [member function] + cls.add_method('Init', + 'void', + [param('ns3::Ipv4Address const', 'net'), param('ns3::Ipv4Mask const', 'mask'), param('ns3::Ipv4Address const', 'addr', default_value='"0.0.0.1"')], + is_static=True) + ## ipv4-address-generator.h: static ns3::Ipv4Address ns3::Ipv4AddressGenerator::NextNetwork(ns3::Ipv4Mask const mask) [member function] + cls.add_method('NextNetwork', + 'ns3::Ipv4Address', + [param('ns3::Ipv4Mask const', 'mask')], + is_static=True) + ## ipv4-address-generator.h: static ns3::Ipv4Address ns3::Ipv4AddressGenerator::GetNetwork(ns3::Ipv4Mask const mask) [member function] + cls.add_method('GetNetwork', + 'ns3::Ipv4Address', + [param('ns3::Ipv4Mask const', 'mask')], + is_static=True) + ## ipv4-address-generator.h: static void ns3::Ipv4AddressGenerator::InitAddress(ns3::Ipv4Address const addr, ns3::Ipv4Mask const mask) [member function] + cls.add_method('InitAddress', + 'void', + [param('ns3::Ipv4Address const', 'addr'), param('ns3::Ipv4Mask const', 'mask')], + is_static=True) + ## ipv4-address-generator.h: static ns3::Ipv4Address ns3::Ipv4AddressGenerator::NextAddress(ns3::Ipv4Mask const mask) [member function] + cls.add_method('NextAddress', + 'ns3::Ipv4Address', + [param('ns3::Ipv4Mask const', 'mask')], + is_static=True) + ## ipv4-address-generator.h: static ns3::Ipv4Address ns3::Ipv4AddressGenerator::GetAddress(ns3::Ipv4Mask const mask) [member function] + cls.add_method('GetAddress', + 'ns3::Ipv4Address', + [param('ns3::Ipv4Mask const', 'mask')], + is_static=True) + ## ipv4-address-generator.h: static void ns3::Ipv4AddressGenerator::Reset() [member function] + cls.add_method('Reset', + 'void', + [], + is_static=True) + ## ipv4-address-generator.h: static bool ns3::Ipv4AddressGenerator::AddAllocated(ns3::Ipv4Address const addr) [member function] + cls.add_method('AddAllocated', + 'bool', + [param('ns3::Ipv4Address const', 'addr')], + is_static=True) + ## ipv4-address-generator.h: static void ns3::Ipv4AddressGenerator::TestMode() [member function] + cls.add_method('TestMode', + 'void', + [], + is_static=True) + return + +def register_Ns3Ipv4Mask_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('==') + ## ipv4-address.h: ns3::Ipv4Mask::Ipv4Mask(ns3::Ipv4Mask const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4Mask const &', 'arg0')]) + ## ipv4-address.h: ns3::Ipv4Mask::Ipv4Mask() [constructor] + cls.add_constructor([]) + ## ipv4-address.h: ns3::Ipv4Mask::Ipv4Mask(uint32_t mask) [constructor] + cls.add_constructor([param('uint32_t', 'mask')]) + ## ipv4-address.h: ns3::Ipv4Mask::Ipv4Mask(char const * mask) [constructor] + cls.add_constructor([param('char const *', 'mask')]) + ## ipv4-address.h: uint32_t ns3::Ipv4Mask::Get() const [member function] + cls.add_method('Get', + 'uint32_t', + [], + is_const=True) + ## ipv4-address.h: uint32_t ns3::Ipv4Mask::GetInverse() const [member function] + cls.add_method('GetInverse', + 'uint32_t', + [], + is_const=True) + ## ipv4-address.h: static ns3::Ipv4Mask ns3::Ipv4Mask::GetLoopback() [member function] + cls.add_method('GetLoopback', + 'ns3::Ipv4Mask', + [], + is_static=True) + ## ipv4-address.h: static ns3::Ipv4Mask ns3::Ipv4Mask::GetZero() [member function] + cls.add_method('GetZero', + 'ns3::Ipv4Mask', + [], + is_static=True) + ## ipv4-address.h: bool ns3::Ipv4Mask::IsEqual(ns3::Ipv4Mask other) const [member function] + cls.add_method('IsEqual', + 'bool', + [param('ns3::Ipv4Mask', 'other')], + is_const=True) + ## ipv4-address.h: bool ns3::Ipv4Mask::IsMatch(ns3::Ipv4Address a, ns3::Ipv4Address b) const [member function] + cls.add_method('IsMatch', + 'bool', + [param('ns3::Ipv4Address', 'a'), param('ns3::Ipv4Address', 'b')], + is_const=True) + ## ipv4-address.h: void ns3::Ipv4Mask::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## ipv4-address.h: void ns3::Ipv4Mask::Set(uint32_t mask) [member function] + cls.add_method('Set', + 'void', + [param('uint32_t', 'mask')]) + return + +def register_Ns3Ipv4MulticastRoute_methods(root_module, cls): + cls.add_output_stream_operator() + ## ipv4-route.h: ns3::Ipv4MulticastRoute::Ipv4MulticastRoute() [constructor] + cls.add_constructor([]) + ## ipv4-route.h: ns3::Ipv4MulticastRoute::Ipv4MulticastRoute(ns3::Ipv4MulticastRoute const & route) [copy constructor] + cls.add_constructor([param('ns3::Ipv4MulticastRoute const &', 'route')]) + ## ipv4-route.h: ns3::Ipv4MulticastRoute::Ipv4MulticastRoute(ns3::Ipv4MulticastRoute const * route) [constructor] + cls.add_constructor([param('ns3::Ipv4MulticastRoute const *', 'route')]) + ## ipv4-route.h: static ns3::Ipv4MulticastRoute ns3::Ipv4MulticastRoute::CreateMulticastRoute(ns3::Ipv4Address origin, ns3::Ipv4Address group, uint32_t inputInterface, std::vector > outputInterfaces) [member function] + cls.add_method('CreateMulticastRoute', + 'ns3::Ipv4MulticastRoute', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group'), param('uint32_t', 'inputInterface'), param('std::vector< unsigned int >', 'outputInterfaces')], + is_static=True) + ## ipv4-route.h: ns3::Ipv4Address ns3::Ipv4MulticastRoute::GetGroup() const [member function] + cls.add_method('GetGroup', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-route.h: uint32_t ns3::Ipv4MulticastRoute::GetInputInterface() const [member function] + cls.add_method('GetInputInterface', + 'uint32_t', + [], + is_const=True) + ## ipv4-route.h: uint32_t ns3::Ipv4MulticastRoute::GetNOutputInterfaces() const [member function] + cls.add_method('GetNOutputInterfaces', + 'uint32_t', + [], + is_const=True) + ## ipv4-route.h: ns3::Ipv4Address ns3::Ipv4MulticastRoute::GetOrigin() const [member function] + cls.add_method('GetOrigin', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-route.h: uint32_t ns3::Ipv4MulticastRoute::GetOutputInterface(uint32_t n) const [member function] + cls.add_method('GetOutputInterface', + 'uint32_t', + [param('uint32_t', 'n')], + is_const=True) + ## ipv4-route.h: std::vector > ns3::Ipv4MulticastRoute::GetOutputInterfaces() const [member function] + cls.add_method('GetOutputInterfaces', + 'std::vector< unsigned int >', + [], + is_const=True) + return + +def register_Ns3Ipv4Route_methods(root_module, cls): + cls.add_output_stream_operator() + ## ipv4-route.h: ns3::Ipv4Route::Ipv4Route() [constructor] + cls.add_constructor([]) + ## ipv4-route.h: ns3::Ipv4Route::Ipv4Route(ns3::Ipv4Route const & route) [copy constructor] + cls.add_constructor([param('ns3::Ipv4Route const &', 'route')]) + ## ipv4-route.h: ns3::Ipv4Route::Ipv4Route(ns3::Ipv4Route const * route) [constructor] + cls.add_constructor([param('ns3::Ipv4Route const *', 'route')]) + ## ipv4-route.h: static ns3::Ipv4Route ns3::Ipv4Route::CreateDefaultRoute(ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('CreateDefaultRoute', + 'ns3::Ipv4Route', + [param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')], + is_static=True) + ## ipv4-route.h: static ns3::Ipv4Route ns3::Ipv4Route::CreateHostRouteTo(ns3::Ipv4Address dest, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('CreateHostRouteTo', + 'ns3::Ipv4Route', + [param('ns3::Ipv4Address', 'dest'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')], + is_static=True) + ## ipv4-route.h: static ns3::Ipv4Route ns3::Ipv4Route::CreateHostRouteTo(ns3::Ipv4Address dest, uint32_t interface) [member function] + cls.add_method('CreateHostRouteTo', + 'ns3::Ipv4Route', + [param('ns3::Ipv4Address', 'dest'), param('uint32_t', 'interface')], + is_static=True) + ## ipv4-route.h: static ns3::Ipv4Route ns3::Ipv4Route::CreateNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('CreateNetworkRouteTo', + 'ns3::Ipv4Route', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')], + is_static=True) + ## ipv4-route.h: static ns3::Ipv4Route ns3::Ipv4Route::CreateNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, uint32_t interface) [member function] + cls.add_method('CreateNetworkRouteTo', + 'ns3::Ipv4Route', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('uint32_t', 'interface')], + is_static=True) + ## ipv4-route.h: ns3::Ipv4Address ns3::Ipv4Route::GetDest() const [member function] + cls.add_method('GetDest', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-route.h: ns3::Ipv4Address ns3::Ipv4Route::GetDestNetwork() const [member function] + cls.add_method('GetDestNetwork', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-route.h: ns3::Ipv4Mask ns3::Ipv4Route::GetDestNetworkMask() const [member function] + cls.add_method('GetDestNetworkMask', + 'ns3::Ipv4Mask', + [], + is_const=True) + ## ipv4-route.h: ns3::Ipv4Address ns3::Ipv4Route::GetGateway() const [member function] + cls.add_method('GetGateway', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-route.h: uint32_t ns3::Ipv4Route::GetInterface() const [member function] + cls.add_method('GetInterface', + 'uint32_t', + [], + is_const=True) + ## ipv4-route.h: bool ns3::Ipv4Route::IsDefault() const [member function] + cls.add_method('IsDefault', + 'bool', + [], + is_const=True) + ## ipv4-route.h: bool ns3::Ipv4Route::IsGateway() const [member function] + cls.add_method('IsGateway', + 'bool', + [], + is_const=True) + ## ipv4-route.h: bool ns3::Ipv4Route::IsHost() const [member function] + cls.add_method('IsHost', + 'bool', + [], + is_const=True) + ## ipv4-route.h: bool ns3::Ipv4Route::IsNetwork() const [member function] + cls.add_method('IsNetwork', + 'bool', + [], + is_const=True) + return + +def register_Ns3Mac48Address_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_binary_comparison_operator('<') + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('==') + ## mac48-address.h: ns3::Mac48Address::Mac48Address(ns3::Mac48Address const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Mac48Address const &', 'arg0')]) + ## mac48-address.h: ns3::Mac48Address::Mac48Address() [constructor] + cls.add_constructor([]) + ## mac48-address.h: ns3::Mac48Address::Mac48Address(char const * str) [constructor] + cls.add_constructor([param('char const *', 'str')]) + ## mac48-address.h: static ns3::Mac48Address ns3::Mac48Address::Allocate() [member function] + cls.add_method('Allocate', + 'ns3::Mac48Address', + [], + is_static=True) + ## mac48-address.h: static ns3::Mac48Address ns3::Mac48Address::ConvertFrom(ns3::Address const & address) [member function] + cls.add_method('ConvertFrom', + 'ns3::Mac48Address', + [param('ns3::Address const &', 'address')], + is_static=True) + ## mac48-address.h: void ns3::Mac48Address::CopyFrom(uint8_t const * buffer) [member function] + cls.add_method('CopyFrom', + 'void', + [param('uint8_t const *', 'buffer')]) + ## mac48-address.h: void ns3::Mac48Address::CopyTo(uint8_t * buffer) const [member function] + cls.add_method('CopyTo', + 'void', + [param('uint8_t *', 'buffer')], + is_const=True) + ## mac48-address.h: static ns3::Mac48Address ns3::Mac48Address::GetBroadcast() [member function] + cls.add_method('GetBroadcast', + 'ns3::Mac48Address', + [], + is_static=True) + ## mac48-address.h: static ns3::Mac48Address ns3::Mac48Address::GetMulticast(ns3::Ipv4Address address) [member function] + cls.add_method('GetMulticast', + 'ns3::Mac48Address', + [param('ns3::Ipv4Address', 'address')], + is_static=True) + ## mac48-address.h: static ns3::Mac48Address ns3::Mac48Address::GetMulticastPrefix() [member function] + cls.add_method('GetMulticastPrefix', + 'ns3::Mac48Address', + [], + is_static=True) + ## mac48-address.h: bool ns3::Mac48Address::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True) + ## mac48-address.h: bool ns3::Mac48Address::IsGroup() const [member function] + cls.add_method('IsGroup', + 'bool', + [], + is_const=True) + ## mac48-address.h: static bool ns3::Mac48Address::IsMatchingType(ns3::Address const & address) [member function] + cls.add_method('IsMatchingType', + 'bool', + [param('ns3::Address const &', 'address')], + is_static=True) + ## mac48-address.h: bool ns3::Mac48Address::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_const=True) + return + +def register_Ns3Mac64Address_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('==') + ## mac64-address.h: ns3::Mac64Address::Mac64Address(ns3::Mac64Address const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Mac64Address const &', 'arg0')]) + ## mac64-address.h: ns3::Mac64Address::Mac64Address() [constructor] + cls.add_constructor([]) + ## mac64-address.h: ns3::Mac64Address::Mac64Address(char const * str) [constructor] + cls.add_constructor([param('char const *', 'str')]) + ## mac64-address.h: static ns3::Mac64Address ns3::Mac64Address::Allocate() [member function] + cls.add_method('Allocate', + 'ns3::Mac64Address', + [], + is_static=True) + ## mac64-address.h: static ns3::Mac64Address ns3::Mac64Address::ConvertFrom(ns3::Address const & address) [member function] + cls.add_method('ConvertFrom', + 'ns3::Mac64Address', + [param('ns3::Address const &', 'address')], + is_static=True) + ## mac64-address.h: void ns3::Mac64Address::CopyFrom(uint8_t const * buffer) [member function] + cls.add_method('CopyFrom', + 'void', + [param('uint8_t const *', 'buffer')]) + ## mac64-address.h: void ns3::Mac64Address::CopyTo(uint8_t * buffer) const [member function] + cls.add_method('CopyTo', + 'void', + [param('uint8_t *', 'buffer')], + is_const=True) + ## mac64-address.h: static bool ns3::Mac64Address::IsMatchingType(ns3::Address const & address) [member function] + cls.add_method('IsMatchingType', + 'bool', + [param('ns3::Address const &', 'address')], + is_static=True) + return + +def register_Ns3NodeList_methods(root_module, cls): + ## node-list.h: ns3::NodeList::NodeList(ns3::NodeList const & arg0) [copy constructor] + cls.add_constructor([param('ns3::NodeList const &', 'arg0')]) + ## node-list.h: ns3::NodeList::NodeList() [constructor] + cls.add_constructor([]) + ## node-list.h: static uint32_t ns3::NodeList::Add(ns3::Ptr node) [member function] + cls.add_method('Add', + 'uint32_t', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_static=True) + ## node-list.h: static __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NodeList::Begin() [member function] + cls.add_method('Begin', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Node > const, std::vector< ns3::Ptr< ns3::Node > > >', + [], + is_static=True) + ## node-list.h: static __gnu_cxx::__normal_iterator*,std::vector, std::allocator > > > ns3::NodeList::End() [member function] + cls.add_method('End', + '__gnu_cxx::__normal_iterator< ns3::Ptr< ns3::Node > const, std::vector< ns3::Ptr< ns3::Node > > >', + [], + is_static=True) + ## node-list.h: static ns3::Ptr ns3::NodeList::GetNode(uint32_t n) [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [param('uint32_t', 'n')], + is_static=True) + ## node-list.h: static uint32_t ns3::NodeList::GetNNodes() [member function] + cls.add_method('GetNNodes', + 'uint32_t', + [], + is_static=True) + return + +def register_Ns3PacketSocketAddress_methods(root_module, cls): + ## packet-socket-address.h: ns3::PacketSocketAddress::PacketSocketAddress(ns3::PacketSocketAddress const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketSocketAddress const &', 'arg0')]) + ## packet-socket-address.h: ns3::PacketSocketAddress::PacketSocketAddress() [constructor] + cls.add_constructor([]) + ## packet-socket-address.h: void ns3::PacketSocketAddress::SetProtocol(uint16_t protocol) [member function] + cls.add_method('SetProtocol', + 'void', + [param('uint16_t', 'protocol')]) + ## packet-socket-address.h: void ns3::PacketSocketAddress::SetAllDevices() [member function] + cls.add_method('SetAllDevices', + 'void', + []) + ## packet-socket-address.h: void ns3::PacketSocketAddress::SetSingleDevice(uint32_t device) [member function] + cls.add_method('SetSingleDevice', + 'void', + [param('uint32_t', 'device')]) + ## packet-socket-address.h: void ns3::PacketSocketAddress::SetPhysicalAddress(ns3::Address const address) [member function] + cls.add_method('SetPhysicalAddress', + 'void', + [param('ns3::Address const', 'address')]) + ## packet-socket-address.h: uint16_t ns3::PacketSocketAddress::GetProtocol() const [member function] + cls.add_method('GetProtocol', + 'uint16_t', + [], + is_const=True) + ## packet-socket-address.h: uint32_t ns3::PacketSocketAddress::GetSingleDevice() const [member function] + cls.add_method('GetSingleDevice', + 'uint32_t', + [], + is_const=True) + ## packet-socket-address.h: bool ns3::PacketSocketAddress::IsSingleDevice() const [member function] + cls.add_method('IsSingleDevice', + 'bool', + [], + is_const=True) + ## packet-socket-address.h: ns3::Address ns3::PacketSocketAddress::GetPhysicalAddress() const [member function] + cls.add_method('GetPhysicalAddress', + 'ns3::Address', + [], + is_const=True) + ## packet-socket-address.h: static ns3::PacketSocketAddress ns3::PacketSocketAddress::ConvertFrom(ns3::Address const & address) [member function] + cls.add_method('ConvertFrom', + 'ns3::PacketSocketAddress', + [param('ns3::Address const &', 'address')], + is_static=True) + ## packet-socket-address.h: static bool ns3::PacketSocketAddress::IsMatchingType(ns3::Address const & address) [member function] + cls.add_method('IsMatchingType', + 'bool', + [param('ns3::Address const &', 'address')], + is_static=True) + return + +def register_Ns3Ipv4AddressChecker_methods(root_module, cls): + ## ipv4-address.h: ns3::Ipv4AddressChecker::Ipv4AddressChecker(ns3::Ipv4AddressChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4AddressChecker const &', 'arg0')]) + ## ipv4-address.h: ns3::Ipv4AddressChecker::Ipv4AddressChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3Ipv4AddressValue_methods(root_module, cls): + ## ipv4-address.h: ns3::Ipv4AddressValue::Ipv4AddressValue(ns3::Ipv4AddressValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4AddressValue const &', 'arg0')]) + ## ipv4-address.h: ns3::Ipv4AddressValue::Ipv4AddressValue() [constructor] + cls.add_constructor([]) + ## ipv4-address.h: ns3::Ipv4AddressValue::Ipv4AddressValue(ns3::Ipv4Address const & value) [constructor] + cls.add_constructor([param('ns3::Ipv4Address const &', 'value')]) + ## ipv4-address.h: void ns3::Ipv4AddressValue::Set(ns3::Ipv4Address const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Ipv4Address const &', 'value')]) + ## ipv4-address.h: ns3::Ipv4Address ns3::Ipv4AddressValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-address.h: ns3::Ptr ns3::Ipv4AddressValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## ipv4-address.h: std::string ns3::Ipv4AddressValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## ipv4-address.h: bool ns3::Ipv4AddressValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3Ipv4Header_methods(root_module, cls): + ## ipv4-header.h: ns3::Ipv4Header::Ipv4Header(ns3::Ipv4Header const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4Header const &', 'arg0')]) + ## ipv4-header.h: ns3::Ipv4Header::Ipv4Header() [constructor] + cls.add_constructor([]) + ## ipv4-header.h: void ns3::Ipv4Header::EnableChecksum() [member function] + cls.add_method('EnableChecksum', + 'void', + []) + ## ipv4-header.h: void ns3::Ipv4Header::SetPayloadSize(uint16_t size) [member function] + cls.add_method('SetPayloadSize', + 'void', + [param('uint16_t', 'size')]) + ## ipv4-header.h: void ns3::Ipv4Header::SetIdentification(uint16_t identification) [member function] + cls.add_method('SetIdentification', + 'void', + [param('uint16_t', 'identification')]) + ## ipv4-header.h: void ns3::Ipv4Header::SetTos(uint8_t tos) [member function] + cls.add_method('SetTos', + 'void', + [param('uint8_t', 'tos')]) + ## ipv4-header.h: void ns3::Ipv4Header::SetMoreFragments() [member function] + cls.add_method('SetMoreFragments', + 'void', + []) + ## ipv4-header.h: void ns3::Ipv4Header::SetLastFragment() [member function] + cls.add_method('SetLastFragment', + 'void', + []) + ## ipv4-header.h: void ns3::Ipv4Header::SetDontFragment() [member function] + cls.add_method('SetDontFragment', + 'void', + []) + ## ipv4-header.h: void ns3::Ipv4Header::SetMayFragment() [member function] + cls.add_method('SetMayFragment', + 'void', + []) + ## ipv4-header.h: void ns3::Ipv4Header::SetFragmentOffset(uint16_t offset) [member function] + cls.add_method('SetFragmentOffset', + 'void', + [param('uint16_t', 'offset')]) + ## ipv4-header.h: void ns3::Ipv4Header::SetTtl(uint8_t ttl) [member function] + cls.add_method('SetTtl', + 'void', + [param('uint8_t', 'ttl')]) + ## ipv4-header.h: void ns3::Ipv4Header::SetProtocol(uint8_t num) [member function] + cls.add_method('SetProtocol', + 'void', + [param('uint8_t', 'num')]) + ## ipv4-header.h: void ns3::Ipv4Header::SetSource(ns3::Ipv4Address source) [member function] + cls.add_method('SetSource', + 'void', + [param('ns3::Ipv4Address', 'source')]) + ## ipv4-header.h: void ns3::Ipv4Header::SetDestination(ns3::Ipv4Address destination) [member function] + cls.add_method('SetDestination', + 'void', + [param('ns3::Ipv4Address', 'destination')]) + ## ipv4-header.h: uint16_t ns3::Ipv4Header::GetPayloadSize() const [member function] + cls.add_method('GetPayloadSize', + 'uint16_t', + [], + is_const=True) + ## ipv4-header.h: uint16_t ns3::Ipv4Header::GetIdentification() const [member function] + cls.add_method('GetIdentification', + 'uint16_t', + [], + is_const=True) + ## ipv4-header.h: uint8_t ns3::Ipv4Header::GetTos() const [member function] + cls.add_method('GetTos', + 'uint8_t', + [], + is_const=True) + ## ipv4-header.h: bool ns3::Ipv4Header::IsLastFragment() const [member function] + cls.add_method('IsLastFragment', + 'bool', + [], + is_const=True) + ## ipv4-header.h: bool ns3::Ipv4Header::IsDontFragment() const [member function] + cls.add_method('IsDontFragment', + 'bool', + [], + is_const=True) + ## ipv4-header.h: uint16_t ns3::Ipv4Header::GetFragmentOffset() const [member function] + cls.add_method('GetFragmentOffset', + 'uint16_t', + [], + is_const=True) + ## ipv4-header.h: uint8_t ns3::Ipv4Header::GetTtl() const [member function] + cls.add_method('GetTtl', + 'uint8_t', + [], + is_const=True) + ## ipv4-header.h: uint8_t ns3::Ipv4Header::GetProtocol() const [member function] + cls.add_method('GetProtocol', + 'uint8_t', + [], + is_const=True) + ## ipv4-header.h: ns3::Ipv4Address ns3::Ipv4Header::GetSource() const [member function] + cls.add_method('GetSource', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-header.h: ns3::Ipv4Address ns3::Ipv4Header::GetDestination() const [member function] + cls.add_method('GetDestination', + 'ns3::Ipv4Address', + [], + is_const=True) + ## ipv4-header.h: bool ns3::Ipv4Header::IsChecksumOk() const [member function] + cls.add_method('IsChecksumOk', + 'bool', + [], + is_const=True) + ## ipv4-header.h: static ns3::TypeId ns3::Ipv4Header::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## ipv4-header.h: ns3::TypeId ns3::Ipv4Header::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## ipv4-header.h: void ns3::Ipv4Header::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## ipv4-header.h: uint32_t ns3::Ipv4Header::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## ipv4-header.h: void ns3::Ipv4Header::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True, is_virtual=True) + ## ipv4-header.h: uint32_t ns3::Ipv4Header::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_virtual=True) + return + +def register_Ns3Ipv4MaskChecker_methods(root_module, cls): + ## ipv4-address.h: ns3::Ipv4MaskChecker::Ipv4MaskChecker(ns3::Ipv4MaskChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4MaskChecker const &', 'arg0')]) + ## ipv4-address.h: ns3::Ipv4MaskChecker::Ipv4MaskChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3Ipv4MaskValue_methods(root_module, cls): + ## ipv4-address.h: ns3::Ipv4MaskValue::Ipv4MaskValue(ns3::Ipv4MaskValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4MaskValue const &', 'arg0')]) + ## ipv4-address.h: ns3::Ipv4MaskValue::Ipv4MaskValue() [constructor] + cls.add_constructor([]) + ## ipv4-address.h: ns3::Ipv4MaskValue::Ipv4MaskValue(ns3::Ipv4Mask const & value) [constructor] + cls.add_constructor([param('ns3::Ipv4Mask const &', 'value')]) + ## ipv4-address.h: void ns3::Ipv4MaskValue::Set(ns3::Ipv4Mask const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Ipv4Mask const &', 'value')]) + ## ipv4-address.h: ns3::Ipv4Mask ns3::Ipv4MaskValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Ipv4Mask', + [], + is_const=True) + ## ipv4-address.h: ns3::Ptr ns3::Ipv4MaskValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## ipv4-address.h: std::string ns3::Ipv4MaskValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## ipv4-address.h: bool ns3::Ipv4MaskValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3LlcSnapHeader_methods(root_module, cls): + ## llc-snap-header.h: ns3::LlcSnapHeader::LlcSnapHeader(ns3::LlcSnapHeader const & arg0) [copy constructor] + cls.add_constructor([param('ns3::LlcSnapHeader const &', 'arg0')]) + ## llc-snap-header.h: ns3::LlcSnapHeader::LlcSnapHeader() [constructor] + cls.add_constructor([]) + ## llc-snap-header.h: void ns3::LlcSnapHeader::SetType(uint16_t type) [member function] + cls.add_method('SetType', + 'void', + [param('uint16_t', 'type')]) + ## llc-snap-header.h: uint16_t ns3::LlcSnapHeader::GetType() [member function] + cls.add_method('GetType', + 'uint16_t', + []) + ## llc-snap-header.h: static ns3::TypeId ns3::LlcSnapHeader::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## llc-snap-header.h: ns3::TypeId ns3::LlcSnapHeader::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## llc-snap-header.h: void ns3::LlcSnapHeader::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## llc-snap-header.h: uint32_t ns3::LlcSnapHeader::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## llc-snap-header.h: void ns3::LlcSnapHeader::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True, is_virtual=True) + ## llc-snap-header.h: uint32_t ns3::LlcSnapHeader::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_virtual=True) + return + +def register_Ns3Mac48AddressChecker_methods(root_module, cls): + ## mac48-address.h: ns3::Mac48AddressChecker::Mac48AddressChecker(ns3::Mac48AddressChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Mac48AddressChecker const &', 'arg0')]) + ## mac48-address.h: ns3::Mac48AddressChecker::Mac48AddressChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3Mac48AddressValue_methods(root_module, cls): + ## mac48-address.h: ns3::Mac48AddressValue::Mac48AddressValue(ns3::Mac48AddressValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Mac48AddressValue const &', 'arg0')]) + ## mac48-address.h: ns3::Mac48AddressValue::Mac48AddressValue() [constructor] + cls.add_constructor([]) + ## mac48-address.h: ns3::Mac48AddressValue::Mac48AddressValue(ns3::Mac48Address const & value) [constructor] + cls.add_constructor([param('ns3::Mac48Address const &', 'value')]) + ## mac48-address.h: void ns3::Mac48AddressValue::Set(ns3::Mac48Address const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Mac48Address const &', 'value')]) + ## mac48-address.h: ns3::Mac48Address ns3::Mac48AddressValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Mac48Address', + [], + is_const=True) + ## mac48-address.h: ns3::Ptr ns3::Mac48AddressValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## mac48-address.h: std::string ns3::Mac48AddressValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## mac48-address.h: bool ns3::Mac48AddressValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3Queue_methods(root_module, cls): + ## queue.h: ns3::Queue::Queue(ns3::Queue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Queue const &', 'arg0')]) + ## queue.h: static ns3::TypeId ns3::Queue::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## queue.h: ns3::Queue::Queue() [constructor] + cls.add_constructor([]) + ## queue.h: bool ns3::Queue::IsEmpty() const [member function] + cls.add_method('IsEmpty', + 'bool', + [], + is_const=True) + ## queue.h: bool ns3::Queue::Enqueue(ns3::Ptr p) [member function] + cls.add_method('Enqueue', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')]) + ## queue.h: ns3::Ptr ns3::Queue::Dequeue() [member function] + cls.add_method('Dequeue', + 'ns3::Ptr< ns3::Packet >', + []) + ## queue.h: ns3::Ptr ns3::Queue::Peek() const [member function] + cls.add_method('Peek', + 'ns3::Ptr< ns3::Packet const >', + [], + is_const=True) + ## queue.h: void ns3::Queue::DequeueAll() [member function] + cls.add_method('DequeueAll', + 'void', + []) + ## queue.h: uint32_t ns3::Queue::GetNPackets() const [member function] + cls.add_method('GetNPackets', + 'uint32_t', + [], + is_const=True) + ## queue.h: uint32_t ns3::Queue::GetNBytes() const [member function] + cls.add_method('GetNBytes', + 'uint32_t', + [], + is_const=True) + ## queue.h: uint32_t ns3::Queue::GetTotalReceivedBytes() const [member function] + cls.add_method('GetTotalReceivedBytes', + 'uint32_t', + [], + is_const=True) + ## queue.h: uint32_t ns3::Queue::GetTotalReceivedPackets() const [member function] + cls.add_method('GetTotalReceivedPackets', + 'uint32_t', + [], + is_const=True) + ## queue.h: uint32_t ns3::Queue::GetTotalDroppedBytes() const [member function] + cls.add_method('GetTotalDroppedBytes', + 'uint32_t', + [], + is_const=True) + ## queue.h: uint32_t ns3::Queue::GetTotalDroppedPackets() const [member function] + cls.add_method('GetTotalDroppedPackets', + 'uint32_t', + [], + is_const=True) + ## queue.h: void ns3::Queue::ResetStatistics() [member function] + cls.add_method('ResetStatistics', + 'void', + []) + ## queue.h: void ns3::Queue::Drop(ns3::Ptr packet) [member function] + cls.add_method('Drop', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'packet')], + visibility='protected') + ## queue.h: bool ns3::Queue::DoEnqueue(ns3::Ptr p) [member function] + cls.add_method('DoEnqueue', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## queue.h: ns3::Ptr ns3::Queue::DoDequeue() [member function] + cls.add_method('DoDequeue', + 'ns3::Ptr< ns3::Packet >', + [], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## queue.h: ns3::Ptr ns3::Queue::DoPeek() const [member function] + cls.add_method('DoPeek', + 'ns3::Ptr< ns3::Packet const >', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3Socket_methods(root_module, cls): + ## socket.h: ns3::Socket::Socket(ns3::Socket const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Socket const &', 'arg0')]) + ## socket.h: ns3::Socket::Socket() [constructor] + cls.add_constructor([]) + ## socket.h: static ns3::Ptr ns3::Socket::CreateSocket(ns3::Ptr node, ns3::TypeId tid) [member function] + cls.add_method('CreateSocket', + 'ns3::Ptr< ns3::Socket >', + [param('ns3::Ptr< ns3::Node >', 'node'), param('ns3::TypeId', 'tid')], + is_static=True) + ## socket.h: ns3::Socket::SocketErrno ns3::Socket::GetErrno() const [member function] + cls.add_method('GetErrno', + 'ns3::Socket::SocketErrno', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## socket.h: ns3::Ptr ns3::Socket::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## socket.h: void ns3::Socket::SetConnectCallback(ns3::Callback, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty> connectionSucceeded, ns3::Callback, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty> connectionFailed) [member function] + cls.add_method('SetConnectCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Socket >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'connectionSucceeded'), param('ns3::Callback< void, ns3::Ptr< ns3::Socket >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'connectionFailed')]) + ## socket.h: void ns3::Socket::SetAcceptCallback(ns3::Callback, ns3::Address const&, ns3::empty, ns3::empty, ns3::empty, ns3::empty> connectionRequest, ns3::Callback, ns3::Address const&, ns3::empty, ns3::empty, ns3::empty, ns3::empty> newConnectionCreated) [member function] + cls.add_method('SetAcceptCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::Socket >, ns3::Address const &, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'connectionRequest'), param('ns3::Callback< void, ns3::Ptr< ns3::Socket >, ns3::Address const &, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'newConnectionCreated')]) + ## socket.h: void ns3::Socket::SetDataSentCallback(ns3::Callback, unsigned int, ns3::empty, ns3::empty, ns3::empty, ns3::empty> dataSent) [member function] + cls.add_method('SetDataSentCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Socket >, unsigned int, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'dataSent')]) + ## socket.h: void ns3::Socket::SetSendCallback(ns3::Callback, unsigned int, ns3::empty, ns3::empty, ns3::empty, ns3::empty> sendCb) [member function] + cls.add_method('SetSendCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Socket >, unsigned int, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'sendCb')]) + ## socket.h: void ns3::Socket::SetRecvCallback(ns3::Callback, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty> arg0) [member function] + cls.add_method('SetRecvCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Socket >, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'arg0')]) + ## socket.h: int ns3::Socket::Bind(ns3::Address const & address) [member function] + cls.add_method('Bind', + 'int', + [param('ns3::Address const &', 'address')], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::Bind() [member function] + cls.add_method('Bind', + 'int', + [], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::Close() [member function] + cls.add_method('Close', + 'int', + [], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::ShutdownSend() [member function] + cls.add_method('ShutdownSend', + 'int', + [], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::ShutdownRecv() [member function] + cls.add_method('ShutdownRecv', + 'int', + [], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::Connect(ns3::Address const & address) [member function] + cls.add_method('Connect', + 'int', + [param('ns3::Address const &', 'address')], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::Listen() [member function] + cls.add_method('Listen', + 'int', + [], + is_pure_virtual=True, is_virtual=True) + ## socket.h: uint32_t ns3::Socket::GetTxAvailable() const [member function] + cls.add_method('GetTxAvailable', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## socket.h: int ns3::Socket::Send(ns3::Ptr p, uint32_t flags) [member function] + cls.add_method('Send', + 'int', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('uint32_t', 'flags')], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::SendTo(ns3::Ptr p, uint32_t flags, ns3::Address const & toAddress) [member function] + cls.add_method('SendTo', + 'int', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('uint32_t', 'flags'), param('ns3::Address const &', 'toAddress')], + is_pure_virtual=True, is_virtual=True) + ## socket.h: uint32_t ns3::Socket::GetRxAvailable() const [member function] + cls.add_method('GetRxAvailable', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## socket.h: ns3::Ptr ns3::Socket::Recv(uint32_t maxSize, uint32_t flags) [member function] + cls.add_method('Recv', + 'ns3::Ptr< ns3::Packet >', + [param('uint32_t', 'maxSize'), param('uint32_t', 'flags')], + is_pure_virtual=True, is_virtual=True) + ## socket.h: ns3::Ptr ns3::Socket::RecvFrom(uint32_t maxSize, uint32_t flags, ns3::Address & fromAddress) [member function] + cls.add_method('RecvFrom', + 'ns3::Ptr< ns3::Packet >', + [param('uint32_t', 'maxSize'), param('uint32_t', 'flags'), param('ns3::Address &', 'fromAddress')], + is_pure_virtual=True, is_virtual=True) + ## socket.h: int ns3::Socket::Send(ns3::Ptr p) [member function] + cls.add_method('Send', + 'int', + [param('ns3::Ptr< ns3::Packet >', 'p')]) + ## socket.h: int ns3::Socket::Send(uint8_t const * buf, uint32_t size, uint32_t flags) [member function] + cls.add_method('Send', + 'int', + [param('uint8_t const *', 'buf'), param('uint32_t', 'size'), param('uint32_t', 'flags')]) + ## socket.h: int ns3::Socket::SendTo(uint8_t const * buf, uint32_t size, uint32_t flags, ns3::Address const & address) [member function] + cls.add_method('SendTo', + 'int', + [param('uint8_t const *', 'buf'), param('uint32_t', 'size'), param('uint32_t', 'flags'), param('ns3::Address const &', 'address')]) + ## socket.h: ns3::Ptr ns3::Socket::Recv() [member function] + cls.add_method('Recv', + 'ns3::Ptr< ns3::Packet >', + []) + ## socket.h: int ns3::Socket::Recv(uint8_t * buf, uint32_t size, uint32_t flags) [member function] + cls.add_method('Recv', + 'int', + [param('uint8_t *', 'buf'), param('uint32_t', 'size'), param('uint32_t', 'flags')]) + ## socket.h: ns3::Ptr ns3::Socket::RecvFrom(ns3::Address & fromAddress) [member function] + cls.add_method('RecvFrom', + 'ns3::Ptr< ns3::Packet >', + [param('ns3::Address &', 'fromAddress')]) + ## socket.h: int ns3::Socket::RecvFrom(uint8_t * buf, uint32_t size, uint32_t flags, ns3::Address & fromAddress) [member function] + cls.add_method('RecvFrom', + 'int', + [param('uint8_t *', 'buf'), param('uint32_t', 'size'), param('uint32_t', 'flags'), param('ns3::Address &', 'fromAddress')]) + ## socket.h: int ns3::Socket::GetSockName(ns3::Address & address) const [member function] + cls.add_method('GetSockName', + 'int', + [param('ns3::Address &', 'address')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## socket.h: void ns3::Socket::NotifyConnectionSucceeded() [member function] + cls.add_method('NotifyConnectionSucceeded', + 'void', + [], + visibility='protected') + ## socket.h: void ns3::Socket::NotifyConnectionFailed() [member function] + cls.add_method('NotifyConnectionFailed', + 'void', + [], + visibility='protected') + ## socket.h: bool ns3::Socket::NotifyConnectionRequest(ns3::Address const & from) [member function] + cls.add_method('NotifyConnectionRequest', + 'bool', + [param('ns3::Address const &', 'from')], + visibility='protected') + ## socket.h: void ns3::Socket::NotifyNewConnectionCreated(ns3::Ptr socket, ns3::Address const & from) [member function] + cls.add_method('NotifyNewConnectionCreated', + 'void', + [param('ns3::Ptr< ns3::Socket >', 'socket'), param('ns3::Address const &', 'from')], + visibility='protected') + ## socket.h: void ns3::Socket::NotifyDataSent(uint32_t size) [member function] + cls.add_method('NotifyDataSent', + 'void', + [param('uint32_t', 'size')], + visibility='protected') + ## socket.h: void ns3::Socket::NotifySend(uint32_t spaceAvailable) [member function] + cls.add_method('NotifySend', + 'void', + [param('uint32_t', 'spaceAvailable')], + visibility='protected') + ## socket.h: void ns3::Socket::NotifyDataRecv() [member function] + cls.add_method('NotifyDataRecv', + 'void', + [], + visibility='protected') + return + +def register_Ns3SocketAddressTag_methods(root_module, cls): + ## socket.h: ns3::SocketAddressTag::SocketAddressTag(ns3::SocketAddressTag const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SocketAddressTag const &', 'arg0')]) + ## socket.h: ns3::SocketAddressTag::SocketAddressTag() [constructor] + cls.add_constructor([]) + ## socket.h: void ns3::SocketAddressTag::SetAddress(ns3::Address addr) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Address', 'addr')]) + ## socket.h: ns3::Address ns3::SocketAddressTag::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Address', + [], + is_const=True) + ## socket.h: static ns3::TypeId ns3::SocketAddressTag::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## socket.h: ns3::TypeId ns3::SocketAddressTag::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## socket.h: uint32_t ns3::SocketAddressTag::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## socket.h: void ns3::SocketAddressTag::Serialize(ns3::TagBuffer i) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::TagBuffer', 'i')], + is_const=True, is_virtual=True) + ## socket.h: void ns3::SocketAddressTag::Deserialize(ns3::TagBuffer i) [member function] + cls.add_method('Deserialize', + 'void', + [param('ns3::TagBuffer', 'i')], + is_virtual=True) + ## socket.h: void ns3::SocketAddressTag::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + return + +def register_Ns3SocketFactory_methods(root_module, cls): + ## socket-factory.h: ns3::SocketFactory::SocketFactory(ns3::SocketFactory const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SocketFactory const &', 'arg0')]) + ## socket-factory.h: static ns3::TypeId ns3::SocketFactory::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## socket-factory.h: ns3::SocketFactory::SocketFactory() [constructor] + cls.add_constructor([]) + ## socket-factory.h: ns3::Ptr ns3::SocketFactory::CreateSocket() [member function] + cls.add_method('CreateSocket', + 'ns3::Ptr< ns3::Socket >', + [], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3SocketIpTtlTag_methods(root_module, cls): + ## socket.h: ns3::SocketIpTtlTag::SocketIpTtlTag(ns3::SocketIpTtlTag const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SocketIpTtlTag const &', 'arg0')]) + ## socket.h: ns3::SocketIpTtlTag::SocketIpTtlTag() [constructor] + cls.add_constructor([]) + ## socket.h: void ns3::SocketIpTtlTag::SetTtl(uint8_t ttl) [member function] + cls.add_method('SetTtl', + 'void', + [param('uint8_t', 'ttl')]) + ## socket.h: uint8_t ns3::SocketIpTtlTag::GetTtl() const [member function] + cls.add_method('GetTtl', + 'uint8_t', + [], + is_const=True) + ## socket.h: static ns3::TypeId ns3::SocketIpTtlTag::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## socket.h: ns3::TypeId ns3::SocketIpTtlTag::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## socket.h: uint32_t ns3::SocketIpTtlTag::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## socket.h: void ns3::SocketIpTtlTag::Serialize(ns3::TagBuffer i) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::TagBuffer', 'i')], + is_const=True, is_virtual=True) + ## socket.h: void ns3::SocketIpTtlTag::Deserialize(ns3::TagBuffer i) [member function] + cls.add_method('Deserialize', + 'void', + [param('ns3::TagBuffer', 'i')], + is_virtual=True) + ## socket.h: void ns3::SocketIpTtlTag::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + return + +def register_Ns3TcpSocket_methods(root_module, cls): + ## tcp-socket.h: ns3::TcpSocket::TcpSocket(ns3::TcpSocket const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TcpSocket const &', 'arg0')]) + ## tcp-socket.h: static ns3::TypeId ns3::TcpSocket::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## tcp-socket.h: ns3::TcpSocket::TcpSocket() [constructor] + cls.add_constructor([]) + ## tcp-socket.h: void ns3::TcpSocket::SetSndBufSize(uint32_t size) [member function] + cls.add_method('SetSndBufSize', + 'void', + [param('uint32_t', 'size')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: uint32_t ns3::TcpSocket::GetSndBufSize() const [member function] + cls.add_method('GetSndBufSize', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetRcvBufSize(uint32_t size) [member function] + cls.add_method('SetRcvBufSize', + 'void', + [param('uint32_t', 'size')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: uint32_t ns3::TcpSocket::GetRcvBufSize() const [member function] + cls.add_method('GetRcvBufSize', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetSegSize(uint32_t size) [member function] + cls.add_method('SetSegSize', + 'void', + [param('uint32_t', 'size')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: uint32_t ns3::TcpSocket::GetSegSize() const [member function] + cls.add_method('GetSegSize', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetSSThresh(uint32_t threshold) [member function] + cls.add_method('SetSSThresh', + 'void', + [param('uint32_t', 'threshold')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: uint32_t ns3::TcpSocket::GetSSThresh() const [member function] + cls.add_method('GetSSThresh', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetInitialCwnd(uint32_t count) [member function] + cls.add_method('SetInitialCwnd', + 'void', + [param('uint32_t', 'count')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: uint32_t ns3::TcpSocket::GetInitialCwnd() const [member function] + cls.add_method('GetInitialCwnd', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetConnTimeout(ns3::Time timeout) [member function] + cls.add_method('SetConnTimeout', + 'void', + [param('ns3::Time', 'timeout')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: ns3::Time ns3::TcpSocket::GetConnTimeout() const [member function] + cls.add_method('GetConnTimeout', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetConnCount(uint32_t count) [member function] + cls.add_method('SetConnCount', + 'void', + [param('uint32_t', 'count')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: uint32_t ns3::TcpSocket::GetConnCount() const [member function] + cls.add_method('GetConnCount', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetDelAckTimeout(ns3::Time timeout) [member function] + cls.add_method('SetDelAckTimeout', + 'void', + [param('ns3::Time', 'timeout')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: ns3::Time ns3::TcpSocket::GetDelAckTimeout() const [member function] + cls.add_method('GetDelAckTimeout', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## tcp-socket.h: void ns3::TcpSocket::SetDelAckMaxCount(uint32_t count) [member function] + cls.add_method('SetDelAckMaxCount', + 'void', + [param('uint32_t', 'count')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## tcp-socket.h: uint32_t ns3::TcpSocket::GetDelAckMaxCount() const [member function] + cls.add_method('GetDelAckMaxCount', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3TcpSocketFactory_methods(root_module, cls): + ## tcp-socket-factory.h: ns3::TcpSocketFactory::TcpSocketFactory(ns3::TcpSocketFactory const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TcpSocketFactory const &', 'arg0')]) + ## tcp-socket-factory.h: ns3::TcpSocketFactory::TcpSocketFactory() [constructor] + cls.add_constructor([]) + ## tcp-socket-factory.h: static ns3::TypeId ns3::TcpSocketFactory::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + return + +def register_Ns3UdpSocket_methods(root_module, cls): + ## udp-socket.h: ns3::UdpSocket::UdpSocket(ns3::UdpSocket const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UdpSocket const &', 'arg0')]) + ## udp-socket.h: static ns3::TypeId ns3::UdpSocket::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## udp-socket.h: ns3::UdpSocket::UdpSocket() [constructor] + cls.add_constructor([]) + ## udp-socket.h: void ns3::UdpSocket::SetRcvBufSize(uint32_t size) [member function] + cls.add_method('SetRcvBufSize', + 'void', + [param('uint32_t', 'size')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## udp-socket.h: uint32_t ns3::UdpSocket::GetRcvBufSize() const [member function] + cls.add_method('GetRcvBufSize', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## udp-socket.h: void ns3::UdpSocket::SetIpTtl(uint32_t ipTtl) [member function] + cls.add_method('SetIpTtl', + 'void', + [param('uint32_t', 'ipTtl')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## udp-socket.h: uint32_t ns3::UdpSocket::GetIpTtl() const [member function] + cls.add_method('GetIpTtl', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## udp-socket.h: void ns3::UdpSocket::SetIpMulticastTtl(uint32_t ipTtl) [member function] + cls.add_method('SetIpMulticastTtl', + 'void', + [param('uint32_t', 'ipTtl')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## udp-socket.h: uint32_t ns3::UdpSocket::GetIpMulticastTtl() const [member function] + cls.add_method('GetIpMulticastTtl', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3UdpSocketFactory_methods(root_module, cls): + ## udp-socket-factory.h: ns3::UdpSocketFactory::UdpSocketFactory(ns3::UdpSocketFactory const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UdpSocketFactory const &', 'arg0')]) + ## udp-socket-factory.h: ns3::UdpSocketFactory::UdpSocketFactory() [constructor] + cls.add_constructor([]) + ## udp-socket-factory.h: static ns3::TypeId ns3::UdpSocketFactory::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + return + +def register_Ns3AddressChecker_methods(root_module, cls): + ## address.h: ns3::AddressChecker::AddressChecker(ns3::AddressChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AddressChecker const &', 'arg0')]) + ## address.h: ns3::AddressChecker::AddressChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3AddressValue_methods(root_module, cls): + ## address.h: ns3::AddressValue::AddressValue(ns3::AddressValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AddressValue const &', 'arg0')]) + ## address.h: ns3::AddressValue::AddressValue() [constructor] + cls.add_constructor([]) + ## address.h: ns3::AddressValue::AddressValue(ns3::Address const & value) [constructor] + cls.add_constructor([param('ns3::Address const &', 'value')]) + ## address.h: void ns3::AddressValue::Set(ns3::Address const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Address const &', 'value')]) + ## address.h: ns3::Address ns3::AddressValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Address', + [], + is_const=True) + ## address.h: ns3::Ptr ns3::AddressValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## address.h: std::string ns3::AddressValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## address.h: bool ns3::AddressValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3Application_methods(root_module, cls): + ## application.h: ns3::Application::Application(ns3::Application const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Application const &', 'arg0')]) + ## application.h: static ns3::TypeId ns3::Application::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## application.h: ns3::Application::Application() [constructor] + cls.add_constructor([]) + ## application.h: void ns3::Application::Start(ns3::Time const & startTime) [member function] + cls.add_method('Start', + 'void', + [param('ns3::Time const &', 'startTime')]) + ## application.h: void ns3::Application::Start(ns3::RandomVariable const & startVariable) [member function] + cls.add_method('Start', + 'void', + [param('ns3::RandomVariable const &', 'startVariable')]) + ## application.h: void ns3::Application::Stop(ns3::Time const & stopTime) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'stopTime')]) + ## application.h: void ns3::Application::Stop(ns3::RandomVariable const & stopVariable) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::RandomVariable const &', 'stopVariable')]) + ## application.h: ns3::Ptr ns3::Application::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_const=True) + ## application.h: void ns3::Application::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')]) + ## application.h: void ns3::Application::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## application.h: void ns3::Application::StartApplication() [member function] + cls.add_method('StartApplication', + 'void', + [], + visibility='private', is_virtual=True) + ## application.h: void ns3::Application::StopApplication() [member function] + cls.add_method('StopApplication', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3Channel_methods(root_module, cls): + ## channel.h: ns3::Channel::Channel(ns3::Channel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Channel const &', 'arg0')]) + ## channel.h: static ns3::TypeId ns3::Channel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## channel.h: ns3::Channel::Channel() [constructor] + cls.add_constructor([]) + ## channel.h: ns3::Channel::Channel(std::string name) [constructor] + cls.add_constructor([param('std::string', 'name')]) + ## channel.h: void ns3::Channel::SetName(std::string arg0) [member function] + cls.add_method('SetName', + 'void', + [param('std::string', 'arg0')]) + ## channel.h: std::string ns3::Channel::GetName() [member function] + cls.add_method('GetName', + 'std::string', + []) + ## channel.h: uint32_t ns3::Channel::GetNDevices() const [member function] + cls.add_method('GetNDevices', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## channel.h: ns3::Ptr ns3::Channel::GetDevice(uint32_t i) const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3DropTailQueue_methods(root_module, cls): + ## drop-tail-queue.h: ns3::DropTailQueue::DropTailQueue(ns3::DropTailQueue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DropTailQueue const &', 'arg0')]) + ## drop-tail-queue.h: static ns3::TypeId ns3::DropTailQueue::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## drop-tail-queue.h: ns3::DropTailQueue::DropTailQueue() [constructor] + cls.add_constructor([]) + ## drop-tail-queue.h: bool ns3::DropTailQueue::DoEnqueue(ns3::Ptr p) [member function] + cls.add_method('DoEnqueue', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + visibility='private', is_virtual=True) + ## drop-tail-queue.h: ns3::Ptr ns3::DropTailQueue::DoDequeue() [member function] + cls.add_method('DoDequeue', + 'ns3::Ptr< ns3::Packet >', + [], + visibility='private', is_virtual=True) + ## drop-tail-queue.h: ns3::Ptr ns3::DropTailQueue::DoPeek() const [member function] + cls.add_method('DoPeek', + 'ns3::Ptr< ns3::Packet const >', + [], + is_const=True, visibility='private', is_virtual=True) + return + +def register_Ns3EthernetHeader_methods(root_module, cls): + ## ethernet-header.h: ns3::EthernetHeader::EthernetHeader(ns3::EthernetHeader const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EthernetHeader const &', 'arg0')]) + ## ethernet-header.h: ns3::EthernetHeader::EthernetHeader(bool hasPreamble) [constructor] + cls.add_constructor([param('bool', 'hasPreamble')]) + ## ethernet-header.h: ns3::EthernetHeader::EthernetHeader() [constructor] + cls.add_constructor([]) + ## ethernet-header.h: void ns3::EthernetHeader::SetLengthType(uint16_t size) [member function] + cls.add_method('SetLengthType', + 'void', + [param('uint16_t', 'size')]) + ## ethernet-header.h: void ns3::EthernetHeader::SetSource(ns3::Mac48Address source) [member function] + cls.add_method('SetSource', + 'void', + [param('ns3::Mac48Address', 'source')]) + ## ethernet-header.h: void ns3::EthernetHeader::SetDestination(ns3::Mac48Address destination) [member function] + cls.add_method('SetDestination', + 'void', + [param('ns3::Mac48Address', 'destination')]) + ## ethernet-header.h: void ns3::EthernetHeader::SetPreambleSfd(uint64_t preambleSfd) [member function] + cls.add_method('SetPreambleSfd', + 'void', + [param('uint64_t', 'preambleSfd')]) + ## ethernet-header.h: uint16_t ns3::EthernetHeader::GetLengthType() const [member function] + cls.add_method('GetLengthType', + 'uint16_t', + [], + is_const=True) + ## ethernet-header.h: ns3::ethernet_header_t ns3::EthernetHeader::GetPacketType() const [member function] + cls.add_method('GetPacketType', + 'ns3::ethernet_header_t', + [], + is_const=True) + ## ethernet-header.h: ns3::Mac48Address ns3::EthernetHeader::GetSource() const [member function] + cls.add_method('GetSource', + 'ns3::Mac48Address', + [], + is_const=True) + ## ethernet-header.h: ns3::Mac48Address ns3::EthernetHeader::GetDestination() const [member function] + cls.add_method('GetDestination', + 'ns3::Mac48Address', + [], + is_const=True) + ## ethernet-header.h: uint64_t ns3::EthernetHeader::GetPreambleSfd() const [member function] + cls.add_method('GetPreambleSfd', + 'uint64_t', + [], + is_const=True) + ## ethernet-header.h: uint32_t ns3::EthernetHeader::GetHeaderSize() const [member function] + cls.add_method('GetHeaderSize', + 'uint32_t', + [], + is_const=True) + ## ethernet-header.h: static ns3::TypeId ns3::EthernetHeader::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## ethernet-header.h: ns3::TypeId ns3::EthernetHeader::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## ethernet-header.h: void ns3::EthernetHeader::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## ethernet-header.h: uint32_t ns3::EthernetHeader::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## ethernet-header.h: void ns3::EthernetHeader::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True, is_virtual=True) + ## ethernet-header.h: uint32_t ns3::EthernetHeader::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_virtual=True) + return + +def register_Ns3EthernetTrailer_methods(root_module, cls): + ## ethernet-trailer.h: ns3::EthernetTrailer::EthernetTrailer(ns3::EthernetTrailer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EthernetTrailer const &', 'arg0')]) + ## ethernet-trailer.h: ns3::EthernetTrailer::EthernetTrailer() [constructor] + cls.add_constructor([]) + ## ethernet-trailer.h: static void ns3::EthernetTrailer::EnableFcs(bool enable) [member function] + cls.add_method('EnableFcs', + 'void', + [param('bool', 'enable')], + is_static=True) + ## ethernet-trailer.h: void ns3::EthernetTrailer::CalcFcs(ns3::Ptr p) [member function] + cls.add_method('CalcFcs', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'p')]) + ## ethernet-trailer.h: void ns3::EthernetTrailer::SetFcs(uint32_t fcs) [member function] + cls.add_method('SetFcs', + 'void', + [param('uint32_t', 'fcs')]) + ## ethernet-trailer.h: uint32_t ns3::EthernetTrailer::GetFcs() [member function] + cls.add_method('GetFcs', + 'uint32_t', + []) + ## ethernet-trailer.h: bool ns3::EthernetTrailer::CheckFcs(ns3::Ptr p) const [member function] + cls.add_method('CheckFcs', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p')], + is_const=True) + ## ethernet-trailer.h: uint32_t ns3::EthernetTrailer::GetTrailerSize() const [member function] + cls.add_method('GetTrailerSize', + 'uint32_t', + [], + is_const=True) + ## ethernet-trailer.h: static ns3::TypeId ns3::EthernetTrailer::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## ethernet-trailer.h: ns3::TypeId ns3::EthernetTrailer::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## ethernet-trailer.h: void ns3::EthernetTrailer::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## ethernet-trailer.h: uint32_t ns3::EthernetTrailer::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## ethernet-trailer.h: void ns3::EthernetTrailer::Serialize(ns3::Buffer::Iterator end) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'end')], + is_const=True, is_virtual=True) + ## ethernet-trailer.h: uint32_t ns3::EthernetTrailer::Deserialize(ns3::Buffer::Iterator end) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'end')], + is_virtual=True) + return + +def register_Ns3Ipv4_methods(root_module, cls): + ## ipv4.h: ns3::Ipv4::Ipv4(ns3::Ipv4 const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4 const &', 'arg0')]) + ## ipv4.h: static ns3::TypeId ns3::Ipv4::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## ipv4.h: ns3::Ipv4::Ipv4() [constructor] + cls.add_constructor([]) + ## ipv4.h: void ns3::Ipv4::AddRoutingProtocol(ns3::Ptr routingProtocol, int16_t priority) [member function] + cls.add_method('AddRoutingProtocol', + 'void', + [param('ns3::Ptr< ns3::Ipv4RoutingProtocol >', 'routingProtocol'), param('int16_t', 'priority')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::AddHostRouteTo(ns3::Ipv4Address dest, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('AddHostRouteTo', + 'void', + [param('ns3::Ipv4Address', 'dest'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::AddHostRouteTo(ns3::Ipv4Address dest, uint32_t interface) [member function] + cls.add_method('AddHostRouteTo', + 'void', + [param('ns3::Ipv4Address', 'dest'), param('uint32_t', 'interface')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::AddNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('AddNetworkRouteTo', + 'void', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::AddNetworkRouteTo(ns3::Ipv4Address network, ns3::Ipv4Mask networkMask, uint32_t interface) [member function] + cls.add_method('AddNetworkRouteTo', + 'void', + [param('ns3::Ipv4Address', 'network'), param('ns3::Ipv4Mask', 'networkMask'), param('uint32_t', 'interface')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::SetDefaultRoute(ns3::Ipv4Address nextHop, uint32_t interface) [member function] + cls.add_method('SetDefaultRoute', + 'void', + [param('ns3::Ipv4Address', 'nextHop'), param('uint32_t', 'interface')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: uint32_t ns3::Ipv4::GetNRoutes() [member function] + cls.add_method('GetNRoutes', + 'uint32_t', + [], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: ns3::Ipv4Route ns3::Ipv4::GetRoute(uint32_t i) [member function] + cls.add_method('GetRoute', + 'ns3::Ipv4Route', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::RemoveRoute(uint32_t i) [member function] + cls.add_method('RemoveRoute', + 'void', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::AddMulticastRoute(ns3::Ipv4Address origin, ns3::Ipv4Address group, uint32_t inputInterface, std::vector > outputInterfaces) [member function] + cls.add_method('AddMulticastRoute', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group'), param('uint32_t', 'inputInterface'), param('std::vector< unsigned int >', 'outputInterfaces')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::RemoveMulticastRoute(ns3::Ipv4Address origin, ns3::Ipv4Address group, uint32_t inputInterface) [member function] + cls.add_method('RemoveMulticastRoute', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group'), param('uint32_t', 'inputInterface')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::SetDefaultMulticastRoute(uint32_t outputInterface) [member function] + cls.add_method('SetDefaultMulticastRoute', + 'void', + [param('uint32_t', 'outputInterface')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: uint32_t ns3::Ipv4::GetNMulticastRoutes() const [member function] + cls.add_method('GetNMulticastRoutes', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: ns3::Ipv4MulticastRoute ns3::Ipv4::GetMulticastRoute(uint32_t i) const [member function] + cls.add_method('GetMulticastRoute', + 'ns3::Ipv4MulticastRoute', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::RemoveMulticastRoute(uint32_t i) [member function] + cls.add_method('RemoveMulticastRoute', + 'void', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: uint32_t ns3::Ipv4::AddInterface(ns3::Ptr device) [member function] + cls.add_method('AddInterface', + 'uint32_t', + [param('ns3::Ptr< ns3::NetDevice >', 'device')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: uint32_t ns3::Ipv4::GetNInterfaces() [member function] + cls.add_method('GetNInterfaces', + 'uint32_t', + [], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: uint32_t ns3::Ipv4::FindInterfaceForAddr(ns3::Ipv4Address addr) const [member function] + cls.add_method('FindInterfaceForAddr', + 'uint32_t', + [param('ns3::Ipv4Address', 'addr')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: uint32_t ns3::Ipv4::FindInterfaceForAddr(ns3::Ipv4Address addr, ns3::Ipv4Mask mask) const [member function] + cls.add_method('FindInterfaceForAddr', + 'uint32_t', + [param('ns3::Ipv4Address', 'addr'), param('ns3::Ipv4Mask', 'mask')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: int32_t ns3::Ipv4::FindInterfaceForDevice(ns3::Ptr nd) const [member function] + cls.add_method('FindInterfaceForDevice', + 'int32_t', + [param('ns3::Ptr< ns3::NetDevice >', 'nd')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: ns3::Ptr ns3::Ipv4::GetNetDevice(uint32_t i) [member function] + cls.add_method('GetNetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::JoinMulticastGroup(ns3::Ipv4Address origin, ns3::Ipv4Address group) [member function] + cls.add_method('JoinMulticastGroup', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::LeaveMulticastGroup(ns3::Ipv4Address origin, ns3::Ipv4Address group) [member function] + cls.add_method('LeaveMulticastGroup', + 'void', + [param('ns3::Ipv4Address', 'origin'), param('ns3::Ipv4Address', 'group')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::SetAddress(uint32_t i, ns3::Ipv4Address address) [member function] + cls.add_method('SetAddress', + 'void', + [param('uint32_t', 'i'), param('ns3::Ipv4Address', 'address')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::SetNetworkMask(uint32_t i, ns3::Ipv4Mask mask) [member function] + cls.add_method('SetNetworkMask', + 'void', + [param('uint32_t', 'i'), param('ns3::Ipv4Mask', 'mask')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: ns3::Ipv4Mask ns3::Ipv4::GetNetworkMask(uint32_t i) const [member function] + cls.add_method('GetNetworkMask', + 'ns3::Ipv4Mask', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::SetMetric(uint32_t i, uint16_t metric) [member function] + cls.add_method('SetMetric', + 'void', + [param('uint32_t', 'i'), param('uint16_t', 'metric')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: uint16_t ns3::Ipv4::GetMetric(uint32_t i) const [member function] + cls.add_method('GetMetric', + 'uint16_t', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: ns3::Ipv4Address ns3::Ipv4::GetAddress(uint32_t i) const [member function] + cls.add_method('GetAddress', + 'ns3::Ipv4Address', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: ns3::Ipv4Address ns3::Ipv4::GetSourceAddress(ns3::Ipv4Address destination) const [member function] + cls.add_method('GetSourceAddress', + 'ns3::Ipv4Address', + [param('ns3::Ipv4Address', 'destination')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: bool ns3::Ipv4::GetIfIndexForDestination(ns3::Ipv4Address dest, uint32_t & ifIndex) const [member function] + cls.add_method('GetIfIndexForDestination', + 'bool', + [param('ns3::Ipv4Address', 'dest'), param('uint32_t &', 'ifIndex')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: uint16_t ns3::Ipv4::GetMtu(uint32_t i) const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: bool ns3::Ipv4::IsUp(uint32_t i) const [member function] + cls.add_method('IsUp', + 'bool', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::SetUp(uint32_t i) [member function] + cls.add_method('SetUp', + 'void', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: void ns3::Ipv4::SetDown(uint32_t i) [member function] + cls.add_method('SetDown', + 'void', + [param('uint32_t', 'i')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: uint32_t ns3::Ipv4::GetIfIndexByAddress(ns3::Ipv4Address addr, ns3::Ipv4Mask mask=ns3::Ipv4Mask(((const char*)"255.255.255.255"))) [member function] + cls.add_method('GetIfIndexByAddress', + 'uint32_t', + [param('ns3::Ipv4Address', 'addr'), param('ns3::Ipv4Mask', 'mask', default_value='ns3::Ipv4Mask(((const char*)"255.255.255.255"))')], + is_virtual=True) + return + +def register_Ns3Ipv4RoutingProtocol_methods(root_module, cls): + ## ipv4.h: ns3::Ipv4RoutingProtocol::IF_INDEX_ANY [variable] + cls.add_static_attribute('IF_INDEX_ANY', 'uint32_t const', is_const=True) + ## ipv4.h: ns3::Ipv4RoutingProtocol::Ipv4RoutingProtocol(ns3::Ipv4RoutingProtocol const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ipv4RoutingProtocol const &', 'arg0')]) + ## ipv4.h: ns3::Ipv4RoutingProtocol::Ipv4RoutingProtocol() [constructor] + cls.add_constructor([]) + ## ipv4.h: bool ns3::Ipv4RoutingProtocol::RequestRoute(uint32_t ifIndex, ns3::Ipv4Header const & ipHeader, ns3::Ptr packet, ns3::Callback,const ns3::Ipv4Header&,ns3::empty,ns3::empty> routeReply) [member function] + cls.add_method('RequestRoute', + 'bool', + [param('uint32_t', 'ifIndex'), param('ns3::Ipv4Header const &', 'ipHeader'), param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Callback< void, bool, ns3::Ipv4Route const &, ns3::Ptr< ns3::Packet >, ns3::Ipv4Header const &, ns3::empty, ns3::empty >', 'routeReply')], + is_pure_virtual=True, is_virtual=True) + ## ipv4.h: bool ns3::Ipv4RoutingProtocol::RequestIfIndex(ns3::Ipv4Address destination, uint32_t & ifIndex) [member function] + cls.add_method('RequestIfIndex', + 'bool', + [param('ns3::Ipv4Address', 'destination'), param('uint32_t &', 'ifIndex')], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3NetDevice_methods(root_module, cls): + ## net-device.h: ns3::NetDevice::NetDevice(ns3::NetDevice const & arg0) [copy constructor] + cls.add_constructor([param('ns3::NetDevice const &', 'arg0')]) + ## net-device.h: ns3::NetDevice::NetDevice() [constructor] + cls.add_constructor([]) + ## net-device.h: static ns3::TypeId ns3::NetDevice::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## net-device.h: void ns3::NetDevice::SetName(std::string const name) [member function] + cls.add_method('SetName', + 'void', + [param('std::string const', 'name')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: std::string ns3::NetDevice::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: void ns3::NetDevice::SetIfIndex(uint32_t const index) [member function] + cls.add_method('SetIfIndex', + 'void', + [param('uint32_t const', 'index')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: uint32_t ns3::NetDevice::GetIfIndex() const [member function] + cls.add_method('GetIfIndex', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: ns3::Ptr ns3::NetDevice::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::Channel >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: ns3::Address ns3::NetDevice::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Address', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::SetMtu(uint16_t const mtu) [member function] + cls.add_method('SetMtu', + 'bool', + [param('uint16_t const', 'mtu')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: uint16_t ns3::NetDevice::GetMtu() const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::IsLinkUp() const [member function] + cls.add_method('IsLinkUp', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: void ns3::NetDevice::SetLinkChangeCallback(ns3::Callback callback) [member function] + cls.add_method('SetLinkChangeCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: ns3::Address ns3::NetDevice::GetBroadcast() const [member function] + cls.add_method('GetBroadcast', + 'ns3::Address', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: ns3::Address ns3::NetDevice::GetMulticast() const [member function] + cls.add_method('GetMulticast', + 'ns3::Address', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: ns3::Address ns3::NetDevice::MakeMulticastAddress(ns3::Ipv4Address multicastGroup) const [member function] + cls.add_method('MakeMulticastAddress', + 'ns3::Address', + [param('ns3::Ipv4Address', 'multicastGroup')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::IsPointToPoint() const [member function] + cls.add_method('IsPointToPoint', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::Send(ns3::Ptr packet, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('Send', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::SendFrom(ns3::Ptr packet, ns3::Address const & source, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('SendFrom', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'source'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: ns3::Ptr ns3::NetDevice::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: void ns3::NetDevice::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::NeedsArp() const [member function] + cls.add_method('NeedsArp', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## net-device.h: void ns3::NetDevice::SetReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::empty, ns3::empty> cb) [member function] + cls.add_method('SetReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::empty, ns3::empty >', 'cb')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: void ns3::NetDevice::SetPromiscReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> cb) [member function] + cls.add_method('SetPromiscReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'cb')], + is_pure_virtual=True, is_virtual=True) + ## net-device.h: bool ns3::NetDevice::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3Node_methods(root_module, cls): + ## node.h: ns3::Node::Node(ns3::Node const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Node const &', 'arg0')]) + ## node.h: static ns3::TypeId ns3::Node::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## node.h: ns3::Node::Node() [constructor] + cls.add_constructor([]) + ## node.h: ns3::Node::Node(uint32_t systemId) [constructor] + cls.add_constructor([param('uint32_t', 'systemId')]) + ## node.h: uint32_t ns3::Node::GetId() const [member function] + cls.add_method('GetId', + 'uint32_t', + [], + is_const=True) + ## node.h: uint32_t ns3::Node::GetSystemId() const [member function] + cls.add_method('GetSystemId', + 'uint32_t', + [], + is_const=True) + ## node.h: uint32_t ns3::Node::AddDevice(ns3::Ptr device) [member function] + cls.add_method('AddDevice', + 'uint32_t', + [param('ns3::Ptr< ns3::NetDevice >', 'device')]) + ## node.h: ns3::Ptr ns3::Node::GetDevice(uint32_t index) const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'index')], + is_const=True) + ## node.h: uint32_t ns3::Node::GetNDevices() const [member function] + cls.add_method('GetNDevices', + 'uint32_t', + [], + is_const=True) + ## node.h: uint32_t ns3::Node::AddApplication(ns3::Ptr application) [member function] + cls.add_method('AddApplication', + 'uint32_t', + [param('ns3::Ptr< ns3::Application >', 'application')]) + ## node.h: ns3::Ptr ns3::Node::GetApplication(uint32_t index) const [member function] + cls.add_method('GetApplication', + 'ns3::Ptr< ns3::Application >', + [param('uint32_t', 'index')], + is_const=True) + ## node.h: uint32_t ns3::Node::GetNApplications() const [member function] + cls.add_method('GetNApplications', + 'uint32_t', + [], + is_const=True) + ## node.h: void ns3::Node::RegisterProtocolHandler(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> handler, uint16_t protocolType, ns3::Ptr device, bool promiscuous=false) [member function] + cls.add_method('RegisterProtocolHandler', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'handler'), param('uint16_t', 'protocolType'), param('ns3::Ptr< ns3::NetDevice >', 'device'), param('bool', 'promiscuous', default_value='false')]) + ## node.h: void ns3::Node::UnregisterProtocolHandler(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> handler) [member function] + cls.add_method('UnregisterProtocolHandler', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'handler')]) + ## node.h: void ns3::Node::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## node.h: void ns3::Node::NotifyDeviceAdded(ns3::Ptr device) [member function] + cls.add_method('NotifyDeviceAdded', + 'void', + [param('ns3::Ptr< ns3::NetDevice >', 'device')], + visibility='private', is_virtual=True) + return + +def register_Ns3PacketSocketFactory_methods(root_module, cls): + ## packet-socket-factory.h: ns3::PacketSocketFactory::PacketSocketFactory(ns3::PacketSocketFactory const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketSocketFactory const &', 'arg0')]) + ## packet-socket-factory.h: static ns3::TypeId ns3::PacketSocketFactory::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## packet-socket-factory.h: ns3::PacketSocketFactory::PacketSocketFactory() [constructor] + cls.add_constructor([]) + ## packet-socket-factory.h: ns3::Ptr ns3::PacketSocketFactory::CreateSocket() [member function] + cls.add_method('CreateSocket', + 'ns3::Ptr< ns3::Socket >', + [], + is_virtual=True) + return + +def register_Ns3SimpleChannel_methods(root_module, cls): + ## simple-channel.h: ns3::SimpleChannel::SimpleChannel(ns3::SimpleChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SimpleChannel const &', 'arg0')]) + ## simple-channel.h: static ns3::TypeId ns3::SimpleChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## simple-channel.h: ns3::SimpleChannel::SimpleChannel() [constructor] + cls.add_constructor([]) + ## simple-channel.h: void ns3::SimpleChannel::Send(ns3::Ptr p, uint16_t protocol, ns3::Mac48Address to, ns3::Mac48Address from, ns3::Ptr sender) [member function] + cls.add_method('Send', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('uint16_t', 'protocol'), param('ns3::Mac48Address', 'to'), param('ns3::Mac48Address', 'from'), param('ns3::Ptr< ns3::SimpleNetDevice >', 'sender')]) + ## simple-channel.h: void ns3::SimpleChannel::Add(ns3::Ptr device) [member function] + cls.add_method('Add', + 'void', + [param('ns3::Ptr< ns3::SimpleNetDevice >', 'device')]) + ## simple-channel.h: uint32_t ns3::SimpleChannel::GetNDevices() const [member function] + cls.add_method('GetNDevices', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## simple-channel.h: ns3::Ptr ns3::SimpleChannel::GetDevice(uint32_t i) const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_const=True, is_virtual=True) + return + +def register_Ns3SimpleNetDevice_methods(root_module, cls): + ## simple-net-device.h: ns3::SimpleNetDevice::SimpleNetDevice(ns3::SimpleNetDevice const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SimpleNetDevice const &', 'arg0')]) + ## simple-net-device.h: static ns3::TypeId ns3::SimpleNetDevice::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## simple-net-device.h: ns3::SimpleNetDevice::SimpleNetDevice() [constructor] + cls.add_constructor([]) + ## simple-net-device.h: void ns3::SimpleNetDevice::Receive(ns3::Ptr packet, uint16_t protocol, ns3::Mac48Address to, ns3::Mac48Address from) [member function] + cls.add_method('Receive', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('uint16_t', 'protocol'), param('ns3::Mac48Address', 'to'), param('ns3::Mac48Address', 'from')]) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetChannel(ns3::Ptr channel) [member function] + cls.add_method('SetChannel', + 'void', + [param('ns3::Ptr< ns3::SimpleChannel >', 'channel')]) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetAddress(ns3::Mac48Address address) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Mac48Address', 'address')]) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetName(std::string const name) [member function] + cls.add_method('SetName', + 'void', + [param('std::string const', 'name')], + is_virtual=True) + ## simple-net-device.h: std::string ns3::SimpleNetDevice::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetIfIndex(uint32_t const index) [member function] + cls.add_method('SetIfIndex', + 'void', + [param('uint32_t const', 'index')], + is_virtual=True) + ## simple-net-device.h: uint32_t ns3::SimpleNetDevice::GetIfIndex() const [member function] + cls.add_method('GetIfIndex', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: ns3::Ptr ns3::SimpleNetDevice::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::Channel >', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: ns3::Address ns3::SimpleNetDevice::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::SetMtu(uint16_t const mtu) [member function] + cls.add_method('SetMtu', + 'bool', + [param('uint16_t const', 'mtu')], + is_virtual=True) + ## simple-net-device.h: uint16_t ns3::SimpleNetDevice::GetMtu() const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::IsLinkUp() const [member function] + cls.add_method('IsLinkUp', + 'bool', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetLinkChangeCallback(ns3::Callback callback) [member function] + cls.add_method('SetLinkChangeCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: ns3::Address ns3::SimpleNetDevice::GetBroadcast() const [member function] + cls.add_method('GetBroadcast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: ns3::Address ns3::SimpleNetDevice::GetMulticast() const [member function] + cls.add_method('GetMulticast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: ns3::Address ns3::SimpleNetDevice::MakeMulticastAddress(ns3::Ipv4Address multicastGroup) const [member function] + cls.add_method('MakeMulticastAddress', + 'ns3::Address', + [param('ns3::Ipv4Address', 'multicastGroup')], + is_const=True, is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::IsPointToPoint() const [member function] + cls.add_method('IsPointToPoint', + 'bool', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::Send(ns3::Ptr packet, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('Send', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::SendFrom(ns3::Ptr packet, ns3::Address const & source, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('SendFrom', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'source'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## simple-net-device.h: ns3::Ptr ns3::SimpleNetDevice::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::NeedsArp() const [member function] + cls.add_method('NeedsArp', + 'bool', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::empty, ns3::empty> cb) [member function] + cls.add_method('SetReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::empty, ns3::empty >', 'cb')], + is_virtual=True) + ## simple-net-device.h: void ns3::SimpleNetDevice::SetPromiscReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> cb) [member function] + cls.add_method('SetPromiscReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'cb')], + is_virtual=True) + ## simple-net-device.h: bool ns3::SimpleNetDevice::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## simple-net-device.h: void ns3::SimpleNetDevice::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + ## address-utils.h: extern void ns3::ReadFrom(ns3::Buffer::Iterator & i, ns3::Mac48Address & ad) [free function] + module.add_function('ReadFrom', + 'void', + [param('ns3::Buffer::Iterator &', 'i'), param('ns3::Mac48Address &', 'ad')]) + ## address-utils.h: extern void ns3::ReadFrom(ns3::Buffer::Iterator & i, ns3::Address & ad, uint32_t len) [free function] + module.add_function('ReadFrom', + 'void', + [param('ns3::Buffer::Iterator &', 'i'), param('ns3::Address &', 'ad'), param('uint32_t', 'len')]) + ## address-utils.h: extern void ns3::ReadFrom(ns3::Buffer::Iterator & i, ns3::Ipv4Address & ad) [free function] + module.add_function('ReadFrom', + 'void', + [param('ns3::Buffer::Iterator &', 'i'), param('ns3::Ipv4Address &', 'ad')]) + ## ipv4-address.h: extern ns3::Ptr ns3::MakeIpv4AddressChecker() [free function] + module.add_function('MakeIpv4AddressChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## address-utils.h: extern void ns3::WriteTo(ns3::Buffer::Iterator & i, ns3::Mac48Address ad) [free function] + module.add_function('WriteTo', + 'void', + [param('ns3::Buffer::Iterator &', 'i'), param('ns3::Mac48Address', 'ad')]) + ## address-utils.h: extern void ns3::WriteTo(ns3::Buffer::Iterator & i, ns3::Address const & ad) [free function] + module.add_function('WriteTo', + 'void', + [param('ns3::Buffer::Iterator &', 'i'), param('ns3::Address const &', 'ad')]) + ## address-utils.h: extern void ns3::WriteTo(ns3::Buffer::Iterator & i, ns3::Ipv4Address ad) [free function] + module.add_function('WriteTo', + 'void', + [param('ns3::Buffer::Iterator &', 'i'), param('ns3::Ipv4Address', 'ad')]) + ## address.h: extern ns3::Ptr ns3::MakeAddressChecker() [free function] + module.add_function('MakeAddressChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## ipv4-address.h: extern ns3::Ptr ns3::MakeIpv4MaskChecker() [free function] + module.add_function('MakeIpv4MaskChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## mac48-address.h: extern ns3::Ptr ns3::MakeMac48AddressChecker() [free function] + module.add_function('MakeMac48AddressChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_olsr.py b/bindings/python/ns3_module_olsr.py new file mode 100644 index 000000000..bf30ff817 --- /dev/null +++ b/bindings/python/ns3_module_olsr.py @@ -0,0 +1,468 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + ## olsr-agent.h: ns3::olsr::Agent [class] + module.add_class('Agent', parent=root_module['ns3::Object']) + ## olsr-header.h: ns3::olsr::MessageHeader [class] + module.add_class('MessageHeader', parent=root_module['ns3::Header']) + ## olsr-header.h: ns3::olsr::MessageHeader::MessageType [enumeration] + module.add_enum('MessageType', ['HELLO_MESSAGE', 'TC_MESSAGE', 'MID_MESSAGE', 'HNA_MESSAGE'], outer_class=root_module['ns3::olsr::MessageHeader']) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello [struct] + module.add_class('Hello', outer_class=root_module['ns3::olsr::MessageHeader']) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::LinkMessage [struct] + module.add_class('LinkMessage', outer_class=root_module['ns3::olsr::MessageHeader::Hello']) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna [struct] + module.add_class('Hna', outer_class=root_module['ns3::olsr::MessageHeader']) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::Association [struct] + module.add_class('Association', outer_class=root_module['ns3::olsr::MessageHeader::Hna']) + ## olsr-header.h: ns3::olsr::MessageHeader::Mid [struct] + module.add_class('Mid', outer_class=root_module['ns3::olsr::MessageHeader']) + ## olsr-header.h: ns3::olsr::MessageHeader::Tc [struct] + module.add_class('Tc', outer_class=root_module['ns3::olsr::MessageHeader']) + ## olsr-header.h: ns3::olsr::PacketHeader [class] + module.add_class('PacketHeader', parent=root_module['ns3::Header']) + module.add_container('std::vector< ns3::olsr::MessageHeader::Hello::LinkMessage >', 'ns3::olsr::MessageHeader::Hello::LinkMessage', container_type='vector') + module.add_container('std::vector< ns3::olsr::MessageHeader::Hna::Association >', 'ns3::olsr::MessageHeader::Hna::Association', container_type='vector') + +def register_methods(root_module): + register_Ns3OlsrAgent_methods(root_module, root_module['ns3::olsr::Agent']) + register_Ns3OlsrMessageHeader_methods(root_module, root_module['ns3::olsr::MessageHeader']) + register_Ns3OlsrMessageHeaderHello_methods(root_module, root_module['ns3::olsr::MessageHeader::Hello']) + register_Ns3OlsrMessageHeaderHelloLinkMessage_methods(root_module, root_module['ns3::olsr::MessageHeader::Hello::LinkMessage']) + register_Ns3OlsrMessageHeaderHna_methods(root_module, root_module['ns3::olsr::MessageHeader::Hna']) + register_Ns3OlsrMessageHeaderHnaAssociation_methods(root_module, root_module['ns3::olsr::MessageHeader::Hna::Association']) + register_Ns3OlsrMessageHeaderMid_methods(root_module, root_module['ns3::olsr::MessageHeader::Mid']) + register_Ns3OlsrMessageHeaderTc_methods(root_module, root_module['ns3::olsr::MessageHeader::Tc']) + register_Ns3OlsrPacketHeader_methods(root_module, root_module['ns3::olsr::PacketHeader']) + return + +def register_Ns3OlsrAgent_methods(root_module, cls): + ## olsr-agent.h: ns3::olsr::Agent::Agent(ns3::olsr::Agent const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::Agent const &', 'arg0')]) + ## olsr-agent.h: ns3::olsr::Agent::Agent() [constructor] + cls.add_constructor([]) + ## olsr-agent.h: static ns3::TypeId ns3::olsr::Agent::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## olsr-agent.h: void ns3::olsr::Agent::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_pure_virtual=True, is_virtual=True) + ## olsr-agent.h: void ns3::olsr::Agent::SetMainInterface(uint32_t interface) [member function] + cls.add_method('SetMainInterface', + 'void', + [param('uint32_t', 'interface')], + is_pure_virtual=True, is_virtual=True) + ## olsr-agent.h: void ns3::olsr::Agent::Start() [member function] + cls.add_method('Start', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3OlsrMessageHeader_methods(root_module, cls): + cls.add_output_stream_operator() + ## olsr-header.h: ns3::olsr::MessageHeader::MessageHeader(ns3::olsr::MessageHeader const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::MessageHeader const &', 'arg0')]) + ## olsr-header.h: ns3::olsr::MessageHeader::MessageHeader() [constructor] + cls.add_constructor([]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_virtual=True) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello & ns3::olsr::MessageHeader::GetHello() [member function] + cls.add_method('GetHello', + 'ns3::olsr::MessageHeader::Hello &', + []) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello const & ns3::olsr::MessageHeader::GetHello() const [member function] + cls.add_method('GetHello', + 'ns3::olsr::MessageHeader::Hello const &', + [], + is_const=True) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna & ns3::olsr::MessageHeader::GetHna() [member function] + cls.add_method('GetHna', + 'ns3::olsr::MessageHeader::Hna &', + []) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna const & ns3::olsr::MessageHeader::GetHna() const [member function] + cls.add_method('GetHna', + 'ns3::olsr::MessageHeader::Hna const &', + [], + is_const=True) + ## olsr-header.h: uint8_t ns3::olsr::MessageHeader::GetHopCount() const [member function] + cls.add_method('GetHopCount', + 'uint8_t', + [], + is_const=True) + ## olsr-header.h: ns3::TypeId ns3::olsr::MessageHeader::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## olsr-header.h: uint16_t ns3::olsr::MessageHeader::GetMessageSequenceNumber() const [member function] + cls.add_method('GetMessageSequenceNumber', + 'uint16_t', + [], + is_const=True) + ## olsr-header.h: ns3::olsr::MessageHeader::MessageType ns3::olsr::MessageHeader::GetMessageType() const [member function] + cls.add_method('GetMessageType', + 'ns3::olsr::MessageHeader::MessageType', + [], + is_const=True) + ## olsr-header.h: ns3::olsr::MessageHeader::Mid & ns3::olsr::MessageHeader::GetMid() [member function] + cls.add_method('GetMid', + 'ns3::olsr::MessageHeader::Mid &', + []) + ## olsr-header.h: ns3::olsr::MessageHeader::Mid const & ns3::olsr::MessageHeader::GetMid() const [member function] + cls.add_method('GetMid', + 'ns3::olsr::MessageHeader::Mid const &', + [], + is_const=True) + ## olsr-header.h: ns3::Ipv4Address ns3::olsr::MessageHeader::GetOriginatorAddress() const [member function] + cls.add_method('GetOriginatorAddress', + 'ns3::Ipv4Address', + [], + is_const=True) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## olsr-header.h: ns3::olsr::MessageHeader::Tc & ns3::olsr::MessageHeader::GetTc() [member function] + cls.add_method('GetTc', + 'ns3::olsr::MessageHeader::Tc &', + []) + ## olsr-header.h: ns3::olsr::MessageHeader::Tc const & ns3::olsr::MessageHeader::GetTc() const [member function] + cls.add_method('GetTc', + 'ns3::olsr::MessageHeader::Tc const &', + [], + is_const=True) + ## olsr-header.h: uint8_t ns3::olsr::MessageHeader::GetTimeToLive() const [member function] + cls.add_method('GetTimeToLive', + 'uint8_t', + [], + is_const=True) + ## olsr-header.h: static ns3::TypeId ns3::olsr::MessageHeader::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## olsr-header.h: ns3::Time ns3::olsr::MessageHeader::GetVTime() const [member function] + cls.add_method('GetVTime', + 'ns3::Time', + [], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True, is_virtual=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::SetHopCount(uint8_t hopCount) [member function] + cls.add_method('SetHopCount', + 'void', + [param('uint8_t', 'hopCount')]) + ## olsr-header.h: void ns3::olsr::MessageHeader::SetMessageSequenceNumber(uint16_t messageSequenceNumber) [member function] + cls.add_method('SetMessageSequenceNumber', + 'void', + [param('uint16_t', 'messageSequenceNumber')]) + ## olsr-header.h: void ns3::olsr::MessageHeader::SetMessageType(ns3::olsr::MessageHeader::MessageType messageType) [member function] + cls.add_method('SetMessageType', + 'void', + [param('ns3::olsr::MessageHeader::MessageType', 'messageType')]) + ## olsr-header.h: void ns3::olsr::MessageHeader::SetOriginatorAddress(ns3::Ipv4Address originatorAddress) [member function] + cls.add_method('SetOriginatorAddress', + 'void', + [param('ns3::Ipv4Address', 'originatorAddress')]) + ## olsr-header.h: void ns3::olsr::MessageHeader::SetTimeToLive(uint8_t timeToLive) [member function] + cls.add_method('SetTimeToLive', + 'void', + [param('uint8_t', 'timeToLive')]) + ## olsr-header.h: void ns3::olsr::MessageHeader::SetVTime(ns3::Time time) [member function] + cls.add_method('SetVTime', + 'void', + [param('ns3::Time', 'time')]) + return + +def register_Ns3OlsrMessageHeaderHello_methods(root_module, cls): + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::Hello() [constructor] + cls.add_constructor([]) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::Hello(ns3::olsr::MessageHeader::Hello const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::MessageHeader::Hello const &', 'arg0')]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Hello::Deserialize(ns3::Buffer::Iterator start, uint32_t messageSize) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start'), param('uint32_t', 'messageSize')]) + ## olsr-header.h: ns3::Time ns3::olsr::MessageHeader::Hello::GetHTime() const [member function] + cls.add_method('GetHTime', + 'ns3::Time', + [], + is_const=True) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Hello::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Hello::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Hello::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Hello::SetHTime(ns3::Time time) [member function] + cls.add_method('SetHTime', + 'void', + [param('ns3::Time', 'time')]) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::hTime [variable] + cls.add_instance_attribute('hTime', 'uint8_t', is_const=False) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::linkMessages [variable] + cls.add_instance_attribute('linkMessages', 'std::vector< ns3::olsr::MessageHeader::Hello::LinkMessage >', is_const=False) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::willingness [variable] + cls.add_instance_attribute('willingness', 'uint8_t', is_const=False) + return + +def register_Ns3OlsrMessageHeaderHelloLinkMessage_methods(root_module, cls): + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::LinkMessage::linkCode [variable] + cls.add_instance_attribute('linkCode', 'uint8_t', is_const=False) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::LinkMessage::neighborInterfaceAddresses [variable] + cls.add_instance_attribute('neighborInterfaceAddresses', 'std::vector< ns3::Ipv4Address >', is_const=False) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::LinkMessage::LinkMessage(ns3::olsr::MessageHeader::Hello::LinkMessage const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::MessageHeader::Hello::LinkMessage const &', 'arg0')]) + ## olsr-header.h: ns3::olsr::MessageHeader::Hello::LinkMessage::LinkMessage() [constructor] + cls.add_constructor([]) + return + +def register_Ns3OlsrMessageHeaderHna_methods(root_module, cls): + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::Hna() [constructor] + cls.add_constructor([]) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::Hna(ns3::olsr::MessageHeader::Hna const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::MessageHeader::Hna const &', 'arg0')]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Hna::Deserialize(ns3::Buffer::Iterator start, uint32_t messageSize) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start'), param('uint32_t', 'messageSize')]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Hna::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Hna::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Hna::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::associations [variable] + cls.add_instance_attribute('associations', 'std::vector< ns3::olsr::MessageHeader::Hna::Association >', is_const=False) + return + +def register_Ns3OlsrMessageHeaderHnaAssociation_methods(root_module, cls): + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::Association::address [variable] + cls.add_instance_attribute('address', 'ns3::Ipv4Address', is_const=False) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::Association::mask [variable] + cls.add_instance_attribute('mask', 'ns3::Ipv4Mask', is_const=False) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::Association::Association(ns3::olsr::MessageHeader::Hna::Association const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::MessageHeader::Hna::Association const &', 'arg0')]) + ## olsr-header.h: ns3::olsr::MessageHeader::Hna::Association::Association() [constructor] + cls.add_constructor([]) + return + +def register_Ns3OlsrMessageHeaderMid_methods(root_module, cls): + ## olsr-header.h: ns3::olsr::MessageHeader::Mid::Mid() [constructor] + cls.add_constructor([]) + ## olsr-header.h: ns3::olsr::MessageHeader::Mid::Mid(ns3::olsr::MessageHeader::Mid const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::MessageHeader::Mid const &', 'arg0')]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Mid::Deserialize(ns3::Buffer::Iterator start, uint32_t messageSize) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start'), param('uint32_t', 'messageSize')]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Mid::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Mid::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Mid::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True) + ## olsr-header.h: ns3::olsr::MessageHeader::Mid::interfaceAddresses [variable] + cls.add_instance_attribute('interfaceAddresses', 'std::vector< ns3::Ipv4Address >', is_const=False) + return + +def register_Ns3OlsrMessageHeaderTc_methods(root_module, cls): + ## olsr-header.h: ns3::olsr::MessageHeader::Tc::Tc() [constructor] + cls.add_constructor([]) + ## olsr-header.h: ns3::olsr::MessageHeader::Tc::Tc(ns3::olsr::MessageHeader::Tc const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::MessageHeader::Tc const &', 'arg0')]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Tc::Deserialize(ns3::Buffer::Iterator start, uint32_t messageSize) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start'), param('uint32_t', 'messageSize')]) + ## olsr-header.h: uint32_t ns3::olsr::MessageHeader::Tc::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Tc::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True) + ## olsr-header.h: void ns3::olsr::MessageHeader::Tc::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True) + ## olsr-header.h: ns3::olsr::MessageHeader::Tc::ansn [variable] + cls.add_instance_attribute('ansn', 'uint16_t', is_const=False) + ## olsr-header.h: ns3::olsr::MessageHeader::Tc::neighborAddresses [variable] + cls.add_instance_attribute('neighborAddresses', 'std::vector< ns3::Ipv4Address >', is_const=False) + return + +def register_Ns3OlsrPacketHeader_methods(root_module, cls): + cls.add_output_stream_operator() + ## olsr-header.h: ns3::olsr::PacketHeader::PacketHeader(ns3::olsr::PacketHeader const & arg0) [copy constructor] + cls.add_constructor([param('ns3::olsr::PacketHeader const &', 'arg0')]) + ## olsr-header.h: ns3::olsr::PacketHeader::PacketHeader() [constructor] + cls.add_constructor([]) + ## olsr-header.h: uint32_t ns3::olsr::PacketHeader::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'uint32_t', + [param('ns3::Buffer::Iterator', 'start')], + is_virtual=True) + ## olsr-header.h: ns3::TypeId ns3::olsr::PacketHeader::GetInstanceTypeId() const [member function] + cls.add_method('GetInstanceTypeId', + 'ns3::TypeId', + [], + is_const=True, is_virtual=True) + ## olsr-header.h: uint16_t ns3::olsr::PacketHeader::GetPacketLength() const [member function] + cls.add_method('GetPacketLength', + 'uint16_t', + [], + is_const=True) + ## olsr-header.h: uint16_t ns3::olsr::PacketHeader::GetPacketSequenceNumber() const [member function] + cls.add_method('GetPacketSequenceNumber', + 'uint16_t', + [], + is_const=True) + ## olsr-header.h: uint32_t ns3::olsr::PacketHeader::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## olsr-header.h: static ns3::TypeId ns3::olsr::PacketHeader::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## olsr-header.h: void ns3::olsr::PacketHeader::Print(std::ostream & os) const [member function] + cls.add_method('Print', + 'void', + [param('std::ostream &', 'os')], + is_const=True, is_virtual=True) + ## olsr-header.h: void ns3::olsr::PacketHeader::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'void', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True, is_virtual=True) + ## olsr-header.h: void ns3::olsr::PacketHeader::SetPacketLength(uint16_t length) [member function] + cls.add_method('SetPacketLength', + 'void', + [param('uint16_t', 'length')]) + ## olsr-header.h: void ns3::olsr::PacketHeader::SetPacketSequenceNumber(uint16_t seqnum) [member function] + cls.add_method('SetPacketSequenceNumber', + 'void', + [param('uint16_t', 'seqnum')]) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + ## olsr-header.h: extern double ns3::olsr::EmfToSeconds(uint8_t emf) [free function] + module.add_function('EmfToSeconds', + 'double', + [param('uint8_t', 'emf')]) + ## olsr-header.h: extern uint8_t ns3::olsr::SecondsToEmf(double seconds) [free function] + module.add_function('SecondsToEmf', + 'uint8_t', + [param('double', 'seconds')]) + return + diff --git a/bindings/python/ns3_module_onoff.py b/bindings/python/ns3_module_onoff.py new file mode 100644 index 000000000..57833a570 --- /dev/null +++ b/bindings/python/ns3_module_onoff.py @@ -0,0 +1,103 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## onoff-application.h: ns3::OnOffApplication [class] + module.add_class('OnOffApplication', parent=root_module['ns3::Application']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3OnOffApplication_methods(root_module, root_module['ns3::OnOffApplication']) + return + +def register_Ns3OnOffApplication_methods(root_module, cls): + ## onoff-application.h: ns3::OnOffApplication::OnOffApplication(ns3::OnOffApplication const & arg0) [copy constructor] + cls.add_constructor([param('ns3::OnOffApplication const &', 'arg0')]) + ## onoff-application.h: static ns3::TypeId ns3::OnOffApplication::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## onoff-application.h: ns3::OnOffApplication::OnOffApplication() [constructor] + cls.add_constructor([]) + ## onoff-application.h: void ns3::OnOffApplication::SetMaxBytes(uint32_t maxBytes) [member function] + cls.add_method('SetMaxBytes', + 'void', + [param('uint32_t', 'maxBytes')]) + ## onoff-application.h: void ns3::OnOffApplication::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## onoff-application.h: void ns3::OnOffApplication::StartApplication() [member function] + cls.add_method('StartApplication', + 'void', + [], + visibility='private', is_virtual=True) + ## onoff-application.h: void ns3::OnOffApplication::StopApplication() [member function] + cls.add_method('StopApplication', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_packet_sink.py b/bindings/python/ns3_module_packet_sink.py new file mode 100644 index 000000000..291f43a11 --- /dev/null +++ b/bindings/python/ns3_module_packet_sink.py @@ -0,0 +1,99 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## packet-sink.h: ns3::PacketSink [class] + module.add_class('PacketSink', parent=root_module['ns3::Application']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3PacketSink_methods(root_module, root_module['ns3::PacketSink']) + return + +def register_Ns3PacketSink_methods(root_module, cls): + ## packet-sink.h: ns3::PacketSink::PacketSink(ns3::PacketSink const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketSink const &', 'arg0')]) + ## packet-sink.h: static ns3::TypeId ns3::PacketSink::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## packet-sink.h: ns3::PacketSink::PacketSink() [constructor] + cls.add_constructor([]) + ## packet-sink.h: void ns3::PacketSink::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## packet-sink.h: void ns3::PacketSink::StartApplication() [member function] + cls.add_method('StartApplication', + 'void', + [], + visibility='private', is_virtual=True) + ## packet-sink.h: void ns3::PacketSink::StopApplication() [member function] + cls.add_method('StopApplication', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_point_to_point.py b/bindings/python/ns3_module_point_to_point.py new file mode 100644 index 000000000..0945ba6cc --- /dev/null +++ b/bindings/python/ns3_module_point_to_point.py @@ -0,0 +1,284 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## point-to-point-channel.h: ns3::PointToPointChannel [class] + module.add_class('PointToPointChannel', parent=root_module['ns3::Channel']) + ## point-to-point-net-device.h: ns3::PointToPointNetDevice [class] + module.add_class('PointToPointNetDevice', parent=root_module['ns3::NetDevice']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3PointToPointChannel_methods(root_module, root_module['ns3::PointToPointChannel']) + register_Ns3PointToPointNetDevice_methods(root_module, root_module['ns3::PointToPointNetDevice']) + return + +def register_Ns3PointToPointChannel_methods(root_module, cls): + ## point-to-point-channel.h: ns3::PointToPointChannel::PointToPointChannel(ns3::PointToPointChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PointToPointChannel const &', 'arg0')]) + ## point-to-point-channel.h: static ns3::TypeId ns3::PointToPointChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## point-to-point-channel.h: ns3::PointToPointChannel::PointToPointChannel() [constructor] + cls.add_constructor([]) + ## point-to-point-channel.h: void ns3::PointToPointChannel::Attach(ns3::Ptr device) [member function] + cls.add_method('Attach', + 'void', + [param('ns3::Ptr< ns3::PointToPointNetDevice >', 'device')]) + ## point-to-point-channel.h: bool ns3::PointToPointChannel::TransmitStart(ns3::Ptr p, ns3::Ptr src, ns3::Time txTime) [member function] + cls.add_method('TransmitStart', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'p'), param('ns3::Ptr< ns3::PointToPointNetDevice >', 'src'), param('ns3::Time', 'txTime')]) + ## point-to-point-channel.h: uint32_t ns3::PointToPointChannel::GetNDevices() const [member function] + cls.add_method('GetNDevices', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## point-to-point-channel.h: ns3::Ptr ns3::PointToPointChannel::GetPointToPointDevice(uint32_t i) const [member function] + cls.add_method('GetPointToPointDevice', + 'ns3::Ptr< ns3::PointToPointNetDevice >', + [param('uint32_t', 'i')], + is_const=True) + ## point-to-point-channel.h: ns3::Ptr ns3::PointToPointChannel::GetDevice(uint32_t i) const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_const=True, is_virtual=True) + return + +def register_Ns3PointToPointNetDevice_methods(root_module, cls): + ## point-to-point-net-device.h: ns3::PointToPointNetDevice::PointToPointNetDevice(ns3::PointToPointNetDevice const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PointToPointNetDevice const &', 'arg0')]) + ## point-to-point-net-device.h: static ns3::TypeId ns3::PointToPointNetDevice::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## point-to-point-net-device.h: ns3::PointToPointNetDevice::PointToPointNetDevice() [constructor] + cls.add_constructor([]) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetDataRate(ns3::DataRate bps) [member function] + cls.add_method('SetDataRate', + 'void', + [param('ns3::DataRate', 'bps')]) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetInterframeGap(ns3::Time t) [member function] + cls.add_method('SetInterframeGap', + 'void', + [param('ns3::Time', 't')]) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::Attach(ns3::Ptr ch) [member function] + cls.add_method('Attach', + 'bool', + [param('ns3::Ptr< ns3::PointToPointChannel >', 'ch')]) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetQueue(ns3::Ptr queue) [member function] + cls.add_method('SetQueue', + 'void', + [param('ns3::Ptr< ns3::Queue >', 'queue')]) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetReceiveErrorModel(ns3::Ptr em) [member function] + cls.add_method('SetReceiveErrorModel', + 'void', + [param('ns3::Ptr< ns3::ErrorModel >', 'em')]) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::Receive(ns3::Ptr p) [member function] + cls.add_method('Receive', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'p')]) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetAddress(ns3::Mac48Address addr) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Mac48Address', 'addr')]) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetFrameSize(uint16_t frameSize) [member function] + cls.add_method('SetFrameSize', + 'void', + [param('uint16_t', 'frameSize')]) + ## point-to-point-net-device.h: uint16_t ns3::PointToPointNetDevice::GetFrameSize() const [member function] + cls.add_method('GetFrameSize', + 'uint16_t', + [], + is_const=True) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetName(std::string const name) [member function] + cls.add_method('SetName', + 'void', + [param('std::string const', 'name')], + is_virtual=True) + ## point-to-point-net-device.h: std::string ns3::PointToPointNetDevice::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetIfIndex(uint32_t const index) [member function] + cls.add_method('SetIfIndex', + 'void', + [param('uint32_t const', 'index')], + is_virtual=True) + ## point-to-point-net-device.h: uint32_t ns3::PointToPointNetDevice::GetIfIndex() const [member function] + cls.add_method('GetIfIndex', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: ns3::Ptr ns3::PointToPointNetDevice::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::Channel >', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: ns3::Address ns3::PointToPointNetDevice::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::SetMtu(uint16_t const mtu) [member function] + cls.add_method('SetMtu', + 'bool', + [param('uint16_t const', 'mtu')], + is_virtual=True) + ## point-to-point-net-device.h: uint16_t ns3::PointToPointNetDevice::GetMtu() const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::IsLinkUp() const [member function] + cls.add_method('IsLinkUp', + 'bool', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetLinkChangeCallback(ns3::Callback callback) [member function] + cls.add_method('SetLinkChangeCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: ns3::Address ns3::PointToPointNetDevice::GetBroadcast() const [member function] + cls.add_method('GetBroadcast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: ns3::Address ns3::PointToPointNetDevice::GetMulticast() const [member function] + cls.add_method('GetMulticast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: ns3::Address ns3::PointToPointNetDevice::MakeMulticastAddress(ns3::Ipv4Address multicastGroup) const [member function] + cls.add_method('MakeMulticastAddress', + 'ns3::Address', + [param('ns3::Ipv4Address', 'multicastGroup')], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::IsPointToPoint() const [member function] + cls.add_method('IsPointToPoint', + 'bool', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::Send(ns3::Ptr packet, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('Send', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::SendFrom(ns3::Ptr packet, ns3::Address const & source, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('SendFrom', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'source'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## point-to-point-net-device.h: ns3::Ptr ns3::PointToPointNetDevice::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::NeedsArp() const [member function] + cls.add_method('NeedsArp', + 'bool', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::empty, ns3::empty> cb) [member function] + cls.add_method('SetReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::empty, ns3::empty >', 'cb')], + is_virtual=True) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::SetPromiscReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> cb) [member function] + cls.add_method('SetPromiscReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'cb')], + is_virtual=True) + ## point-to-point-net-device.h: bool ns3::PointToPointNetDevice::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## point-to-point-net-device.h: void ns3::PointToPointNetDevice::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_simulator.py b/bindings/python/ns3_module_simulator.py new file mode 100644 index 000000000..679733f08 --- /dev/null +++ b/bindings/python/ns3_module_simulator.py @@ -0,0 +1,1484 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## event-id.h: ns3::EventId [class] + module.add_class('EventId') + ## event-impl.h: ns3::EventImpl [class] + module.add_class('EventImpl', allow_subclassing=True) + ## high-precision-128.h: ns3::HighPrecision [class] + module.add_class('HighPrecision') + ## simulator.h: ns3::Simulator [class] + module.add_class('Simulator', is_singleton=True) + ## nstime.h: ns3::TimeUnit<-1> [class] + module.add_class('TimeInvert') + ## nstime.h: ns3::TimeUnit<0> [class] + module.add_class('Scalar') + ## nstime.h: ns3::TimeUnit<1> [class] + module.add_class('Time') + ## nstime.h: ns3::TimeUnit<2> [class] + module.add_class('TimeSquare') + ## timer.h: ns3::Timer [class] + module.add_class('Timer') + ## timer.h: ns3::Timer::DestroyPolicy [enumeration] + module.add_enum('DestroyPolicy', ['CANCEL_ON_DESTROY', 'REMOVE_ON_DESTROY', 'CHECK_ON_DESTROY'], outer_class=root_module['ns3::Timer']) + ## timer.h: ns3::Timer::State [enumeration] + module.add_enum('State', ['RUNNING', 'EXPIRED', 'SUSPENDED'], outer_class=root_module['ns3::Timer']) + ## timer-impl.h: ns3::TimerImpl [class] + module.add_class('TimerImpl', allow_subclassing=True) + ## watchdog.h: ns3::Watchdog [class] + module.add_class('Watchdog') + ## scheduler.h: ns3::Scheduler [class] + module.add_class('Scheduler', parent=root_module['ns3::Object']) + ## scheduler.h: ns3::Scheduler::Event [struct] + module.add_class('Event', outer_class=root_module['ns3::Scheduler']) + ## scheduler.h: ns3::Scheduler::EventKey [struct] + module.add_class('EventKey', outer_class=root_module['ns3::Scheduler']) + ## simulator-impl.h: ns3::SimulatorImpl [class] + module.add_class('SimulatorImpl', parent=root_module['ns3::Object']) + ## synchronizer.h: ns3::Synchronizer [class] + module.add_class('Synchronizer', parent=root_module['ns3::Object']) + ## nstime.h: ns3::TimeChecker [class] + module.add_class('TimeChecker', parent=root_module['ns3::AttributeChecker']) + ## nstime.h: ns3::TimeValue [class] + module.add_class('TimeValue', parent=root_module['ns3::AttributeValue']) + ## wall-clock-synchronizer.h: ns3::WallClockSynchronizer [class] + module.add_class('WallClockSynchronizer', parent=root_module['ns3::Synchronizer']) + ## default-simulator-impl.h: ns3::DefaultSimulatorImpl [class] + module.add_class('DefaultSimulatorImpl', parent=root_module['ns3::SimulatorImpl']) + ## heap-scheduler.h: ns3::HeapScheduler [class] + module.add_class('HeapScheduler', parent=root_module['ns3::Scheduler']) + ## list-scheduler.h: ns3::ListScheduler [class] + module.add_class('ListScheduler', parent=root_module['ns3::Scheduler']) + ## map-scheduler.h: ns3::MapScheduler [class] + module.add_class('MapScheduler', parent=root_module['ns3::Scheduler']) + ## realtime-simulator-impl.h: ns3::RealtimeSimulatorImpl [class] + module.add_class('RealtimeSimulatorImpl', parent=root_module['ns3::SimulatorImpl']) + ## realtime-simulator-impl.h: ns3::RealtimeSimulatorImpl::SynchronizationMode [enumeration] + module.add_enum('SynchronizationMode', ['SYNC_BEST_EFFORT', 'SYNC_HARD_LIMIT'], outer_class=root_module['ns3::RealtimeSimulatorImpl']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + ## nstime.h: ns3::TimeStepPrecision::precision_t [enumeration] + module.add_enum('precision_t', ['S', 'MS', 'US', 'NS', 'PS', 'FS']) + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3EventId_methods(root_module, root_module['ns3::EventId']) + register_Ns3EventImpl_methods(root_module, root_module['ns3::EventImpl']) + register_Ns3HighPrecision_methods(root_module, root_module['ns3::HighPrecision']) + register_Ns3Simulator_methods(root_module, root_module['ns3::Simulator']) + register_Ns3TimeInvert_methods(root_module, root_module['ns3::TimeInvert']) + register_Ns3Scalar_methods(root_module, root_module['ns3::Scalar']) + register_Ns3Time_methods(root_module, root_module['ns3::Time']) + register_Ns3TimeSquare_methods(root_module, root_module['ns3::TimeSquare']) + register_Ns3Timer_methods(root_module, root_module['ns3::Timer']) + register_Ns3TimerImpl_methods(root_module, root_module['ns3::TimerImpl']) + register_Ns3Watchdog_methods(root_module, root_module['ns3::Watchdog']) + register_Ns3Scheduler_methods(root_module, root_module['ns3::Scheduler']) + register_Ns3SchedulerEvent_methods(root_module, root_module['ns3::Scheduler::Event']) + register_Ns3SchedulerEventKey_methods(root_module, root_module['ns3::Scheduler::EventKey']) + register_Ns3SimulatorImpl_methods(root_module, root_module['ns3::SimulatorImpl']) + register_Ns3Synchronizer_methods(root_module, root_module['ns3::Synchronizer']) + register_Ns3TimeChecker_methods(root_module, root_module['ns3::TimeChecker']) + register_Ns3TimeValue_methods(root_module, root_module['ns3::TimeValue']) + register_Ns3WallClockSynchronizer_methods(root_module, root_module['ns3::WallClockSynchronizer']) + register_Ns3DefaultSimulatorImpl_methods(root_module, root_module['ns3::DefaultSimulatorImpl']) + register_Ns3HeapScheduler_methods(root_module, root_module['ns3::HeapScheduler']) + register_Ns3ListScheduler_methods(root_module, root_module['ns3::ListScheduler']) + register_Ns3MapScheduler_methods(root_module, root_module['ns3::MapScheduler']) + register_Ns3RealtimeSimulatorImpl_methods(root_module, root_module['ns3::RealtimeSimulatorImpl']) + return + +def register_Ns3EventId_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_binary_comparison_operator('==') + ## event-id.h: ns3::EventId::EventId(ns3::EventId const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EventId const &', 'arg0')]) + ## event-id.h: ns3::EventId::EventId() [constructor] + cls.add_constructor([]) + ## event-id.h: ns3::EventId::EventId(ns3::Ptr const & impl, uint64_t ts, uint32_t uid) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::EventImpl > const &', 'impl'), param('uint64_t', 'ts'), param('uint32_t', 'uid')]) + ## event-id.h: void ns3::EventId::Cancel() [member function] + cls.add_method('Cancel', + 'void', + []) + ## event-id.h: uint64_t ns3::EventId::GetTs() const [member function] + cls.add_method('GetTs', + 'uint64_t', + [], + is_const=True) + ## event-id.h: uint32_t ns3::EventId::GetUid() const [member function] + cls.add_method('GetUid', + 'uint32_t', + [], + is_const=True) + ## event-id.h: bool ns3::EventId::IsExpired() const [member function] + cls.add_method('IsExpired', + 'bool', + [], + is_const=True) + ## event-id.h: bool ns3::EventId::IsRunning() const [member function] + cls.add_method('IsRunning', + 'bool', + [], + is_const=True) + ## event-id.h: ns3::EventImpl * ns3::EventId::PeekEventImpl() const [member function] + cls.add_method('PeekEventImpl', + 'ns3::EventImpl *', + [], + is_const=True) + return + +def register_Ns3EventImpl_methods(root_module, cls): + ## event-impl.h: ns3::EventImpl::EventImpl(ns3::EventImpl const & arg0) [copy constructor] + cls.add_constructor([param('ns3::EventImpl const &', 'arg0')]) + ## event-impl.h: ns3::EventImpl::EventImpl() [constructor] + cls.add_constructor([]) + ## event-impl.h: void ns3::EventImpl::Ref() const [member function] + cls.add_method('Ref', + 'void', + [], + is_const=True) + ## event-impl.h: void ns3::EventImpl::Unref() const [member function] + cls.add_method('Unref', + 'void', + [], + is_const=True) + ## event-impl.h: void ns3::EventImpl::Invoke() [member function] + cls.add_method('Invoke', + 'void', + []) + ## event-impl.h: void ns3::EventImpl::Cancel() [member function] + cls.add_method('Cancel', + 'void', + []) + ## event-impl.h: bool ns3::EventImpl::IsCancelled() [member function] + cls.add_method('IsCancelled', + 'bool', + []) + ## event-impl.h: void ns3::EventImpl::Notify() [member function] + cls.add_method('Notify', + 'void', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + return + +def register_Ns3HighPrecision_methods(root_module, cls): + ## high-precision-128.h: ns3::HighPrecision::HighPrecision(ns3::HighPrecision const & arg0) [copy constructor] + cls.add_constructor([param('ns3::HighPrecision const &', 'arg0')]) + ## high-precision-128.h: ns3::HighPrecision::HighPrecision() [constructor] + cls.add_constructor([]) + ## high-precision-128.h: ns3::HighPrecision::HighPrecision(int64_t value, bool dummy) [constructor] + cls.add_constructor([param('int64_t', 'value'), param('bool', 'dummy')]) + ## high-precision-128.h: ns3::HighPrecision::HighPrecision(double value) [constructor] + cls.add_constructor([param('double', 'value')]) + ## high-precision-128.h: static void ns3::HighPrecision::PrintStats() [member function] + cls.add_method('PrintStats', + 'void', + [], + is_static=True) + ## high-precision-128.h: int64_t ns3::HighPrecision::GetInteger() const [member function] + cls.add_method('GetInteger', + 'int64_t', + [], + is_const=True) + ## high-precision-128.h: double ns3::HighPrecision::GetDouble() const [member function] + cls.add_method('GetDouble', + 'double', + [], + is_const=True) + ## high-precision-128.h: bool ns3::HighPrecision::Add(ns3::HighPrecision const & o) [member function] + cls.add_method('Add', + 'bool', + [param('ns3::HighPrecision const &', 'o')]) + ## high-precision-128.h: bool ns3::HighPrecision::Sub(ns3::HighPrecision const & o) [member function] + cls.add_method('Sub', + 'bool', + [param('ns3::HighPrecision const &', 'o')]) + ## high-precision-128.h: bool ns3::HighPrecision::Mul(ns3::HighPrecision const & o) [member function] + cls.add_method('Mul', + 'bool', + [param('ns3::HighPrecision const &', 'o')]) + ## high-precision-128.h: bool ns3::HighPrecision::Div(ns3::HighPrecision const & o) [member function] + cls.add_method('Div', + 'bool', + [param('ns3::HighPrecision const &', 'o')]) + ## high-precision-128.h: int ns3::HighPrecision::Compare(ns3::HighPrecision const & o) const [member function] + cls.add_method('Compare', + 'int', + [param('ns3::HighPrecision const &', 'o')], + is_const=True) + ## high-precision-128.h: static ns3::HighPrecision ns3::HighPrecision::Zero() [member function] + cls.add_method('Zero', + 'ns3::HighPrecision', + [], + is_static=True) + return + +def register_Ns3Simulator_methods(root_module, cls): + ## simulator.h: ns3::Simulator::Simulator(ns3::Simulator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Simulator const &', 'arg0')]) + ## simulator.h: static void ns3::Simulator::SetImplementation(ns3::Ptr impl) [member function] + cls.add_method('SetImplementation', + 'void', + [param('ns3::Ptr< ns3::SimulatorImpl >', 'impl')], + is_static=True) + ## simulator.h: static ns3::Ptr ns3::Simulator::GetImplementation() [member function] + cls.add_method('GetImplementation', + 'ns3::Ptr< ns3::SimulatorImpl >', + [], + is_static=True) + ## simulator.h: static void ns3::Simulator::SetScheduler(ns3::Ptr scheduler) [member function] + cls.add_method('SetScheduler', + 'void', + [param('ns3::Ptr< ns3::Scheduler >', 'scheduler')], + is_static=True) + ## simulator.h: static void ns3::Simulator::EnableLogTo(char const * filename) [member function] + cls.add_method('EnableLogTo', + 'void', + [param('char const *', 'filename')], + is_static=True, deprecated=True) + ## simulator.h: static void ns3::Simulator::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_static=True) + ## simulator.h: static bool ns3::Simulator::IsFinished() [member function] + cls.add_method('IsFinished', + 'bool', + [], + is_static=True) + ## simulator.h: static ns3::Time ns3::Simulator::Next() [member function] + cls.add_method('Next', + 'ns3::Time', + [], + is_static=True) + ## simulator.h: static void ns3::Simulator::Run() [member function] + cls.add_method('Run', + 'void', + [], + is_static=True, unblock_threads=True) + ## simulator.h: static void ns3::Simulator::RunOneEvent() [member function] + cls.add_method('RunOneEvent', + 'void', + [], + is_static=True) + ## simulator.h: static void ns3::Simulator::Stop() [member function] + cls.add_method('Stop', + 'void', + [], + is_static=True) + ## simulator.h: static void ns3::Simulator::Stop(ns3::Time const & time) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'time')], + is_static=True) + ## simulator.h: static void ns3::Simulator::Remove(ns3::EventId const & id) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::EventId const &', 'id')], + is_static=True) + ## simulator.h: static void ns3::Simulator::Cancel(ns3::EventId const & id) [member function] + cls.add_method('Cancel', + 'void', + [param('ns3::EventId const &', 'id')], + is_static=True) + ## simulator.h: static bool ns3::Simulator::IsExpired(ns3::EventId const & id) [member function] + cls.add_method('IsExpired', + 'bool', + [param('ns3::EventId const &', 'id')], + is_static=True) + ## simulator.h: static ns3::Time ns3::Simulator::Now() [member function] + cls.add_method('Now', + 'ns3::Time', + [], + is_static=True) + ## simulator.h: static ns3::Time ns3::Simulator::GetDelayLeft(ns3::EventId const & id) [member function] + cls.add_method('GetDelayLeft', + 'ns3::Time', + [param('ns3::EventId const &', 'id')], + is_static=True) + ## simulator.h: static ns3::Time ns3::Simulator::GetMaximumSimulationTime() [member function] + cls.add_method('GetMaximumSimulationTime', + 'ns3::Time', + [], + is_static=True) + return + +def register_Ns3TimeInvert_methods(root_module, cls): + ## nstime.h: ns3::TimeUnit<-1>::TimeUnit() [constructor] + cls.add_constructor([]) + ## nstime.h: ns3::TimeUnit<-1>::TimeUnit(ns3::TimeUnit<-1> const & o) [copy constructor] + cls.add_constructor([param('ns3::TimeUnit< - 1 > const &', 'o')]) + ## nstime.h: ns3::TimeUnit<-1>::TimeUnit(ns3::HighPrecision data) [constructor] + cls.add_constructor([param('ns3::HighPrecision', 'data')]) + ## nstime.h: ns3::HighPrecision const & ns3::TimeUnit<-1>::GetHighPrecision() const [member function] + cls.add_method('GetHighPrecision', + 'ns3::HighPrecision const &', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<-1>::IsNegative() const [member function] + cls.add_method('IsNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<-1>::IsPositive() const [member function] + cls.add_method('IsPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<-1>::IsStrictlyNegative() const [member function] + cls.add_method('IsStrictlyNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<-1>::IsStrictlyPositive() const [member function] + cls.add_method('IsStrictlyPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<-1>::IsZero() const [member function] + cls.add_method('IsZero', + 'bool', + [], + is_const=True) + ## nstime.h: ns3::HighPrecision * ns3::TimeUnit<-1>::PeekHighPrecision() [member function] + cls.add_method('PeekHighPrecision', + 'ns3::HighPrecision *', + []) + return + +def register_Ns3Scalar_methods(root_module, cls): + cls.add_binary_numeric_operator('*', root_module['ns3::Time'], root_module['ns3::Scalar'], root_module['ns3::Time']) + cls.add_binary_numeric_operator('/', root_module['ns3::Time'], root_module['ns3::Time'], root_module['ns3::Scalar']) + cls.add_binary_numeric_operator('/', root_module['ns3::TimeInvert'], root_module['ns3::Scalar'], root_module['ns3::Time']) + ## nstime.h: ns3::TimeUnit<0>::TimeUnit(double scalar) [constructor] + cls.add_constructor([param('double', 'scalar')]) + ## nstime.h: ns3::TimeUnit<0>::TimeUnit() [constructor] + cls.add_constructor([]) + ## nstime.h: ns3::TimeUnit<0>::TimeUnit(ns3::TimeUnit<0> const & o) [copy constructor] + cls.add_constructor([param('ns3::TimeUnit< 0 > const &', 'o')]) + ## nstime.h: ns3::TimeUnit<0>::TimeUnit(ns3::HighPrecision data) [constructor] + cls.add_constructor([param('ns3::HighPrecision', 'data')]) + ## nstime.h: double ns3::TimeUnit<0>::GetDouble() const [member function] + cls.add_method('GetDouble', + 'double', + [], + is_const=True) + ## nstime.h: ns3::HighPrecision const & ns3::TimeUnit<0>::GetHighPrecision() const [member function] + cls.add_method('GetHighPrecision', + 'ns3::HighPrecision const &', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<0>::IsNegative() const [member function] + cls.add_method('IsNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<0>::IsPositive() const [member function] + cls.add_method('IsPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<0>::IsStrictlyNegative() const [member function] + cls.add_method('IsStrictlyNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<0>::IsStrictlyPositive() const [member function] + cls.add_method('IsStrictlyPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<0>::IsZero() const [member function] + cls.add_method('IsZero', + 'bool', + [], + is_const=True) + ## nstime.h: ns3::HighPrecision * ns3::TimeUnit<0>::PeekHighPrecision() [member function] + cls.add_method('PeekHighPrecision', + 'ns3::HighPrecision *', + []) + return + +def register_Ns3Time_methods(root_module, cls): + cls.add_binary_comparison_operator('!=') + cls.add_binary_numeric_operator('*', root_module['ns3::Time'], root_module['ns3::Scalar'], root_module['ns3::Time']) + cls.add_binary_numeric_operator('*', root_module['ns3::TimeSquare'], root_module['ns3::Time'], root_module['ns3::Time']) + cls.add_binary_numeric_operator('+', root_module['ns3::Time'], root_module['ns3::Time'], root_module['ns3::Time']) + cls.add_binary_numeric_operator('-', root_module['ns3::Time'], root_module['ns3::Time'], root_module['ns3::Time']) + cls.add_binary_numeric_operator('/', root_module['ns3::Time'], root_module['ns3::Time'], root_module['ns3::Scalar']) + cls.add_binary_numeric_operator('/', root_module['ns3::TimeInvert'], root_module['ns3::Scalar'], root_module['ns3::Time']) + cls.add_binary_numeric_operator('/', root_module['ns3::Scalar'], root_module['ns3::Time'], root_module['ns3::Time']) + cls.add_binary_numeric_operator('/', root_module['ns3::Time'], root_module['ns3::TimeSquare'], root_module['ns3::Time']) + cls.add_binary_comparison_operator('<') + cls.add_binary_comparison_operator('>') + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('<=') + cls.add_binary_comparison_operator('==') + cls.add_binary_comparison_operator('>=') + ## nstime.h: ns3::TimeUnit<1>::TimeUnit(std::string const & s) [constructor] + cls.add_constructor([param('std::string const &', 's')]) + ## nstime.h: ns3::TimeUnit<1>::TimeUnit() [constructor] + cls.add_constructor([]) + ## nstime.h: ns3::TimeUnit<1>::TimeUnit(ns3::TimeUnit<1> const & o) [copy constructor] + cls.add_constructor([param('ns3::TimeUnit< 1 > const &', 'o')]) + ## nstime.h: ns3::TimeUnit<1>::TimeUnit(ns3::HighPrecision data) [constructor] + cls.add_constructor([param('ns3::HighPrecision', 'data')]) + ## nstime.h: int64_t ns3::TimeUnit<1>::GetFemtoSeconds() const [member function] + cls.add_method('GetFemtoSeconds', + 'int64_t', + [], + is_const=True) + ## nstime.h: ns3::HighPrecision const & ns3::TimeUnit<1>::GetHighPrecision() const [member function] + cls.add_method('GetHighPrecision', + 'ns3::HighPrecision const &', + [], + is_const=True) + ## nstime.h: int64_t ns3::TimeUnit<1>::GetMicroSeconds() const [member function] + cls.add_method('GetMicroSeconds', + 'int64_t', + [], + is_const=True) + ## nstime.h: int64_t ns3::TimeUnit<1>::GetMilliSeconds() const [member function] + cls.add_method('GetMilliSeconds', + 'int64_t', + [], + is_const=True) + ## nstime.h: int64_t ns3::TimeUnit<1>::GetNanoSeconds() const [member function] + cls.add_method('GetNanoSeconds', + 'int64_t', + [], + is_const=True) + ## nstime.h: int64_t ns3::TimeUnit<1>::GetPicoSeconds() const [member function] + cls.add_method('GetPicoSeconds', + 'int64_t', + [], + is_const=True) + ## nstime.h: double ns3::TimeUnit<1>::GetSeconds() const [member function] + cls.add_method('GetSeconds', + 'double', + [], + is_const=True) + ## nstime.h: int64_t ns3::TimeUnit<1>::GetTimeStep() const [member function] + cls.add_method('GetTimeStep', + 'int64_t', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<1>::IsNegative() const [member function] + cls.add_method('IsNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<1>::IsPositive() const [member function] + cls.add_method('IsPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<1>::IsStrictlyNegative() const [member function] + cls.add_method('IsStrictlyNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<1>::IsStrictlyPositive() const [member function] + cls.add_method('IsStrictlyPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<1>::IsZero() const [member function] + cls.add_method('IsZero', + 'bool', + [], + is_const=True) + ## nstime.h: ns3::HighPrecision * ns3::TimeUnit<1>::PeekHighPrecision() [member function] + cls.add_method('PeekHighPrecision', + 'ns3::HighPrecision *', + []) + ## nstime.h: static uint64_t ns3::TimeUnit<1>::UnitsToTimestep(uint64_t unitValue, uint64_t unitFactor) [member function] + cls.add_method('UnitsToTimestep', + 'uint64_t', + [param('uint64_t', 'unitValue'), param('uint64_t', 'unitFactor')], + is_static=True) + return + +def register_Ns3TimeSquare_methods(root_module, cls): + cls.add_binary_numeric_operator('/', root_module['ns3::Time'], root_module['ns3::TimeSquare'], root_module['ns3::Time']) + ## nstime.h: ns3::TimeUnit<2>::TimeUnit() [constructor] + cls.add_constructor([]) + ## nstime.h: ns3::TimeUnit<2>::TimeUnit(ns3::TimeUnit<2> const & o) [copy constructor] + cls.add_constructor([param('ns3::TimeUnit< 2 > const &', 'o')]) + ## nstime.h: ns3::TimeUnit<2>::TimeUnit(ns3::HighPrecision data) [constructor] + cls.add_constructor([param('ns3::HighPrecision', 'data')]) + ## nstime.h: ns3::HighPrecision const & ns3::TimeUnit<2>::GetHighPrecision() const [member function] + cls.add_method('GetHighPrecision', + 'ns3::HighPrecision const &', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<2>::IsNegative() const [member function] + cls.add_method('IsNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<2>::IsPositive() const [member function] + cls.add_method('IsPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<2>::IsStrictlyNegative() const [member function] + cls.add_method('IsStrictlyNegative', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<2>::IsStrictlyPositive() const [member function] + cls.add_method('IsStrictlyPositive', + 'bool', + [], + is_const=True) + ## nstime.h: bool ns3::TimeUnit<2>::IsZero() const [member function] + cls.add_method('IsZero', + 'bool', + [], + is_const=True) + ## nstime.h: ns3::HighPrecision * ns3::TimeUnit<2>::PeekHighPrecision() [member function] + cls.add_method('PeekHighPrecision', + 'ns3::HighPrecision *', + []) + return + +def register_Ns3Timer_methods(root_module, cls): + ## timer.h: ns3::Timer::Timer(ns3::Timer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Timer const &', 'arg0')]) + ## timer.h: ns3::Timer::Timer() [constructor] + cls.add_constructor([]) + ## timer.h: ns3::Timer::Timer(ns3::Timer::DestroyPolicy destroyPolicy) [constructor] + cls.add_constructor([param('ns3::Timer::DestroyPolicy', 'destroyPolicy')]) + ## timer.h: void ns3::Timer::SetDelay(ns3::Time const & delay) [member function] + cls.add_method('SetDelay', + 'void', + [param('ns3::Time const &', 'delay')]) + ## timer.h: ns3::Time ns3::Timer::GetDelay() const [member function] + cls.add_method('GetDelay', + 'ns3::Time', + [], + is_const=True) + ## timer.h: ns3::Time ns3::Timer::GetDelayLeft() const [member function] + cls.add_method('GetDelayLeft', + 'ns3::Time', + [], + is_const=True) + ## timer.h: void ns3::Timer::Cancel() [member function] + cls.add_method('Cancel', + 'void', + []) + ## timer.h: void ns3::Timer::Remove() [member function] + cls.add_method('Remove', + 'void', + []) + ## timer.h: bool ns3::Timer::IsExpired() const [member function] + cls.add_method('IsExpired', + 'bool', + [], + is_const=True) + ## timer.h: bool ns3::Timer::IsRunning() const [member function] + cls.add_method('IsRunning', + 'bool', + [], + is_const=True) + ## timer.h: bool ns3::Timer::IsSuspended() const [member function] + cls.add_method('IsSuspended', + 'bool', + [], + is_const=True) + ## timer.h: ns3::Timer::State ns3::Timer::GetState() const [member function] + cls.add_method('GetState', + 'ns3::Timer::State', + [], + is_const=True) + ## timer.h: void ns3::Timer::Schedule() [member function] + cls.add_method('Schedule', + 'void', + []) + ## timer.h: void ns3::Timer::Schedule(ns3::Time delay) [member function] + cls.add_method('Schedule', + 'void', + [param('ns3::Time', 'delay')]) + ## timer.h: void ns3::Timer::Suspend() [member function] + cls.add_method('Suspend', + 'void', + []) + ## timer.h: void ns3::Timer::Resume() [member function] + cls.add_method('Resume', + 'void', + []) + return + +def register_Ns3TimerImpl_methods(root_module, cls): + ## timer-impl.h: ns3::TimerImpl::TimerImpl(ns3::TimerImpl const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TimerImpl const &', 'arg0')]) + ## timer-impl.h: ns3::TimerImpl::TimerImpl() [constructor] + cls.add_constructor([]) + ## timer-impl.h: ns3::EventId ns3::TimerImpl::Schedule(ns3::Time const & delay) [member function] + cls.add_method('Schedule', + 'ns3::EventId', + [param('ns3::Time const &', 'delay')], + is_pure_virtual=True, is_virtual=True) + ## timer-impl.h: void ns3::TimerImpl::Invoke() [member function] + cls.add_method('Invoke', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3Watchdog_methods(root_module, cls): + ## watchdog.h: ns3::Watchdog::Watchdog(ns3::Watchdog const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Watchdog const &', 'arg0')]) + ## watchdog.h: ns3::Watchdog::Watchdog() [constructor] + cls.add_constructor([]) + ## watchdog.h: void ns3::Watchdog::Ping(ns3::Time delay) [member function] + cls.add_method('Ping', + 'void', + [param('ns3::Time', 'delay')]) + return + +def register_Ns3Scheduler_methods(root_module, cls): + ## scheduler.h: ns3::Scheduler::Scheduler(ns3::Scheduler const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Scheduler const &', 'arg0')]) + ## scheduler.h: ns3::Scheduler::Scheduler() [constructor] + cls.add_constructor([]) + ## scheduler.h: static ns3::TypeId ns3::Scheduler::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## scheduler.h: void ns3::Scheduler::Insert(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Insert', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_pure_virtual=True, is_virtual=True) + ## scheduler.h: bool ns3::Scheduler::IsEmpty() const [member function] + cls.add_method('IsEmpty', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## scheduler.h: ns3::Scheduler::Event ns3::Scheduler::PeekNext() const [member function] + cls.add_method('PeekNext', + 'ns3::Scheduler::Event', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## scheduler.h: ns3::Scheduler::Event ns3::Scheduler::RemoveNext() [member function] + cls.add_method('RemoveNext', + 'ns3::Scheduler::Event', + [], + is_pure_virtual=True, is_virtual=True) + ## scheduler.h: void ns3::Scheduler::Remove(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3SchedulerEvent_methods(root_module, cls): + cls.add_binary_comparison_operator('<') + ## scheduler.h: ns3::Scheduler::Event::Event() [constructor] + cls.add_constructor([]) + ## scheduler.h: ns3::Scheduler::Event::Event(ns3::Scheduler::Event const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Scheduler::Event const &', 'arg0')]) + ## scheduler.h: ns3::Scheduler::Event::impl [variable] + cls.add_instance_attribute('impl', 'ns3::EventImpl *', is_const=False) + ## scheduler.h: ns3::Scheduler::Event::key [variable] + cls.add_instance_attribute('key', 'ns3::Scheduler::EventKey', is_const=False) + return + +def register_Ns3SchedulerEventKey_methods(root_module, cls): + cls.add_binary_comparison_operator('<') + ## scheduler.h: ns3::Scheduler::EventKey::EventKey() [constructor] + cls.add_constructor([]) + ## scheduler.h: ns3::Scheduler::EventKey::EventKey(ns3::Scheduler::EventKey const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Scheduler::EventKey const &', 'arg0')]) + ## scheduler.h: ns3::Scheduler::EventKey::m_ts [variable] + cls.add_instance_attribute('m_ts', 'uint64_t', is_const=False) + ## scheduler.h: ns3::Scheduler::EventKey::m_uid [variable] + cls.add_instance_attribute('m_uid', 'uint32_t', is_const=False) + return + +def register_Ns3SimulatorImpl_methods(root_module, cls): + ## simulator-impl.h: ns3::SimulatorImpl::SimulatorImpl(ns3::SimulatorImpl const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SimulatorImpl const &', 'arg0')]) + ## simulator-impl.h: ns3::SimulatorImpl::SimulatorImpl() [constructor] + cls.add_constructor([]) + ## simulator-impl.h: void ns3::SimulatorImpl::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: bool ns3::SimulatorImpl::IsFinished() const [member function] + cls.add_method('IsFinished', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: ns3::Time ns3::SimulatorImpl::Next() const [member function] + cls.add_method('Next', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: void ns3::SimulatorImpl::Stop() [member function] + cls.add_method('Stop', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: void ns3::SimulatorImpl::Stop(ns3::Time const & time) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'time')], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: ns3::EventId ns3::SimulatorImpl::Schedule(ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('Schedule', + 'ns3::EventId', + [param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: ns3::EventId ns3::SimulatorImpl::ScheduleNow(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleNow', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: ns3::EventId ns3::SimulatorImpl::ScheduleDestroy(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleDestroy', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: void ns3::SimulatorImpl::Remove(ns3::EventId const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::EventId const &', 'ev')], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: void ns3::SimulatorImpl::Cancel(ns3::EventId const & ev) [member function] + cls.add_method('Cancel', + 'void', + [param('ns3::EventId const &', 'ev')], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: bool ns3::SimulatorImpl::IsExpired(ns3::EventId const & ev) const [member function] + cls.add_method('IsExpired', + 'bool', + [param('ns3::EventId const &', 'ev')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: void ns3::SimulatorImpl::Run() [member function] + cls.add_method('Run', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: void ns3::SimulatorImpl::RunOneEvent() [member function] + cls.add_method('RunOneEvent', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: ns3::Time ns3::SimulatorImpl::Now() const [member function] + cls.add_method('Now', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: ns3::Time ns3::SimulatorImpl::GetDelayLeft(ns3::EventId const & id) const [member function] + cls.add_method('GetDelayLeft', + 'ns3::Time', + [param('ns3::EventId const &', 'id')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: ns3::Time ns3::SimulatorImpl::GetMaximumSimulationTime() const [member function] + cls.add_method('GetMaximumSimulationTime', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## simulator-impl.h: void ns3::SimulatorImpl::SetScheduler(ns3::Ptr scheduler) [member function] + cls.add_method('SetScheduler', + 'void', + [param('ns3::Ptr< ns3::Scheduler >', 'scheduler')], + is_pure_virtual=True, is_virtual=True) + ## simulator-impl.h: ns3::Ptr ns3::SimulatorImpl::GetScheduler() const [member function] + cls.add_method('GetScheduler', + 'ns3::Ptr< ns3::Scheduler >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3Synchronizer_methods(root_module, cls): + ## synchronizer.h: ns3::Synchronizer::Synchronizer(ns3::Synchronizer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Synchronizer const &', 'arg0')]) + ## synchronizer.h: static ns3::TypeId ns3::Synchronizer::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## synchronizer.h: ns3::Synchronizer::Synchronizer() [constructor] + cls.add_constructor([]) + ## synchronizer.h: bool ns3::Synchronizer::Realtime() [member function] + cls.add_method('Realtime', + 'bool', + []) + ## synchronizer.h: uint64_t ns3::Synchronizer::GetCurrentRealtime() [member function] + cls.add_method('GetCurrentRealtime', + 'uint64_t', + []) + ## synchronizer.h: void ns3::Synchronizer::SetOrigin(uint64_t ts) [member function] + cls.add_method('SetOrigin', + 'void', + [param('uint64_t', 'ts')]) + ## synchronizer.h: uint64_t ns3::Synchronizer::GetOrigin() [member function] + cls.add_method('GetOrigin', + 'uint64_t', + []) + ## synchronizer.h: int64_t ns3::Synchronizer::GetDrift(uint64_t ts) [member function] + cls.add_method('GetDrift', + 'int64_t', + [param('uint64_t', 'ts')]) + ## synchronizer.h: bool ns3::Synchronizer::Synchronize(uint64_t tsCurrent, uint64_t tsDelay) [member function] + cls.add_method('Synchronize', + 'bool', + [param('uint64_t', 'tsCurrent'), param('uint64_t', 'tsDelay')]) + ## synchronizer.h: void ns3::Synchronizer::Signal() [member function] + cls.add_method('Signal', + 'void', + []) + ## synchronizer.h: void ns3::Synchronizer::SetCondition(bool arg0) [member function] + cls.add_method('SetCondition', + 'void', + [param('bool', 'arg0')]) + ## synchronizer.h: void ns3::Synchronizer::EventStart() [member function] + cls.add_method('EventStart', + 'void', + []) + ## synchronizer.h: uint64_t ns3::Synchronizer::EventEnd() [member function] + cls.add_method('EventEnd', + 'uint64_t', + []) + ## synchronizer.h: void ns3::Synchronizer::DoSetOrigin(uint64_t ns) [member function] + cls.add_method('DoSetOrigin', + 'void', + [param('uint64_t', 'ns')], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: bool ns3::Synchronizer::DoRealtime() [member function] + cls.add_method('DoRealtime', + 'bool', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: uint64_t ns3::Synchronizer::DoGetCurrentRealtime() [member function] + cls.add_method('DoGetCurrentRealtime', + 'uint64_t', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: bool ns3::Synchronizer::DoSynchronize(uint64_t nsCurrent, uint64_t nsDelay) [member function] + cls.add_method('DoSynchronize', + 'bool', + [param('uint64_t', 'nsCurrent'), param('uint64_t', 'nsDelay')], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: void ns3::Synchronizer::DoSignal() [member function] + cls.add_method('DoSignal', + 'void', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: void ns3::Synchronizer::DoSetCondition(bool arg0) [member function] + cls.add_method('DoSetCondition', + 'void', + [param('bool', 'arg0')], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: int64_t ns3::Synchronizer::DoGetDrift(uint64_t ns) [member function] + cls.add_method('DoGetDrift', + 'int64_t', + [param('uint64_t', 'ns')], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: void ns3::Synchronizer::DoEventStart() [member function] + cls.add_method('DoEventStart', + 'void', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## synchronizer.h: uint64_t ns3::Synchronizer::DoEventEnd() [member function] + cls.add_method('DoEventEnd', + 'uint64_t', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + return + +def register_Ns3TimeChecker_methods(root_module, cls): + ## nstime.h: ns3::TimeChecker::TimeChecker(ns3::TimeChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TimeChecker const &', 'arg0')]) + ## nstime.h: ns3::TimeChecker::TimeChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3TimeValue_methods(root_module, cls): + ## nstime.h: ns3::TimeValue::TimeValue(ns3::TimeValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TimeValue const &', 'arg0')]) + ## nstime.h: ns3::TimeValue::TimeValue() [constructor] + cls.add_constructor([]) + ## nstime.h: ns3::TimeValue::TimeValue(ns3::Time const & value) [constructor] + cls.add_constructor([param('ns3::Time const &', 'value')]) + ## nstime.h: void ns3::TimeValue::Set(ns3::Time const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Time const &', 'value')]) + ## nstime.h: ns3::Time ns3::TimeValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Time', + [], + is_const=True) + ## nstime.h: ns3::Ptr ns3::TimeValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## nstime.h: std::string ns3::TimeValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## nstime.h: bool ns3::TimeValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3WallClockSynchronizer_methods(root_module, cls): + ## wall-clock-synchronizer.h: ns3::WallClockSynchronizer::US_PER_NS [variable] + cls.add_static_attribute('US_PER_NS', 'uint64_t const', is_const=True) + ## wall-clock-synchronizer.h: ns3::WallClockSynchronizer::US_PER_SEC [variable] + cls.add_static_attribute('US_PER_SEC', 'uint64_t const', is_const=True) + ## wall-clock-synchronizer.h: ns3::WallClockSynchronizer::NS_PER_SEC [variable] + cls.add_static_attribute('NS_PER_SEC', 'uint64_t const', is_const=True) + ## wall-clock-synchronizer.h: ns3::WallClockSynchronizer::WallClockSynchronizer(ns3::WallClockSynchronizer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WallClockSynchronizer const &', 'arg0')]) + ## wall-clock-synchronizer.h: ns3::WallClockSynchronizer::WallClockSynchronizer() [constructor] + cls.add_constructor([]) + ## wall-clock-synchronizer.h: bool ns3::WallClockSynchronizer::DoRealtime() [member function] + cls.add_method('DoRealtime', + 'bool', + [], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: uint64_t ns3::WallClockSynchronizer::DoGetCurrentRealtime() [member function] + cls.add_method('DoGetCurrentRealtime', + 'uint64_t', + [], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: void ns3::WallClockSynchronizer::DoSetOrigin(uint64_t ns) [member function] + cls.add_method('DoSetOrigin', + 'void', + [param('uint64_t', 'ns')], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: int64_t ns3::WallClockSynchronizer::DoGetDrift(uint64_t ns) [member function] + cls.add_method('DoGetDrift', + 'int64_t', + [param('uint64_t', 'ns')], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: bool ns3::WallClockSynchronizer::DoSynchronize(uint64_t nsCurrent, uint64_t nsDelay) [member function] + cls.add_method('DoSynchronize', + 'bool', + [param('uint64_t', 'nsCurrent'), param('uint64_t', 'nsDelay')], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: void ns3::WallClockSynchronizer::DoSignal() [member function] + cls.add_method('DoSignal', + 'void', + [], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: void ns3::WallClockSynchronizer::DoSetCondition(bool cond) [member function] + cls.add_method('DoSetCondition', + 'void', + [param('bool', 'cond')], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: void ns3::WallClockSynchronizer::DoEventStart() [member function] + cls.add_method('DoEventStart', + 'void', + [], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: uint64_t ns3::WallClockSynchronizer::DoEventEnd() [member function] + cls.add_method('DoEventEnd', + 'uint64_t', + [], + visibility='protected', is_virtual=True) + ## wall-clock-synchronizer.h: bool ns3::WallClockSynchronizer::SpinWait(uint64_t arg0) [member function] + cls.add_method('SpinWait', + 'bool', + [param('uint64_t', 'arg0')], + visibility='protected') + ## wall-clock-synchronizer.h: bool ns3::WallClockSynchronizer::SleepWait(uint64_t arg0) [member function] + cls.add_method('SleepWait', + 'bool', + [param('uint64_t', 'arg0')], + visibility='protected') + ## wall-clock-synchronizer.h: uint64_t ns3::WallClockSynchronizer::DriftCorrect(uint64_t nsNow, uint64_t nsDelay) [member function] + cls.add_method('DriftCorrect', + 'uint64_t', + [param('uint64_t', 'nsNow'), param('uint64_t', 'nsDelay')], + visibility='protected') + ## wall-clock-synchronizer.h: uint64_t ns3::WallClockSynchronizer::GetRealtime() [member function] + cls.add_method('GetRealtime', + 'uint64_t', + [], + visibility='protected') + ## wall-clock-synchronizer.h: uint64_t ns3::WallClockSynchronizer::GetNormalizedRealtime() [member function] + cls.add_method('GetNormalizedRealtime', + 'uint64_t', + [], + visibility='protected') + ## wall-clock-synchronizer.h: void ns3::WallClockSynchronizer::NsToTimeval(int64_t ns, timeval * tv) [member function] + cls.add_method('NsToTimeval', + 'void', + [param('int64_t', 'ns'), param('timeval *', 'tv')], + visibility='protected') + ## wall-clock-synchronizer.h: uint64_t ns3::WallClockSynchronizer::TimevalToNs(timeval * tv) [member function] + cls.add_method('TimevalToNs', + 'uint64_t', + [param('timeval *', 'tv')], + visibility='protected') + ## wall-clock-synchronizer.h: void ns3::WallClockSynchronizer::TimevalAdd(timeval * tv1, timeval * tv2, timeval * result) [member function] + cls.add_method('TimevalAdd', + 'void', + [param('timeval *', 'tv1'), param('timeval *', 'tv2'), param('timeval *', 'result')], + visibility='protected') + return + +def register_Ns3DefaultSimulatorImpl_methods(root_module, cls): + ## default-simulator-impl.h: ns3::DefaultSimulatorImpl::DefaultSimulatorImpl(ns3::DefaultSimulatorImpl const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DefaultSimulatorImpl const &', 'arg0')]) + ## default-simulator-impl.h: static ns3::TypeId ns3::DefaultSimulatorImpl::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## default-simulator-impl.h: ns3::DefaultSimulatorImpl::DefaultSimulatorImpl() [constructor] + cls.add_constructor([]) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_virtual=True) + ## default-simulator-impl.h: bool ns3::DefaultSimulatorImpl::IsFinished() const [member function] + cls.add_method('IsFinished', + 'bool', + [], + is_const=True, is_virtual=True) + ## default-simulator-impl.h: ns3::Time ns3::DefaultSimulatorImpl::Next() const [member function] + cls.add_method('Next', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::Stop() [member function] + cls.add_method('Stop', + 'void', + [], + is_virtual=True) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::Stop(ns3::Time const & time) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'time')], + is_virtual=True) + ## default-simulator-impl.h: ns3::EventId ns3::DefaultSimulatorImpl::Schedule(ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('Schedule', + 'ns3::EventId', + [param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## default-simulator-impl.h: ns3::EventId ns3::DefaultSimulatorImpl::ScheduleNow(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleNow', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## default-simulator-impl.h: ns3::EventId ns3::DefaultSimulatorImpl::ScheduleDestroy(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleDestroy', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::Remove(ns3::EventId const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::Cancel(ns3::EventId const & ev) [member function] + cls.add_method('Cancel', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## default-simulator-impl.h: bool ns3::DefaultSimulatorImpl::IsExpired(ns3::EventId const & ev) const [member function] + cls.add_method('IsExpired', + 'bool', + [param('ns3::EventId const &', 'ev')], + is_const=True, is_virtual=True) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::Run() [member function] + cls.add_method('Run', + 'void', + [], + is_virtual=True) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::RunOneEvent() [member function] + cls.add_method('RunOneEvent', + 'void', + [], + is_virtual=True) + ## default-simulator-impl.h: ns3::Time ns3::DefaultSimulatorImpl::Now() const [member function] + cls.add_method('Now', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## default-simulator-impl.h: ns3::Time ns3::DefaultSimulatorImpl::GetDelayLeft(ns3::EventId const & id) const [member function] + cls.add_method('GetDelayLeft', + 'ns3::Time', + [param('ns3::EventId const &', 'id')], + is_const=True, is_virtual=True) + ## default-simulator-impl.h: ns3::Time ns3::DefaultSimulatorImpl::GetMaximumSimulationTime() const [member function] + cls.add_method('GetMaximumSimulationTime', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## default-simulator-impl.h: void ns3::DefaultSimulatorImpl::SetScheduler(ns3::Ptr scheduler) [member function] + cls.add_method('SetScheduler', + 'void', + [param('ns3::Ptr< ns3::Scheduler >', 'scheduler')], + is_virtual=True) + ## default-simulator-impl.h: ns3::Ptr ns3::DefaultSimulatorImpl::GetScheduler() const [member function] + cls.add_method('GetScheduler', + 'ns3::Ptr< ns3::Scheduler >', + [], + is_const=True, is_virtual=True) + return + +def register_Ns3HeapScheduler_methods(root_module, cls): + ## heap-scheduler.h: ns3::HeapScheduler::HeapScheduler(ns3::HeapScheduler const & arg0) [copy constructor] + cls.add_constructor([param('ns3::HeapScheduler const &', 'arg0')]) + ## heap-scheduler.h: ns3::HeapScheduler::HeapScheduler() [constructor] + cls.add_constructor([]) + ## heap-scheduler.h: void ns3::HeapScheduler::Insert(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Insert', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_virtual=True) + ## heap-scheduler.h: bool ns3::HeapScheduler::IsEmpty() const [member function] + cls.add_method('IsEmpty', + 'bool', + [], + is_const=True, is_virtual=True) + ## heap-scheduler.h: ns3::Scheduler::Event ns3::HeapScheduler::PeekNext() const [member function] + cls.add_method('PeekNext', + 'ns3::Scheduler::Event', + [], + is_const=True, is_virtual=True) + ## heap-scheduler.h: ns3::Scheduler::Event ns3::HeapScheduler::RemoveNext() [member function] + cls.add_method('RemoveNext', + 'ns3::Scheduler::Event', + [], + is_virtual=True) + ## heap-scheduler.h: void ns3::HeapScheduler::Remove(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_virtual=True) + return + +def register_Ns3ListScheduler_methods(root_module, cls): + ## list-scheduler.h: ns3::ListScheduler::ListScheduler(ns3::ListScheduler const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ListScheduler const &', 'arg0')]) + ## list-scheduler.h: ns3::ListScheduler::ListScheduler() [constructor] + cls.add_constructor([]) + ## list-scheduler.h: void ns3::ListScheduler::Insert(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Insert', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_virtual=True) + ## list-scheduler.h: bool ns3::ListScheduler::IsEmpty() const [member function] + cls.add_method('IsEmpty', + 'bool', + [], + is_const=True, is_virtual=True) + ## list-scheduler.h: ns3::Scheduler::Event ns3::ListScheduler::PeekNext() const [member function] + cls.add_method('PeekNext', + 'ns3::Scheduler::Event', + [], + is_const=True, is_virtual=True) + ## list-scheduler.h: ns3::Scheduler::Event ns3::ListScheduler::RemoveNext() [member function] + cls.add_method('RemoveNext', + 'ns3::Scheduler::Event', + [], + is_virtual=True) + ## list-scheduler.h: void ns3::ListScheduler::Remove(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_virtual=True) + return + +def register_Ns3MapScheduler_methods(root_module, cls): + ## map-scheduler.h: ns3::MapScheduler::MapScheduler(ns3::MapScheduler const & arg0) [copy constructor] + cls.add_constructor([param('ns3::MapScheduler const &', 'arg0')]) + ## map-scheduler.h: ns3::MapScheduler::MapScheduler() [constructor] + cls.add_constructor([]) + ## map-scheduler.h: void ns3::MapScheduler::Insert(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Insert', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_virtual=True) + ## map-scheduler.h: bool ns3::MapScheduler::IsEmpty() const [member function] + cls.add_method('IsEmpty', + 'bool', + [], + is_const=True, is_virtual=True) + ## map-scheduler.h: ns3::Scheduler::Event ns3::MapScheduler::PeekNext() const [member function] + cls.add_method('PeekNext', + 'ns3::Scheduler::Event', + [], + is_const=True, is_virtual=True) + ## map-scheduler.h: ns3::Scheduler::Event ns3::MapScheduler::RemoveNext() [member function] + cls.add_method('RemoveNext', + 'ns3::Scheduler::Event', + [], + is_virtual=True) + ## map-scheduler.h: void ns3::MapScheduler::Remove(ns3::Scheduler::Event const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::Scheduler::Event const &', 'ev')], + is_virtual=True) + return + +def register_Ns3RealtimeSimulatorImpl_methods(root_module, cls): + ## realtime-simulator-impl.h: ns3::RealtimeSimulatorImpl::RealtimeSimulatorImpl(ns3::RealtimeSimulatorImpl const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RealtimeSimulatorImpl const &', 'arg0')]) + ## realtime-simulator-impl.h: static ns3::TypeId ns3::RealtimeSimulatorImpl::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## realtime-simulator-impl.h: ns3::RealtimeSimulatorImpl::RealtimeSimulatorImpl() [constructor] + cls.add_constructor([]) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::Destroy() [member function] + cls.add_method('Destroy', + 'void', + [], + is_virtual=True) + ## realtime-simulator-impl.h: bool ns3::RealtimeSimulatorImpl::IsFinished() const [member function] + cls.add_method('IsFinished', + 'bool', + [], + is_const=True, is_virtual=True) + ## realtime-simulator-impl.h: ns3::Time ns3::RealtimeSimulatorImpl::Next() const [member function] + cls.add_method('Next', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::Stop() [member function] + cls.add_method('Stop', + 'void', + [], + is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::Stop(ns3::Time const & time) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'time')], + is_virtual=True) + ## realtime-simulator-impl.h: ns3::EventId ns3::RealtimeSimulatorImpl::Schedule(ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('Schedule', + 'ns3::EventId', + [param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## realtime-simulator-impl.h: ns3::EventId ns3::RealtimeSimulatorImpl::ScheduleNow(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleNow', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## realtime-simulator-impl.h: ns3::EventId ns3::RealtimeSimulatorImpl::ScheduleDestroy(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleDestroy', + 'ns3::EventId', + [param('ns3::EventImpl *', 'event')], + is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::Remove(ns3::EventId const & ev) [member function] + cls.add_method('Remove', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::Cancel(ns3::EventId const & ev) [member function] + cls.add_method('Cancel', + 'void', + [param('ns3::EventId const &', 'ev')], + is_virtual=True) + ## realtime-simulator-impl.h: bool ns3::RealtimeSimulatorImpl::IsExpired(ns3::EventId const & ev) const [member function] + cls.add_method('IsExpired', + 'bool', + [param('ns3::EventId const &', 'ev')], + is_const=True, is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::Run() [member function] + cls.add_method('Run', + 'void', + [], + is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::RunOneEvent() [member function] + cls.add_method('RunOneEvent', + 'void', + [], + is_virtual=True) + ## realtime-simulator-impl.h: ns3::Time ns3::RealtimeSimulatorImpl::Now() const [member function] + cls.add_method('Now', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## realtime-simulator-impl.h: ns3::Time ns3::RealtimeSimulatorImpl::GetDelayLeft(ns3::EventId const & id) const [member function] + cls.add_method('GetDelayLeft', + 'ns3::Time', + [param('ns3::EventId const &', 'id')], + is_const=True, is_virtual=True) + ## realtime-simulator-impl.h: ns3::Time ns3::RealtimeSimulatorImpl::GetMaximumSimulationTime() const [member function] + cls.add_method('GetMaximumSimulationTime', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::SetScheduler(ns3::Ptr scheduler) [member function] + cls.add_method('SetScheduler', + 'void', + [param('ns3::Ptr< ns3::Scheduler >', 'scheduler')], + is_virtual=True) + ## realtime-simulator-impl.h: ns3::Ptr ns3::RealtimeSimulatorImpl::GetScheduler() const [member function] + cls.add_method('GetScheduler', + 'ns3::Ptr< ns3::Scheduler >', + [], + is_const=True, is_virtual=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtime(ns3::Time const & time, ns3::EventImpl * event) [member function] + cls.add_method('ScheduleRealtime', + 'void', + [param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')]) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeNow(ns3::EventImpl * event) [member function] + cls.add_method('ScheduleRealtimeNow', + 'void', + [param('ns3::EventImpl *', 'event')]) + ## realtime-simulator-impl.h: ns3::Time ns3::RealtimeSimulatorImpl::RealtimeNow() const [member function] + cls.add_method('RealtimeNow', + 'ns3::Time', + [], + is_const=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::SetSynchronizationMode(ns3::RealtimeSimulatorImpl::SynchronizationMode mode) [member function] + cls.add_method('SetSynchronizationMode', + 'void', + [param('ns3::RealtimeSimulatorImpl::SynchronizationMode', 'mode')]) + ## realtime-simulator-impl.h: ns3::RealtimeSimulatorImpl::SynchronizationMode ns3::RealtimeSimulatorImpl::GetSynchronizationMode() const [member function] + cls.add_method('GetSynchronizationMode', + 'ns3::RealtimeSimulatorImpl::SynchronizationMode', + [], + is_const=True) + ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::SetHardLimit(ns3::Time limit) [member function] + cls.add_method('SetHardLimit', + 'void', + [param('ns3::Time', 'limit')]) + ## realtime-simulator-impl.h: ns3::Time ns3::RealtimeSimulatorImpl::GetHardLimit() const [member function] + cls.add_method('GetHardLimit', + 'ns3::Time', + [], + is_const=True) + return + +def register_functions(root_module): + module = root_module + ## high-precision.h: extern ns3::HighPrecision ns3::Max(ns3::HighPrecision const & a, ns3::HighPrecision const & b) [free function] + module.add_function('Max', + 'ns3::HighPrecision', + [param('ns3::HighPrecision const &', 'a'), param('ns3::HighPrecision const &', 'b')]) + ## nstime.h: extern ns3::Time ns3::FemtoSeconds(uint64_t fs) [free function] + module.add_function('FemtoSeconds', + 'ns3::Time', + [param('uint64_t', 'fs')]) + ## nstime.h: extern ns3::Time ns3::MicroSeconds(uint64_t us) [free function] + module.add_function('MicroSeconds', + 'ns3::Time', + [param('uint64_t', 'us')]) + ## simulator.h: extern ns3::Time ns3::Now() [free function] + module.add_function('Now', + 'ns3::Time', + []) + ## nstime.h: extern ns3::Time ns3::MilliSeconds(uint64_t ms) [free function] + module.add_function('MilliSeconds', + 'ns3::Time', + [param('uint64_t', 'ms')]) + ## nstime.h: extern ns3::Time ns3::NanoSeconds(uint64_t ns) [free function] + module.add_function('NanoSeconds', + 'ns3::Time', + [param('uint64_t', 'ns')]) + ## high-precision.h: extern ns3::HighPrecision ns3::Abs(ns3::HighPrecision const & value) [free function] + module.add_function('Abs', + 'ns3::HighPrecision', + [param('ns3::HighPrecision const &', 'value')]) + ## nstime.h: extern ns3::Ptr ns3::MakeTimeChecker() [free function] + module.add_function('MakeTimeChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## nstime.h: extern ns3::Time ns3::Seconds(double seconds) [free function] + module.add_function('Seconds', + 'ns3::Time', + [param('double', 'seconds')]) + ## make-event.h: extern ns3::EventImpl * ns3::MakeEvent(void (*)( ) * f) [free function] + module.add_function('MakeEvent', + 'ns3::EventImpl *', + [param('void ( * ) ( ) *', 'f')]) + ## nstime.h: extern ns3::Time ns3::PicoSeconds(uint64_t ps) [free function] + module.add_function('PicoSeconds', + 'ns3::Time', + [param('uint64_t', 'ps')]) + ## high-precision.h: extern ns3::HighPrecision ns3::Min(ns3::HighPrecision const & a, ns3::HighPrecision const & b) [free function] + module.add_function('Min', + 'ns3::HighPrecision', + [param('ns3::HighPrecision const &', 'a'), param('ns3::HighPrecision const &', 'b')]) + ## nstime.h: extern ns3::Time ns3::TimeStep(uint64_t ts) [free function] + module.add_function('TimeStep', + 'ns3::Time', + [param('uint64_t', 'ts')]) + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + ## nstime.h: extern void ns3::TimeStepPrecision::Set(ns3::TimeStepPrecision::precision_t precision) [free function] + module.add_function('Set', + 'void', + [param('ns3::TimeStepPrecision::precision_t', 'precision')]) + ## nstime.h: extern ns3::TimeStepPrecision::precision_t ns3::TimeStepPrecision::Get() [free function] + module.add_function('Get', + 'ns3::TimeStepPrecision::precision_t', + []) + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_stats.py b/bindings/python/ns3_module_stats.py new file mode 100644 index 000000000..21503c2a0 --- /dev/null +++ b/bindings/python/ns3_module_stats.py @@ -0,0 +1,437 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## data-output-interface.h: ns3::DataOutputCallback [class] + module.add_class('DataOutputCallback', allow_subclassing=True) + ## data-calculator.h: ns3::DataCalculator [class] + module.add_class('DataCalculator', parent=root_module['ns3::Object']) + ## data-collector.h: ns3::DataCollector [class] + module.add_class('DataCollector', parent=root_module['ns3::Object']) + ## data-output-interface.h: ns3::DataOutputInterface [class] + module.add_class('DataOutputInterface', parent=root_module['ns3::Object']) + ## basic-data-calculators.h: ns3::MinMaxAvgTotalCalculator [class] + module.add_class('MinMaxAvgTotalCalculator', template_parameters=['unsigned int'], parent=root_module['ns3::DataCalculator']) + ## omnet-data-output.h: ns3::OmnetDataOutput [class] + module.add_class('OmnetDataOutput', parent=root_module['ns3::DataOutputInterface']) + ## packet-data-calculators.h: ns3::PacketSizeMinMaxAvgTotalCalculator [class] + module.add_class('PacketSizeMinMaxAvgTotalCalculator', parent=root_module['ns3::MinMaxAvgTotalCalculator< unsigned int >']) + ## sqlite-data-output.h: ns3::SqliteDataOutput [class] + module.add_class('SqliteDataOutput', parent=root_module['ns3::DataOutputInterface']) + ## time-data-calculators.h: ns3::TimeMinMaxAvgTotalCalculator [class] + module.add_class('TimeMinMaxAvgTotalCalculator', parent=root_module['ns3::DataCalculator']) + ## basic-data-calculators.h: ns3::CounterCalculator [class] + module.add_class('CounterCalculator', template_parameters=['unsigned int'], parent=root_module['ns3::DataCalculator']) + ## packet-data-calculators.h: ns3::PacketCounterCalculator [class] + module.add_class('PacketCounterCalculator', parent=root_module['ns3::CounterCalculator< unsigned int >']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3DataOutputCallback_methods(root_module, root_module['ns3::DataOutputCallback']) + register_Ns3DataCalculator_methods(root_module, root_module['ns3::DataCalculator']) + register_Ns3DataCollector_methods(root_module, root_module['ns3::DataCollector']) + register_Ns3DataOutputInterface_methods(root_module, root_module['ns3::DataOutputInterface']) + register_Ns3MinMaxAvgTotalCalculator__Unsigned_int_methods(root_module, root_module['ns3::MinMaxAvgTotalCalculator< unsigned int >']) + register_Ns3OmnetDataOutput_methods(root_module, root_module['ns3::OmnetDataOutput']) + register_Ns3PacketSizeMinMaxAvgTotalCalculator_methods(root_module, root_module['ns3::PacketSizeMinMaxAvgTotalCalculator']) + register_Ns3SqliteDataOutput_methods(root_module, root_module['ns3::SqliteDataOutput']) + register_Ns3TimeMinMaxAvgTotalCalculator_methods(root_module, root_module['ns3::TimeMinMaxAvgTotalCalculator']) + register_Ns3CounterCalculator__Unsigned_int_methods(root_module, root_module['ns3::CounterCalculator< unsigned int >']) + register_Ns3PacketCounterCalculator_methods(root_module, root_module['ns3::PacketCounterCalculator']) + return + +def register_Ns3DataOutputCallback_methods(root_module, cls): + ## data-output-interface.h: ns3::DataOutputCallback::DataOutputCallback(ns3::DataOutputCallback const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DataOutputCallback const &', 'arg0')]) + ## data-output-interface.h: ns3::DataOutputCallback::DataOutputCallback() [constructor] + cls.add_constructor([]) + ## data-output-interface.h: void ns3::DataOutputCallback::OutputSingleton(std::string key, std::string variable, int val) [member function] + cls.add_method('OutputSingleton', + 'void', + [param('std::string', 'key'), param('std::string', 'variable'), param('int', 'val')], + is_pure_virtual=True, is_virtual=True) + ## data-output-interface.h: void ns3::DataOutputCallback::OutputSingleton(std::string key, std::string variable, uint32_t val) [member function] + cls.add_method('OutputSingleton', + 'void', + [param('std::string', 'key'), param('std::string', 'variable'), param('uint32_t', 'val')], + is_pure_virtual=True, is_virtual=True) + ## data-output-interface.h: void ns3::DataOutputCallback::OutputSingleton(std::string key, std::string variable, double val) [member function] + cls.add_method('OutputSingleton', + 'void', + [param('std::string', 'key'), param('std::string', 'variable'), param('double', 'val')], + is_pure_virtual=True, is_virtual=True) + ## data-output-interface.h: void ns3::DataOutputCallback::OutputSingleton(std::string key, std::string variable, std::string val) [member function] + cls.add_method('OutputSingleton', + 'void', + [param('std::string', 'key'), param('std::string', 'variable'), param('std::string', 'val')], + is_pure_virtual=True, is_virtual=True) + ## data-output-interface.h: void ns3::DataOutputCallback::OutputSingleton(std::string key, std::string variable, ns3::Time val) [member function] + cls.add_method('OutputSingleton', + 'void', + [param('std::string', 'key'), param('std::string', 'variable'), param('ns3::Time', 'val')], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3DataCalculator_methods(root_module, cls): + ## data-calculator.h: ns3::DataCalculator::DataCalculator(ns3::DataCalculator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DataCalculator const &', 'arg0')]) + ## data-calculator.h: ns3::DataCalculator::DataCalculator() [constructor] + cls.add_constructor([]) + ## data-calculator.h: bool ns3::DataCalculator::GetEnabled() const [member function] + cls.add_method('GetEnabled', + 'bool', + [], + is_const=True) + ## data-calculator.h: void ns3::DataCalculator::Enable() [member function] + cls.add_method('Enable', + 'void', + []) + ## data-calculator.h: void ns3::DataCalculator::Disable() [member function] + cls.add_method('Disable', + 'void', + []) + ## data-calculator.h: void ns3::DataCalculator::SetKey(std::string const key) [member function] + cls.add_method('SetKey', + 'void', + [param('std::string const', 'key')]) + ## data-calculator.h: std::string ns3::DataCalculator::GetKey() const [member function] + cls.add_method('GetKey', + 'std::string', + [], + is_const=True) + ## data-calculator.h: void ns3::DataCalculator::Start(ns3::Time const & startTime) [member function] + cls.add_method('Start', + 'void', + [param('ns3::Time const &', 'startTime')], + is_virtual=True) + ## data-calculator.h: void ns3::DataCalculator::Stop(ns3::Time const & stopTime) [member function] + cls.add_method('Stop', + 'void', + [param('ns3::Time const &', 'stopTime')], + is_virtual=True) + ## data-calculator.h: void ns3::DataCalculator::Output(ns3::DataOutputCallback & callback) const [member function] + cls.add_method('Output', + 'void', + [param('ns3::DataOutputCallback &', 'callback')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## data-calculator.h: void ns3::DataCalculator::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3DataCollector_methods(root_module, cls): + ## data-collector.h: ns3::DataCollector::DataCollector(ns3::DataCollector const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DataCollector const &', 'arg0')]) + ## data-collector.h: ns3::DataCollector::DataCollector() [constructor] + cls.add_constructor([]) + ## data-collector.h: void ns3::DataCollector::DescribeRun(std::string experiment, std::string strategy, std::string input, std::string runID, std::string description="") [member function] + cls.add_method('DescribeRun', + 'void', + [param('std::string', 'experiment'), param('std::string', 'strategy'), param('std::string', 'input'), param('std::string', 'runID'), param('std::string', 'description', default_value='""')]) + ## data-collector.h: std::string ns3::DataCollector::GetExperimentLabel() const [member function] + cls.add_method('GetExperimentLabel', + 'std::string', + [], + is_const=True) + ## data-collector.h: std::string ns3::DataCollector::GetStrategyLabel() const [member function] + cls.add_method('GetStrategyLabel', + 'std::string', + [], + is_const=True) + ## data-collector.h: std::string ns3::DataCollector::GetInputLabel() const [member function] + cls.add_method('GetInputLabel', + 'std::string', + [], + is_const=True) + ## data-collector.h: std::string ns3::DataCollector::GetRunLabel() const [member function] + cls.add_method('GetRunLabel', + 'std::string', + [], + is_const=True) + ## data-collector.h: std::string ns3::DataCollector::GetDescription() const [member function] + cls.add_method('GetDescription', + 'std::string', + [], + is_const=True) + ## data-collector.h: void ns3::DataCollector::AddMetadata(std::string key, std::string value) [member function] + cls.add_method('AddMetadata', + 'void', + [param('std::string', 'key'), param('std::string', 'value')]) + ## data-collector.h: void ns3::DataCollector::AddMetadata(std::string key, double value) [member function] + cls.add_method('AddMetadata', + 'void', + [param('std::string', 'key'), param('double', 'value')]) + ## data-collector.h: void ns3::DataCollector::AddMetadata(std::string key, uint32_t value) [member function] + cls.add_method('AddMetadata', + 'void', + [param('std::string', 'key'), param('uint32_t', 'value')]) + ## data-collector.h: std::_List_iterator, std::allocator >, std::basic_string, std::allocator > > > ns3::DataCollector::MetadataBegin() [member function] + cls.add_method('MetadataBegin', + 'std::_List_iterator< std::pair< std::basic_string< char, std::char_traits< char >, std::allocator< char > >, std::basic_string< char, std::char_traits< char >, std::allocator< char > > > >', + []) + ## data-collector.h: std::_List_iterator, std::allocator >, std::basic_string, std::allocator > > > ns3::DataCollector::MetadataEnd() [member function] + cls.add_method('MetadataEnd', + 'std::_List_iterator< std::pair< std::basic_string< char, std::char_traits< char >, std::allocator< char > >, std::basic_string< char, std::char_traits< char >, std::allocator< char > > > >', + []) + ## data-collector.h: void ns3::DataCollector::AddDataCalculator(ns3::Ptr datac) [member function] + cls.add_method('AddDataCalculator', + 'void', + [param('ns3::Ptr< ns3::DataCalculator >', 'datac')]) + ## data-collector.h: std::_List_iterator > ns3::DataCollector::DataCalculatorBegin() [member function] + cls.add_method('DataCalculatorBegin', + 'std::_List_iterator< ns3::Ptr< ns3::DataCalculator > >', + []) + ## data-collector.h: std::_List_iterator > ns3::DataCollector::DataCalculatorEnd() [member function] + cls.add_method('DataCalculatorEnd', + 'std::_List_iterator< ns3::Ptr< ns3::DataCalculator > >', + []) + ## data-collector.h: void ns3::DataCollector::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3DataOutputInterface_methods(root_module, cls): + ## data-output-interface.h: ns3::DataOutputInterface::DataOutputInterface(ns3::DataOutputInterface const & arg0) [copy constructor] + cls.add_constructor([param('ns3::DataOutputInterface const &', 'arg0')]) + ## data-output-interface.h: ns3::DataOutputInterface::DataOutputInterface() [constructor] + cls.add_constructor([]) + ## data-output-interface.h: void ns3::DataOutputInterface::Output(ns3::DataCollector & dc) [member function] + cls.add_method('Output', + 'void', + [param('ns3::DataCollector &', 'dc')], + is_pure_virtual=True, is_virtual=True) + ## data-output-interface.h: void ns3::DataOutputInterface::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3MinMaxAvgTotalCalculator__Unsigned_int_methods(root_module, cls): + ## basic-data-calculators.h: ns3::MinMaxAvgTotalCalculator::MinMaxAvgTotalCalculator(ns3::MinMaxAvgTotalCalculator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::MinMaxAvgTotalCalculator< unsigned int > const &', 'arg0')]) + ## basic-data-calculators.h: ns3::MinMaxAvgTotalCalculator::MinMaxAvgTotalCalculator() [constructor] + cls.add_constructor([]) + ## basic-data-calculators.h: void ns3::MinMaxAvgTotalCalculator::Update(unsigned int const i) [member function] + cls.add_method('Update', + 'void', + [param('unsigned int const', 'i')]) + ## basic-data-calculators.h: void ns3::MinMaxAvgTotalCalculator::Output(ns3::DataOutputCallback & callback) const [member function] + cls.add_method('Output', + 'void', + [param('ns3::DataOutputCallback &', 'callback')], + is_const=True, is_virtual=True) + ## basic-data-calculators.h: void ns3::MinMaxAvgTotalCalculator::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3OmnetDataOutput_methods(root_module, cls): + ## omnet-data-output.h: ns3::OmnetDataOutput::OmnetDataOutput(ns3::OmnetDataOutput const & arg0) [copy constructor] + cls.add_constructor([param('ns3::OmnetDataOutput const &', 'arg0')]) + ## omnet-data-output.h: ns3::OmnetDataOutput::OmnetDataOutput() [constructor] + cls.add_constructor([]) + ## omnet-data-output.h: void ns3::OmnetDataOutput::Output(ns3::DataCollector & dc) [member function] + cls.add_method('Output', + 'void', + [param('ns3::DataCollector &', 'dc')], + is_virtual=True) + ## omnet-data-output.h: void ns3::OmnetDataOutput::SetFilePrefix(std::string const prefix) [member function] + cls.add_method('SetFilePrefix', + 'void', + [param('std::string const', 'prefix')]) + ## omnet-data-output.h: std::string ns3::OmnetDataOutput::GetFilePrefix() const [member function] + cls.add_method('GetFilePrefix', + 'std::string', + [], + is_const=True) + ## omnet-data-output.h: void ns3::OmnetDataOutput::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3PacketSizeMinMaxAvgTotalCalculator_methods(root_module, cls): + ## packet-data-calculators.h: ns3::PacketSizeMinMaxAvgTotalCalculator::PacketSizeMinMaxAvgTotalCalculator(ns3::PacketSizeMinMaxAvgTotalCalculator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketSizeMinMaxAvgTotalCalculator const &', 'arg0')]) + ## packet-data-calculators.h: ns3::PacketSizeMinMaxAvgTotalCalculator::PacketSizeMinMaxAvgTotalCalculator() [constructor] + cls.add_constructor([]) + ## packet-data-calculators.h: void ns3::PacketSizeMinMaxAvgTotalCalculator::PacketUpdate(std::string path, ns3::Ptr packet) [member function] + cls.add_method('PacketUpdate', + 'void', + [param('std::string', 'path'), param('ns3::Ptr< ns3::Packet const >', 'packet')]) + ## packet-data-calculators.h: void ns3::PacketSizeMinMaxAvgTotalCalculator::FrameUpdate(std::string path, ns3::Ptr packet, ns3::Mac48Address realto) [member function] + cls.add_method('FrameUpdate', + 'void', + [param('std::string', 'path'), param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'realto')]) + ## packet-data-calculators.h: void ns3::PacketSizeMinMaxAvgTotalCalculator::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3SqliteDataOutput_methods(root_module, cls): + ## sqlite-data-output.h: ns3::SqliteDataOutput::SqliteDataOutput(ns3::SqliteDataOutput const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SqliteDataOutput const &', 'arg0')]) + ## sqlite-data-output.h: ns3::SqliteDataOutput::SqliteDataOutput() [constructor] + cls.add_constructor([]) + ## sqlite-data-output.h: void ns3::SqliteDataOutput::Output(ns3::DataCollector & dc) [member function] + cls.add_method('Output', + 'void', + [param('ns3::DataCollector &', 'dc')], + is_virtual=True) + ## sqlite-data-output.h: void ns3::SqliteDataOutput::SetDBFile(std::string const file) [member function] + cls.add_method('SetDBFile', + 'void', + [param('std::string const', 'file')]) + ## sqlite-data-output.h: std::string ns3::SqliteDataOutput::GetDBFile() const [member function] + cls.add_method('GetDBFile', + 'std::string', + [], + is_const=True) + ## sqlite-data-output.h: void ns3::SqliteDataOutput::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3TimeMinMaxAvgTotalCalculator_methods(root_module, cls): + ## time-data-calculators.h: ns3::TimeMinMaxAvgTotalCalculator::TimeMinMaxAvgTotalCalculator(ns3::TimeMinMaxAvgTotalCalculator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::TimeMinMaxAvgTotalCalculator const &', 'arg0')]) + ## time-data-calculators.h: ns3::TimeMinMaxAvgTotalCalculator::TimeMinMaxAvgTotalCalculator() [constructor] + cls.add_constructor([]) + ## time-data-calculators.h: void ns3::TimeMinMaxAvgTotalCalculator::Update(ns3::Time const i) [member function] + cls.add_method('Update', + 'void', + [param('ns3::Time const', 'i')]) + ## time-data-calculators.h: void ns3::TimeMinMaxAvgTotalCalculator::Output(ns3::DataOutputCallback & callback) const [member function] + cls.add_method('Output', + 'void', + [param('ns3::DataOutputCallback &', 'callback')], + is_const=True, is_virtual=True) + ## time-data-calculators.h: void ns3::TimeMinMaxAvgTotalCalculator::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3CounterCalculator__Unsigned_int_methods(root_module, cls): + ## basic-data-calculators.h: ns3::CounterCalculator::CounterCalculator(ns3::CounterCalculator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CounterCalculator< unsigned int > const &', 'arg0')]) + ## basic-data-calculators.h: ns3::CounterCalculator::CounterCalculator() [constructor] + cls.add_constructor([]) + ## basic-data-calculators.h: void ns3::CounterCalculator::Update() [member function] + cls.add_method('Update', + 'void', + []) + ## basic-data-calculators.h: void ns3::CounterCalculator::Update(unsigned int const i) [member function] + cls.add_method('Update', + 'void', + [param('unsigned int const', 'i')]) + ## basic-data-calculators.h: unsigned int ns3::CounterCalculator::GetCount() const [member function] + cls.add_method('GetCount', + 'unsigned int', + [], + is_const=True) + ## basic-data-calculators.h: void ns3::CounterCalculator::Output(ns3::DataOutputCallback & callback) const [member function] + cls.add_method('Output', + 'void', + [param('ns3::DataOutputCallback &', 'callback')], + is_const=True, is_virtual=True) + ## basic-data-calculators.h: void ns3::CounterCalculator::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3PacketCounterCalculator_methods(root_module, cls): + ## packet-data-calculators.h: ns3::PacketCounterCalculator::PacketCounterCalculator(ns3::PacketCounterCalculator const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PacketCounterCalculator const &', 'arg0')]) + ## packet-data-calculators.h: ns3::PacketCounterCalculator::PacketCounterCalculator() [constructor] + cls.add_constructor([]) + ## packet-data-calculators.h: void ns3::PacketCounterCalculator::PacketUpdate(std::string path, ns3::Ptr packet) [member function] + cls.add_method('PacketUpdate', + 'void', + [param('std::string', 'path'), param('ns3::Ptr< ns3::Packet const >', 'packet')]) + ## packet-data-calculators.h: void ns3::PacketCounterCalculator::FrameUpdate(std::string path, ns3::Ptr packet, ns3::Mac48Address realto) [member function] + cls.add_method('FrameUpdate', + 'void', + [param('std::string', 'path'), param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'realto')]) + ## packet-data-calculators.h: void ns3::PacketCounterCalculator::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_udp_echo.py b/bindings/python/ns3_module_udp_echo.py new file mode 100644 index 000000000..c4fb73c46 --- /dev/null +++ b/bindings/python/ns3_module_udp_echo.py @@ -0,0 +1,133 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## udp-echo-client.h: ns3::UdpEchoClient [class] + module.add_class('UdpEchoClient', parent=root_module['ns3::Application']) + ## udp-echo-server.h: ns3::UdpEchoServer [class] + module.add_class('UdpEchoServer', parent=root_module['ns3::Application']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3UdpEchoClient_methods(root_module, root_module['ns3::UdpEchoClient']) + register_Ns3UdpEchoServer_methods(root_module, root_module['ns3::UdpEchoServer']) + return + +def register_Ns3UdpEchoClient_methods(root_module, cls): + ## udp-echo-client.h: ns3::UdpEchoClient::UdpEchoClient(ns3::UdpEchoClient const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UdpEchoClient const &', 'arg0')]) + ## udp-echo-client.h: static ns3::TypeId ns3::UdpEchoClient::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## udp-echo-client.h: ns3::UdpEchoClient::UdpEchoClient() [constructor] + cls.add_constructor([]) + ## udp-echo-client.h: void ns3::UdpEchoClient::SetRemote(ns3::Ipv4Address ip, uint16_t port) [member function] + cls.add_method('SetRemote', + 'void', + [param('ns3::Ipv4Address', 'ip'), param('uint16_t', 'port')]) + ## udp-echo-client.h: void ns3::UdpEchoClient::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## udp-echo-client.h: void ns3::UdpEchoClient::StartApplication() [member function] + cls.add_method('StartApplication', + 'void', + [], + visibility='private', is_virtual=True) + ## udp-echo-client.h: void ns3::UdpEchoClient::StopApplication() [member function] + cls.add_method('StopApplication', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3UdpEchoServer_methods(root_module, cls): + ## udp-echo-server.h: ns3::UdpEchoServer::UdpEchoServer(ns3::UdpEchoServer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::UdpEchoServer const &', 'arg0')]) + ## udp-echo-server.h: static ns3::TypeId ns3::UdpEchoServer::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## udp-echo-server.h: ns3::UdpEchoServer::UdpEchoServer() [constructor] + cls.add_constructor([]) + ## udp-echo-server.h: void ns3::UdpEchoServer::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## udp-echo-server.h: void ns3::UdpEchoServer::StartApplication() [member function] + cls.add_method('StartApplication', + 'void', + [], + visibility='private', is_virtual=True) + ## udp-echo-server.h: void ns3::UdpEchoServer::StopApplication() [member function] + cls.add_method('StopApplication', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3_module_wifi.py b/bindings/python/ns3_module_wifi.py new file mode 100644 index 000000000..b5350b533 --- /dev/null +++ b/bindings/python/ns3_module_wifi.py @@ -0,0 +1,2819 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + +def register_types(module): + root_module = module.get_root() + + ## wifi-preamble.h: ns3::WifiPreamble [enumeration] + module.add_enum('WifiPreamble', ['WIFI_PREAMBLE_LONG', 'WIFI_PREAMBLE_SHORT']) + ## wifi-phy-standard.h: ns3::WifiPhyStandard [enumeration] + module.add_enum('WifiPhyStandard', ['WIFI_PHY_STANDARD_80211a', 'WIFI_PHY_STANDARD_holland']) + ## interference-helper.h: ns3::InterferenceHelper [class] + module.add_class('InterferenceHelper', allow_subclassing=False) + ## interference-helper.h: ns3::InterferenceHelper::SnrPer [struct] + module.add_class('SnrPer', outer_class=root_module['ns3::InterferenceHelper']) + ## ssid.h: ns3::Ssid [class] + module.add_class('Ssid') + ## supported-rates.h: ns3::SupportedRates [class] + module.add_class('SupportedRates') + ## rraa-wifi-manager.h: ns3::ThresholdsItem [struct] + module.add_class('ThresholdsItem') + ## wifi-mode.h: ns3::WifiMode [class] + module.add_class('WifiMode') + ## wifi-mode.h: ns3::WifiMode::ModulationType [enumeration] + module.add_enum('ModulationType', ['BPSK', 'QAM'], outer_class=root_module['ns3::WifiMode']) + ## wifi-mode.h: ns3::WifiModeFactory [class] + module.add_class('WifiModeFactory') + ## wifi-phy.h: ns3::WifiPhyListener [class] + module.add_class('WifiPhyListener', allow_subclassing=True) + ## wifi-remote-station-manager.h: ns3::WifiRemoteStation [class] + module.add_class('WifiRemoteStation', allow_subclassing=True) + ## amrr-wifi-manager.h: ns3::AmrrWifiRemoteStation [class] + module.add_class('AmrrWifiRemoteStation', parent=root_module['ns3::WifiRemoteStation']) + ## arf-wifi-manager.h: ns3::ArfWifiRemoteStation [class] + module.add_class('ArfWifiRemoteStation', parent=root_module['ns3::WifiRemoteStation']) + ## constant-rate-wifi-manager.h: ns3::ConstantRateWifiRemoteStation [class] + module.add_class('ConstantRateWifiRemoteStation', parent=root_module['ns3::WifiRemoteStation']) + ## ideal-wifi-manager.h: ns3::IdealWifiRemoteStation [class] + module.add_class('IdealWifiRemoteStation', parent=root_module['ns3::WifiRemoteStation']) + ## onoe-wifi-manager.h: ns3::OnoeWifiRemoteStation [class] + module.add_class('OnoeWifiRemoteStation', parent=root_module['ns3::WifiRemoteStation']) + ## propagation-delay-model.h: ns3::PropagationDelayModel [class] + module.add_class('PropagationDelayModel', parent=root_module['ns3::Object']) + ## propagation-loss-model.h: ns3::PropagationLossModel [class] + module.add_class('PropagationLossModel', parent=root_module['ns3::Object']) + ## propagation-delay-model.h: ns3::RandomPropagationDelayModel [class] + module.add_class('RandomPropagationDelayModel', parent=root_module['ns3::PropagationDelayModel']) + ## propagation-loss-model.h: ns3::RandomPropagationLossModel [class] + module.add_class('RandomPropagationLossModel', parent=root_module['ns3::PropagationLossModel']) + ## rraa-wifi-manager.h: ns3::RraaWifiRemoteStation [class] + module.add_class('RraaWifiRemoteStation', parent=root_module['ns3::WifiRemoteStation']) + ## ssid.h: ns3::SsidChecker [class] + module.add_class('SsidChecker', parent=root_module['ns3::AttributeChecker']) + ## ssid.h: ns3::SsidValue [class] + module.add_class('SsidValue', parent=root_module['ns3::AttributeValue']) + ## wifi-mac.h: ns3::WifiMac [class] + module.add_class('WifiMac', parent=root_module['ns3::Object']) + ## wifi-mode.h: ns3::WifiModeChecker [class] + module.add_class('WifiModeChecker', parent=root_module['ns3::AttributeChecker']) + ## wifi-mode.h: ns3::WifiModeValue [class] + module.add_class('WifiModeValue', parent=root_module['ns3::AttributeValue']) + ## wifi-phy.h: ns3::WifiPhy [class] + module.add_class('WifiPhy', parent=root_module['ns3::Object']) + ## wifi-phy.h: ns3::WifiPhy::State [enumeration] + module.add_enum('State', ['SYNC', 'TX', 'CCA_BUSY', 'IDLE'], outer_class=root_module['ns3::WifiPhy']) + ## wifi-remote-station-manager.h: ns3::WifiRemoteStationManager [class] + module.add_class('WifiRemoteStationManager', parent=root_module['ns3::Object']) + ## yans-wifi-phy.h: ns3::YansWifiPhy [class] + module.add_class('YansWifiPhy', parent=root_module['ns3::WifiPhy']) + ## aarf-wifi-manager.h: ns3::AarfWifiRemoteStation [class] + module.add_class('AarfWifiRemoteStation', parent=root_module['ns3::ArfWifiRemoteStation']) + ## adhoc-wifi-mac.h: ns3::AdhocWifiMac [class] + module.add_class('AdhocWifiMac', parent=root_module['ns3::WifiMac']) + ## amrr-wifi-manager.h: ns3::AmrrWifiManager [class] + module.add_class('AmrrWifiManager', parent=root_module['ns3::WifiRemoteStationManager']) + ## arf-wifi-manager.h: ns3::ArfWifiManager [class] + module.add_class('ArfWifiManager', parent=root_module['ns3::WifiRemoteStationManager']) + ## composite-propagation-loss-model.h: ns3::CompositePropagationLossModel [class] + module.add_class('CompositePropagationLossModel', parent=root_module['ns3::PropagationLossModel']) + ## constant-rate-wifi-manager.h: ns3::ConstantRateWifiManager [class] + module.add_class('ConstantRateWifiManager', parent=root_module['ns3::WifiRemoteStationManager']) + ## propagation-delay-model.h: ns3::ConstantSpeedPropagationDelayModel [class] + module.add_class('ConstantSpeedPropagationDelayModel', parent=root_module['ns3::PropagationDelayModel']) + ## propagation-loss-model.h: ns3::FriisPropagationLossModel [class] + module.add_class('FriisPropagationLossModel', parent=root_module['ns3::PropagationLossModel']) + ## ideal-wifi-manager.h: ns3::IdealWifiManager [class] + module.add_class('IdealWifiManager', parent=root_module['ns3::WifiRemoteStationManager']) + ## jakes-propagation-loss-model.h: ns3::JakesPropagationLossModel [class] + module.add_class('JakesPropagationLossModel', parent=root_module['ns3::PropagationLossModel']) + ## propagation-loss-model.h: ns3::LogDistancePropagationLossModel [class] + module.add_class('LogDistancePropagationLossModel', parent=root_module['ns3::PropagationLossModel']) + ## nqap-wifi-mac.h: ns3::NqapWifiMac [class] + module.add_class('NqapWifiMac', parent=root_module['ns3::WifiMac']) + ## nqsta-wifi-mac.h: ns3::NqstaWifiMac [class] + module.add_class('NqstaWifiMac', parent=root_module['ns3::WifiMac']) + ## onoe-wifi-manager.h: ns3::OnoeWifiManager [class] + module.add_class('OnoeWifiManager', parent=root_module['ns3::WifiRemoteStationManager']) + ## rraa-wifi-manager.h: ns3::RraaWifiManager [class] + module.add_class('RraaWifiManager', parent=root_module['ns3::WifiRemoteStationManager']) + ## wifi-channel.h: ns3::WifiChannel [class] + module.add_class('WifiChannel', parent=root_module['ns3::Channel']) + ## wifi-net-device.h: ns3::WifiNetDevice [class] + module.add_class('WifiNetDevice', parent=root_module['ns3::NetDevice']) + ## yans-wifi-channel.h: ns3::YansWifiChannel [class] + module.add_class('YansWifiChannel', parent=root_module['ns3::WifiChannel']) + ## aarf-wifi-manager.h: ns3::AarfWifiManager [class] + module.add_class('AarfWifiManager', parent=root_module['ns3::ArfWifiManager']) + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + register_Ns3InterferenceHelper_methods(root_module, root_module['ns3::InterferenceHelper']) + register_Ns3InterferenceHelperSnrPer_methods(root_module, root_module['ns3::InterferenceHelper::SnrPer']) + register_Ns3Ssid_methods(root_module, root_module['ns3::Ssid']) + register_Ns3SupportedRates_methods(root_module, root_module['ns3::SupportedRates']) + register_Ns3ThresholdsItem_methods(root_module, root_module['ns3::ThresholdsItem']) + register_Ns3WifiMode_methods(root_module, root_module['ns3::WifiMode']) + register_Ns3WifiModeFactory_methods(root_module, root_module['ns3::WifiModeFactory']) + register_Ns3WifiPhyListener_methods(root_module, root_module['ns3::WifiPhyListener']) + register_Ns3WifiRemoteStation_methods(root_module, root_module['ns3::WifiRemoteStation']) + register_Ns3AmrrWifiRemoteStation_methods(root_module, root_module['ns3::AmrrWifiRemoteStation']) + register_Ns3ArfWifiRemoteStation_methods(root_module, root_module['ns3::ArfWifiRemoteStation']) + register_Ns3ConstantRateWifiRemoteStation_methods(root_module, root_module['ns3::ConstantRateWifiRemoteStation']) + register_Ns3IdealWifiRemoteStation_methods(root_module, root_module['ns3::IdealWifiRemoteStation']) + register_Ns3OnoeWifiRemoteStation_methods(root_module, root_module['ns3::OnoeWifiRemoteStation']) + register_Ns3PropagationDelayModel_methods(root_module, root_module['ns3::PropagationDelayModel']) + register_Ns3PropagationLossModel_methods(root_module, root_module['ns3::PropagationLossModel']) + register_Ns3RandomPropagationDelayModel_methods(root_module, root_module['ns3::RandomPropagationDelayModel']) + register_Ns3RandomPropagationLossModel_methods(root_module, root_module['ns3::RandomPropagationLossModel']) + register_Ns3RraaWifiRemoteStation_methods(root_module, root_module['ns3::RraaWifiRemoteStation']) + register_Ns3SsidChecker_methods(root_module, root_module['ns3::SsidChecker']) + register_Ns3SsidValue_methods(root_module, root_module['ns3::SsidValue']) + register_Ns3WifiMac_methods(root_module, root_module['ns3::WifiMac']) + register_Ns3WifiModeChecker_methods(root_module, root_module['ns3::WifiModeChecker']) + register_Ns3WifiModeValue_methods(root_module, root_module['ns3::WifiModeValue']) + register_Ns3WifiPhy_methods(root_module, root_module['ns3::WifiPhy']) + register_Ns3WifiRemoteStationManager_methods(root_module, root_module['ns3::WifiRemoteStationManager']) + register_Ns3YansWifiPhy_methods(root_module, root_module['ns3::YansWifiPhy']) + register_Ns3AarfWifiRemoteStation_methods(root_module, root_module['ns3::AarfWifiRemoteStation']) + register_Ns3AdhocWifiMac_methods(root_module, root_module['ns3::AdhocWifiMac']) + register_Ns3AmrrWifiManager_methods(root_module, root_module['ns3::AmrrWifiManager']) + register_Ns3ArfWifiManager_methods(root_module, root_module['ns3::ArfWifiManager']) + register_Ns3CompositePropagationLossModel_methods(root_module, root_module['ns3::CompositePropagationLossModel']) + register_Ns3ConstantRateWifiManager_methods(root_module, root_module['ns3::ConstantRateWifiManager']) + register_Ns3ConstantSpeedPropagationDelayModel_methods(root_module, root_module['ns3::ConstantSpeedPropagationDelayModel']) + register_Ns3FriisPropagationLossModel_methods(root_module, root_module['ns3::FriisPropagationLossModel']) + register_Ns3IdealWifiManager_methods(root_module, root_module['ns3::IdealWifiManager']) + register_Ns3JakesPropagationLossModel_methods(root_module, root_module['ns3::JakesPropagationLossModel']) + register_Ns3LogDistancePropagationLossModel_methods(root_module, root_module['ns3::LogDistancePropagationLossModel']) + register_Ns3NqapWifiMac_methods(root_module, root_module['ns3::NqapWifiMac']) + register_Ns3NqstaWifiMac_methods(root_module, root_module['ns3::NqstaWifiMac']) + register_Ns3OnoeWifiManager_methods(root_module, root_module['ns3::OnoeWifiManager']) + register_Ns3RraaWifiManager_methods(root_module, root_module['ns3::RraaWifiManager']) + register_Ns3WifiChannel_methods(root_module, root_module['ns3::WifiChannel']) + register_Ns3WifiNetDevice_methods(root_module, root_module['ns3::WifiNetDevice']) + register_Ns3YansWifiChannel_methods(root_module, root_module['ns3::YansWifiChannel']) + register_Ns3AarfWifiManager_methods(root_module, root_module['ns3::AarfWifiManager']) + return + +def register_Ns3InterferenceHelper_methods(root_module, cls): + ## interference-helper.h: ns3::InterferenceHelper::InterferenceHelper() [constructor] + cls.add_constructor([]) + ## interference-helper.h: ns3::Ptr ns3::InterferenceHelper::Add(uint32_t size, ns3::WifiMode payloadMode, ns3::WifiPreamble preamble, ns3::Time duration, double rxPower) [member function] + cls.add_method('Add', + 'ns3::Ptr< ns3::InterferenceHelper::Event >', + [param('uint32_t', 'size'), param('ns3::WifiMode', 'payloadMode'), param('ns3::WifiPreamble', 'preamble'), param('ns3::Time', 'duration'), param('double', 'rxPower')]) + ## interference-helper.h: ns3::InterferenceHelper::SnrPer ns3::InterferenceHelper::CalculateSnrPer(ns3::Ptr event) [member function] + cls.add_method('CalculateSnrPer', + 'ns3::InterferenceHelper::SnrPer', + [param('ns3::Ptr< ns3::InterferenceHelper::Event >', 'event')]) + ## interference-helper.h: ns3::Time ns3::InterferenceHelper::CalculateTxDuration(uint32_t size, ns3::WifiMode payloadMode, ns3::WifiPreamble preamble) const [member function] + cls.add_method('CalculateTxDuration', + 'ns3::Time', + [param('uint32_t', 'size'), param('ns3::WifiMode', 'payloadMode'), param('ns3::WifiPreamble', 'preamble')], + is_const=True) + ## interference-helper.h: void ns3::InterferenceHelper::Configure80211aParameters() [member function] + cls.add_method('Configure80211aParameters', + 'void', + []) + ## interference-helper.h: ns3::Time ns3::InterferenceHelper::GetEnergyDuration(double energyW) [member function] + cls.add_method('GetEnergyDuration', + 'ns3::Time', + [param('double', 'energyW')]) + ## interference-helper.h: ns3::Ptr ns3::InterferenceHelper::GetErrorRateModel() const [member function] + cls.add_method('GetErrorRateModel', + 'ns3::Ptr< ns3::ErrorRateModel >', + [], + is_const=True) + ## interference-helper.h: double ns3::InterferenceHelper::GetNoiseFloorW() const [member function] + cls.add_method('GetNoiseFloorW', + 'double', + [], + is_const=True) + ## interference-helper.h: void ns3::InterferenceHelper::SetErrorRateModel(ns3::Ptr rate) [member function] + cls.add_method('SetErrorRateModel', + 'void', + [param('ns3::Ptr< ns3::ErrorRateModel >', 'rate')]) + ## interference-helper.h: void ns3::InterferenceHelper::SetNoiseFloorW(double noiseFloor) [member function] + cls.add_method('SetNoiseFloorW', + 'void', + [param('double', 'noiseFloor')]) + return + +def register_Ns3InterferenceHelperSnrPer_methods(root_module, cls): + ## interference-helper.h: ns3::InterferenceHelper::SnrPer::SnrPer() [constructor] + cls.add_constructor([]) + ## interference-helper.h: ns3::InterferenceHelper::SnrPer::SnrPer(ns3::InterferenceHelper::SnrPer const & arg0) [copy constructor] + cls.add_constructor([param('ns3::InterferenceHelper::SnrPer const &', 'arg0')]) + ## interference-helper.h: ns3::InterferenceHelper::SnrPer::per [variable] + cls.add_instance_attribute('per', 'double', is_const=False) + ## interference-helper.h: ns3::InterferenceHelper::SnrPer::snr [variable] + cls.add_instance_attribute('snr', 'double', is_const=False) + return + +def register_Ns3Ssid_methods(root_module, cls): + cls.add_output_stream_operator() + ## ssid.h: ns3::Ssid::Ssid(ns3::Ssid const & arg0) [copy constructor] + cls.add_constructor([param('ns3::Ssid const &', 'arg0')]) + ## ssid.h: ns3::Ssid::Ssid() [constructor] + cls.add_constructor([]) + ## ssid.h: ns3::Ssid::Ssid(std::string s) [constructor] + cls.add_constructor([param('std::string', 's')]) + ## ssid.h: ns3::Ssid::Ssid(char const * ssid, uint8_t length) [constructor] + cls.add_constructor([param('char const *', 'ssid'), param('uint8_t', 'length')]) + ## ssid.h: ns3::Buffer::Iterator ns3::Ssid::Deserialize(ns3::Buffer::Iterator i) [member function] + cls.add_method('Deserialize', + 'ns3::Buffer::Iterator', + [param('ns3::Buffer::Iterator', 'i')]) + ## ssid.h: uint32_t ns3::Ssid::GetLength() const [member function] + cls.add_method('GetLength', + 'uint32_t', + [], + is_const=True) + ## ssid.h: uint32_t ns3::Ssid::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## ssid.h: bool ns3::Ssid::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True) + ## ssid.h: bool ns3::Ssid::IsEqual(ns3::Ssid const & o) const [member function] + cls.add_method('IsEqual', + 'bool', + [param('ns3::Ssid const &', 'o')], + is_const=True) + ## ssid.h: char * ns3::Ssid::PeekString() const [member function] + cls.add_method('PeekString', + 'char *', + [], + is_const=True) + ## ssid.h: ns3::Buffer::Iterator ns3::Ssid::Serialize(ns3::Buffer::Iterator i) const [member function] + cls.add_method('Serialize', + 'ns3::Buffer::Iterator', + [param('ns3::Buffer::Iterator', 'i')], + is_const=True) + return + +def register_Ns3SupportedRates_methods(root_module, cls): + cls.add_output_stream_operator() + ## supported-rates.h: ns3::SupportedRates::SupportedRates(ns3::SupportedRates const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SupportedRates const &', 'arg0')]) + ## supported-rates.h: ns3::SupportedRates::SupportedRates() [constructor] + cls.add_constructor([]) + ## supported-rates.h: void ns3::SupportedRates::AddSupportedRate(uint32_t bs) [member function] + cls.add_method('AddSupportedRate', + 'void', + [param('uint32_t', 'bs')]) + ## supported-rates.h: ns3::Buffer::Iterator ns3::SupportedRates::Deserialize(ns3::Buffer::Iterator start) [member function] + cls.add_method('Deserialize', + 'ns3::Buffer::Iterator', + [param('ns3::Buffer::Iterator', 'start')]) + ## supported-rates.h: uint8_t ns3::SupportedRates::GetNRates() const [member function] + cls.add_method('GetNRates', + 'uint8_t', + [], + is_const=True) + ## supported-rates.h: uint32_t ns3::SupportedRates::GetRate(uint8_t i) const [member function] + cls.add_method('GetRate', + 'uint32_t', + [param('uint8_t', 'i')], + is_const=True) + ## supported-rates.h: uint32_t ns3::SupportedRates::GetSerializedSize() const [member function] + cls.add_method('GetSerializedSize', + 'uint32_t', + [], + is_const=True) + ## supported-rates.h: bool ns3::SupportedRates::IsBasicRate(uint32_t bs) const [member function] + cls.add_method('IsBasicRate', + 'bool', + [param('uint32_t', 'bs')], + is_const=True) + ## supported-rates.h: bool ns3::SupportedRates::IsSupportedRate(uint32_t bs) const [member function] + cls.add_method('IsSupportedRate', + 'bool', + [param('uint32_t', 'bs')], + is_const=True) + ## supported-rates.h: ns3::Buffer::Iterator ns3::SupportedRates::Serialize(ns3::Buffer::Iterator start) const [member function] + cls.add_method('Serialize', + 'ns3::Buffer::Iterator', + [param('ns3::Buffer::Iterator', 'start')], + is_const=True) + ## supported-rates.h: void ns3::SupportedRates::SetBasicRate(uint32_t bs) [member function] + cls.add_method('SetBasicRate', + 'void', + [param('uint32_t', 'bs')]) + return + +def register_Ns3ThresholdsItem_methods(root_module, cls): + ## rraa-wifi-manager.h: ns3::ThresholdsItem::datarate [variable] + cls.add_instance_attribute('datarate', 'uint32_t', is_const=False) + ## rraa-wifi-manager.h: ns3::ThresholdsItem::pori [variable] + cls.add_instance_attribute('pori', 'double', is_const=False) + ## rraa-wifi-manager.h: ns3::ThresholdsItem::pmtl [variable] + cls.add_instance_attribute('pmtl', 'double', is_const=False) + ## rraa-wifi-manager.h: ns3::ThresholdsItem::ewnd [variable] + cls.add_instance_attribute('ewnd', 'uint32_t', is_const=False) + ## rraa-wifi-manager.h: ns3::ThresholdsItem::ThresholdsItem(ns3::ThresholdsItem const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ThresholdsItem const &', 'arg0')]) + ## rraa-wifi-manager.h: ns3::ThresholdsItem::ThresholdsItem() [constructor] + cls.add_constructor([]) + return + +def register_Ns3WifiMode_methods(root_module, cls): + cls.add_output_stream_operator() + cls.add_binary_comparison_operator('==') + ## wifi-mode.h: ns3::WifiMode::WifiMode(ns3::WifiMode const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiMode const &', 'arg0')]) + ## wifi-mode.h: ns3::WifiMode::WifiMode() [constructor] + cls.add_constructor([]) + ## wifi-mode.h: ns3::WifiMode::WifiMode(std::string name) [constructor] + cls.add_constructor([param('std::string', 'name')]) + ## wifi-mode.h: uint32_t ns3::WifiMode::GetBandwidth() const [member function] + cls.add_method('GetBandwidth', + 'uint32_t', + [], + is_const=True) + ## wifi-mode.h: uint8_t ns3::WifiMode::GetConstellationSize() const [member function] + cls.add_method('GetConstellationSize', + 'uint8_t', + [], + is_const=True) + ## wifi-mode.h: uint32_t ns3::WifiMode::GetDataRate() const [member function] + cls.add_method('GetDataRate', + 'uint32_t', + [], + is_const=True) + ## wifi-mode.h: ns3::WifiMode::ModulationType ns3::WifiMode::GetModulationType() const [member function] + cls.add_method('GetModulationType', + 'ns3::WifiMode::ModulationType', + [], + is_const=True) + ## wifi-mode.h: uint32_t ns3::WifiMode::GetPhyRate() const [member function] + cls.add_method('GetPhyRate', + 'uint32_t', + [], + is_const=True) + ## wifi-mode.h: uint32_t ns3::WifiMode::GetUid() const [member function] + cls.add_method('GetUid', + 'uint32_t', + [], + is_const=True) + ## wifi-mode.h: std::string ns3::WifiMode::GetUniqueName() const [member function] + cls.add_method('GetUniqueName', + 'std::string', + [], + is_const=True) + ## wifi-mode.h: bool ns3::WifiMode::IsMandatory() const [member function] + cls.add_method('IsMandatory', + 'bool', + [], + is_const=True) + ## wifi-mode.h: bool ns3::WifiMode::IsModulationBpsk() const [member function] + cls.add_method('IsModulationBpsk', + 'bool', + [], + is_const=True) + ## wifi-mode.h: bool ns3::WifiMode::IsModulationQam() const [member function] + cls.add_method('IsModulationQam', + 'bool', + [], + is_const=True) + return + +def register_Ns3WifiModeFactory_methods(root_module, cls): + ## wifi-mode.h: ns3::WifiModeFactory::WifiModeFactory(ns3::WifiModeFactory const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiModeFactory const &', 'arg0')]) + ## wifi-mode.h: static ns3::WifiMode ns3::WifiModeFactory::CreateBpsk(std::string uniqueName, bool isMandatory, uint32_t bandwidth, uint32_t dataRate, uint32_t phyRate) [member function] + cls.add_method('CreateBpsk', + 'ns3::WifiMode', + [param('std::string', 'uniqueName'), param('bool', 'isMandatory'), param('uint32_t', 'bandwidth'), param('uint32_t', 'dataRate'), param('uint32_t', 'phyRate')], + is_static=True) + ## wifi-mode.h: static ns3::WifiMode ns3::WifiModeFactory::CreateQam(std::string uniqueName, bool isMandatory, uint32_t bandwidth, uint32_t dataRate, uint32_t phyRate, uint8_t constellationSize) [member function] + cls.add_method('CreateQam', + 'ns3::WifiMode', + [param('std::string', 'uniqueName'), param('bool', 'isMandatory'), param('uint32_t', 'bandwidth'), param('uint32_t', 'dataRate'), param('uint32_t', 'phyRate'), param('uint8_t', 'constellationSize')], + is_static=True) + return + +def register_Ns3WifiPhyListener_methods(root_module, cls): + ## wifi-phy.h: ns3::WifiPhyListener::WifiPhyListener(ns3::WifiPhyListener const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiPhyListener const &', 'arg0')]) + ## wifi-phy.h: ns3::WifiPhyListener::WifiPhyListener() [constructor] + cls.add_constructor([]) + ## wifi-phy.h: void ns3::WifiPhyListener::NotifyRxStart(ns3::Time duration) [member function] + cls.add_method('NotifyRxStart', + 'void', + [param('ns3::Time', 'duration')], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhyListener::NotifyRxEndOk() [member function] + cls.add_method('NotifyRxEndOk', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhyListener::NotifyRxEndError() [member function] + cls.add_method('NotifyRxEndError', + 'void', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhyListener::NotifyTxStart(ns3::Time duration) [member function] + cls.add_method('NotifyTxStart', + 'void', + [param('ns3::Time', 'duration')], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhyListener::NotifyMaybeCcaBusyStart(ns3::Time duration) [member function] + cls.add_method('NotifyMaybeCcaBusyStart', + 'void', + [param('ns3::Time', 'duration')], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3WifiRemoteStation_methods(root_module, cls): + ## wifi-remote-station-manager.h: ns3::WifiRemoteStation::WifiRemoteStation(ns3::WifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiRemoteStation const &', 'arg0')]) + ## wifi-remote-station-manager.h: static ns3::TypeId ns3::WifiRemoteStation::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## wifi-remote-station-manager.h: ns3::WifiRemoteStation::WifiRemoteStation() [constructor] + cls.add_constructor([]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::Reset() [member function] + cls.add_method('Reset', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::AddSupportedMode(ns3::WifiMode mode) [member function] + cls.add_method('AddSupportedMode', + 'void', + [param('ns3::WifiMode', 'mode')]) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::IsBrandNew() const [member function] + cls.add_method('IsBrandNew', + 'bool', + [], + is_const=True) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::IsAssociated() const [member function] + cls.add_method('IsAssociated', + 'bool', + [], + is_const=True) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::IsWaitAssocTxOk() const [member function] + cls.add_method('IsWaitAssocTxOk', + 'bool', + [], + is_const=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::RecordWaitAssocTxOk() [member function] + cls.add_method('RecordWaitAssocTxOk', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::RecordGotAssocTxOk() [member function] + cls.add_method('RecordGotAssocTxOk', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::RecordGotAssocTxFailed() [member function] + cls.add_method('RecordGotAssocTxFailed', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::RecordDisassociated() [member function] + cls.add_method('RecordDisassociated', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::PrepareForQueue(ns3::Ptr packet, uint32_t fullPacketSize) [member function] + cls.add_method('PrepareForQueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint32_t', 'fullPacketSize')]) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStation::GetDataMode(ns3::Ptr packet, uint32_t fullPacketSize) [member function] + cls.add_method('GetDataMode', + 'ns3::WifiMode', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint32_t', 'fullPacketSize')]) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStation::GetRtsMode(ns3::Ptr packet) [member function] + cls.add_method('GetRtsMode', + 'ns3::WifiMode', + [param('ns3::Ptr< ns3::Packet const >', 'packet')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::ReportRtsFailed() [member function] + cls.add_method('ReportRtsFailed', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::ReportDataFailed() [member function] + cls.add_method('ReportDataFailed', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::ReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('ReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::ReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('ReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::ReportFinalRtsFailed() [member function] + cls.add_method('ReportFinalRtsFailed', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::ReportFinalDataFailed() [member function] + cls.add_method('ReportFinalDataFailed', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::ReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('ReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')]) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::NeedRts(ns3::Ptr packet) [member function] + cls.add_method('NeedRts', + 'bool', + [param('ns3::Ptr< ns3::Packet const >', 'packet')], + is_virtual=True) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::NeedRtsRetransmission(ns3::Ptr packet) [member function] + cls.add_method('NeedRtsRetransmission', + 'bool', + [param('ns3::Ptr< ns3::Packet const >', 'packet')], + is_virtual=True) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::NeedDataRetransmission(ns3::Ptr packet) [member function] + cls.add_method('NeedDataRetransmission', + 'bool', + [param('ns3::Ptr< ns3::Packet const >', 'packet')], + is_virtual=True) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::NeedFragmentation(ns3::Ptr packet) [member function] + cls.add_method('NeedFragmentation', + 'bool', + [param('ns3::Ptr< ns3::Packet const >', 'packet')], + is_virtual=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStation::GetFragmentSize(ns3::Ptr packet, uint32_t fragmentNumber) [member function] + cls.add_method('GetFragmentSize', + 'uint32_t', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint32_t', 'fragmentNumber')], + is_virtual=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStation::GetFragmentOffset(ns3::Ptr packet, uint32_t fragmentNumber) [member function] + cls.add_method('GetFragmentOffset', + 'uint32_t', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint32_t', 'fragmentNumber')], + is_virtual=True) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStation::IsLastFragment(ns3::Ptr packet, uint32_t fragmentNumber) [member function] + cls.add_method('IsLastFragment', + 'bool', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('uint32_t', 'fragmentNumber')], + is_virtual=True) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStation::GetCtsMode(ns3::WifiMode rtsMode) [member function] + cls.add_method('GetCtsMode', + 'ns3::WifiMode', + [param('ns3::WifiMode', 'rtsMode')]) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStation::GetAckMode(ns3::WifiMode dataMode) [member function] + cls.add_method('GetAckMode', + 'ns3::WifiMode', + [param('ns3::WifiMode', 'dataMode')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::DoReportRtsFailed() [member function] + cls.add_method('DoReportRtsFailed', + 'void', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::DoReportDataFailed() [member function] + cls.add_method('DoReportDataFailed', + 'void', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::DoReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('DoReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::DoReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('DoReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::DoReportFinalRtsFailed() [member function] + cls.add_method('DoReportFinalRtsFailed', + 'void', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::DoReportFinalDataFailed() [member function] + cls.add_method('DoReportFinalDataFailed', + 'void', + [], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStation::DoReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('DoReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')], + is_pure_virtual=True, visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStation::GetNSupportedModes() const [member function] + cls.add_method('GetNSupportedModes', + 'uint32_t', + [], + is_const=True, visibility='protected') + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStation::GetSupportedMode(uint32_t i) const [member function] + cls.add_method('GetSupportedMode', + 'ns3::WifiMode', + [param('uint32_t', 'i')], + is_const=True, visibility='protected') + ## wifi-remote-station-manager.h: ns3::Ptr ns3::WifiRemoteStation::GetManager() const [member function] + cls.add_method('GetManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_pure_virtual=True, is_const=True, visibility='private', is_virtual=True) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStation::DoGetDataMode(uint32_t size) [member function] + cls.add_method('DoGetDataMode', + 'ns3::WifiMode', + [param('uint32_t', 'size')], + is_pure_virtual=True, visibility='private', is_virtual=True) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStation::DoGetRtsMode() [member function] + cls.add_method('DoGetRtsMode', + 'ns3::WifiMode', + [], + is_pure_virtual=True, visibility='private', is_virtual=True) + return + +def register_Ns3AmrrWifiRemoteStation_methods(root_module, cls): + ## amrr-wifi-manager.h: ns3::AmrrWifiRemoteStation::AmrrWifiRemoteStation(ns3::AmrrWifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AmrrWifiRemoteStation const &', 'arg0')]) + ## amrr-wifi-manager.h: ns3::AmrrWifiRemoteStation::AmrrWifiRemoteStation(ns3::Ptr stations) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::AmrrWifiManager >', 'stations')]) + ## amrr-wifi-manager.h: void ns3::AmrrWifiRemoteStation::DoReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('DoReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')], + visibility='protected', is_virtual=True) + ## amrr-wifi-manager.h: void ns3::AmrrWifiRemoteStation::DoReportRtsFailed() [member function] + cls.add_method('DoReportRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## amrr-wifi-manager.h: void ns3::AmrrWifiRemoteStation::DoReportDataFailed() [member function] + cls.add_method('DoReportDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## amrr-wifi-manager.h: void ns3::AmrrWifiRemoteStation::DoReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('DoReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')], + visibility='protected', is_virtual=True) + ## amrr-wifi-manager.h: void ns3::AmrrWifiRemoteStation::DoReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('DoReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')], + visibility='protected', is_virtual=True) + ## amrr-wifi-manager.h: void ns3::AmrrWifiRemoteStation::DoReportFinalRtsFailed() [member function] + cls.add_method('DoReportFinalRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## amrr-wifi-manager.h: void ns3::AmrrWifiRemoteStation::DoReportFinalDataFailed() [member function] + cls.add_method('DoReportFinalDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## amrr-wifi-manager.h: ns3::Ptr ns3::AmrrWifiRemoteStation::GetManager() const [member function] + cls.add_method('GetManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_const=True, visibility='private', is_virtual=True) + ## amrr-wifi-manager.h: ns3::WifiMode ns3::AmrrWifiRemoteStation::DoGetDataMode(uint32_t size) [member function] + cls.add_method('DoGetDataMode', + 'ns3::WifiMode', + [param('uint32_t', 'size')], + visibility='private', is_virtual=True) + ## amrr-wifi-manager.h: ns3::WifiMode ns3::AmrrWifiRemoteStation::DoGetRtsMode() [member function] + cls.add_method('DoGetRtsMode', + 'ns3::WifiMode', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3ArfWifiRemoteStation_methods(root_module, cls): + ## arf-wifi-manager.h: ns3::ArfWifiRemoteStation::ArfWifiRemoteStation(ns3::ArfWifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ArfWifiRemoteStation const &', 'arg0')]) + ## arf-wifi-manager.h: ns3::ArfWifiRemoteStation::ArfWifiRemoteStation(ns3::Ptr stations, int minTimerTimeout, int minSuccessThreshold) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::ArfWifiManager >', 'stations'), param('int', 'minTimerTimeout'), param('int', 'minSuccessThreshold')]) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::DoReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('DoReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')], + visibility='protected', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::DoReportRtsFailed() [member function] + cls.add_method('DoReportRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::DoReportDataFailed() [member function] + cls.add_method('DoReportDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::DoReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('DoReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')], + visibility='protected', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::DoReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('DoReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')], + visibility='protected', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::DoReportFinalRtsFailed() [member function] + cls.add_method('DoReportFinalRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::DoReportFinalDataFailed() [member function] + cls.add_method('DoReportFinalDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## arf-wifi-manager.h: uint32_t ns3::ArfWifiRemoteStation::GetMinTimerTimeout() [member function] + cls.add_method('GetMinTimerTimeout', + 'uint32_t', + [], + visibility='protected') + ## arf-wifi-manager.h: uint32_t ns3::ArfWifiRemoteStation::GetMinSuccessThreshold() [member function] + cls.add_method('GetMinSuccessThreshold', + 'uint32_t', + [], + visibility='protected') + ## arf-wifi-manager.h: uint32_t ns3::ArfWifiRemoteStation::GetTimerTimeout() [member function] + cls.add_method('GetTimerTimeout', + 'uint32_t', + [], + visibility='protected') + ## arf-wifi-manager.h: uint32_t ns3::ArfWifiRemoteStation::GetSuccessThreshold() [member function] + cls.add_method('GetSuccessThreshold', + 'uint32_t', + [], + visibility='protected') + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::SetTimerTimeout(uint32_t timerTimeout) [member function] + cls.add_method('SetTimerTimeout', + 'void', + [param('uint32_t', 'timerTimeout')], + visibility='protected') + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::SetSuccessThreshold(uint32_t successThreshold) [member function] + cls.add_method('SetSuccessThreshold', + 'void', + [param('uint32_t', 'successThreshold')], + visibility='protected') + ## arf-wifi-manager.h: ns3::Ptr ns3::ArfWifiRemoteStation::GetManager() const [member function] + cls.add_method('GetManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_const=True, visibility='private', is_virtual=True) + ## arf-wifi-manager.h: ns3::WifiMode ns3::ArfWifiRemoteStation::DoGetDataMode(uint32_t size) [member function] + cls.add_method('DoGetDataMode', + 'ns3::WifiMode', + [param('uint32_t', 'size')], + visibility='private', is_virtual=True) + ## arf-wifi-manager.h: ns3::WifiMode ns3::ArfWifiRemoteStation::DoGetRtsMode() [member function] + cls.add_method('DoGetRtsMode', + 'ns3::WifiMode', + [], + visibility='private', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::ReportRecoveryFailure() [member function] + cls.add_method('ReportRecoveryFailure', + 'void', + [], + visibility='private', is_virtual=True) + ## arf-wifi-manager.h: void ns3::ArfWifiRemoteStation::ReportFailure() [member function] + cls.add_method('ReportFailure', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3ConstantRateWifiRemoteStation_methods(root_module, cls): + ## constant-rate-wifi-manager.h: ns3::ConstantRateWifiRemoteStation::ConstantRateWifiRemoteStation(ns3::ConstantRateWifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ConstantRateWifiRemoteStation const &', 'arg0')]) + ## constant-rate-wifi-manager.h: ns3::ConstantRateWifiRemoteStation::ConstantRateWifiRemoteStation(ns3::Ptr stations) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::ConstantRateWifiManager >', 'stations')]) + ## constant-rate-wifi-manager.h: void ns3::ConstantRateWifiRemoteStation::DoReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('DoReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')], + visibility='protected', is_virtual=True) + ## constant-rate-wifi-manager.h: void ns3::ConstantRateWifiRemoteStation::DoReportRtsFailed() [member function] + cls.add_method('DoReportRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## constant-rate-wifi-manager.h: void ns3::ConstantRateWifiRemoteStation::DoReportDataFailed() [member function] + cls.add_method('DoReportDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## constant-rate-wifi-manager.h: void ns3::ConstantRateWifiRemoteStation::DoReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('DoReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')], + visibility='protected', is_virtual=True) + ## constant-rate-wifi-manager.h: void ns3::ConstantRateWifiRemoteStation::DoReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('DoReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')], + visibility='protected', is_virtual=True) + ## constant-rate-wifi-manager.h: void ns3::ConstantRateWifiRemoteStation::DoReportFinalRtsFailed() [member function] + cls.add_method('DoReportFinalRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## constant-rate-wifi-manager.h: void ns3::ConstantRateWifiRemoteStation::DoReportFinalDataFailed() [member function] + cls.add_method('DoReportFinalDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## constant-rate-wifi-manager.h: ns3::Ptr ns3::ConstantRateWifiRemoteStation::GetManager() const [member function] + cls.add_method('GetManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_const=True, visibility='private', is_virtual=True) + ## constant-rate-wifi-manager.h: ns3::WifiMode ns3::ConstantRateWifiRemoteStation::DoGetDataMode(uint32_t size) [member function] + cls.add_method('DoGetDataMode', + 'ns3::WifiMode', + [param('uint32_t', 'size')], + visibility='private', is_virtual=True) + ## constant-rate-wifi-manager.h: ns3::WifiMode ns3::ConstantRateWifiRemoteStation::DoGetRtsMode() [member function] + cls.add_method('DoGetRtsMode', + 'ns3::WifiMode', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3IdealWifiRemoteStation_methods(root_module, cls): + ## ideal-wifi-manager.h: ns3::IdealWifiRemoteStation::IdealWifiRemoteStation(ns3::IdealWifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IdealWifiRemoteStation const &', 'arg0')]) + ## ideal-wifi-manager.h: ns3::IdealWifiRemoteStation::IdealWifiRemoteStation(ns3::Ptr stations) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::IdealWifiManager >', 'stations')]) + ## ideal-wifi-manager.h: void ns3::IdealWifiRemoteStation::DoReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('DoReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')], + visibility='protected', is_virtual=True) + ## ideal-wifi-manager.h: void ns3::IdealWifiRemoteStation::DoReportRtsFailed() [member function] + cls.add_method('DoReportRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## ideal-wifi-manager.h: void ns3::IdealWifiRemoteStation::DoReportDataFailed() [member function] + cls.add_method('DoReportDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## ideal-wifi-manager.h: void ns3::IdealWifiRemoteStation::DoReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('DoReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')], + visibility='protected', is_virtual=True) + ## ideal-wifi-manager.h: void ns3::IdealWifiRemoteStation::DoReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('DoReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')], + visibility='protected', is_virtual=True) + ## ideal-wifi-manager.h: void ns3::IdealWifiRemoteStation::DoReportFinalRtsFailed() [member function] + cls.add_method('DoReportFinalRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## ideal-wifi-manager.h: void ns3::IdealWifiRemoteStation::DoReportFinalDataFailed() [member function] + cls.add_method('DoReportFinalDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## ideal-wifi-manager.h: ns3::Ptr ns3::IdealWifiRemoteStation::GetManager() const [member function] + cls.add_method('GetManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_const=True, visibility='private', is_virtual=True) + ## ideal-wifi-manager.h: ns3::WifiMode ns3::IdealWifiRemoteStation::DoGetDataMode(uint32_t size) [member function] + cls.add_method('DoGetDataMode', + 'ns3::WifiMode', + [param('uint32_t', 'size')], + visibility='private', is_virtual=True) + ## ideal-wifi-manager.h: ns3::WifiMode ns3::IdealWifiRemoteStation::DoGetRtsMode() [member function] + cls.add_method('DoGetRtsMode', + 'ns3::WifiMode', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3OnoeWifiRemoteStation_methods(root_module, cls): + ## onoe-wifi-manager.h: ns3::OnoeWifiRemoteStation::OnoeWifiRemoteStation(ns3::OnoeWifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::OnoeWifiRemoteStation const &', 'arg0')]) + ## onoe-wifi-manager.h: ns3::OnoeWifiRemoteStation::OnoeWifiRemoteStation(ns3::Ptr stations) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::OnoeWifiManager >', 'stations')]) + ## onoe-wifi-manager.h: void ns3::OnoeWifiRemoteStation::DoReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('DoReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')], + visibility='protected', is_virtual=True) + ## onoe-wifi-manager.h: void ns3::OnoeWifiRemoteStation::DoReportRtsFailed() [member function] + cls.add_method('DoReportRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## onoe-wifi-manager.h: void ns3::OnoeWifiRemoteStation::DoReportDataFailed() [member function] + cls.add_method('DoReportDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## onoe-wifi-manager.h: void ns3::OnoeWifiRemoteStation::DoReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('DoReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')], + visibility='protected', is_virtual=True) + ## onoe-wifi-manager.h: void ns3::OnoeWifiRemoteStation::DoReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('DoReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')], + visibility='protected', is_virtual=True) + ## onoe-wifi-manager.h: void ns3::OnoeWifiRemoteStation::DoReportFinalRtsFailed() [member function] + cls.add_method('DoReportFinalRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## onoe-wifi-manager.h: void ns3::OnoeWifiRemoteStation::DoReportFinalDataFailed() [member function] + cls.add_method('DoReportFinalDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## onoe-wifi-manager.h: ns3::Ptr ns3::OnoeWifiRemoteStation::GetManager() const [member function] + cls.add_method('GetManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_const=True, visibility='private', is_virtual=True) + ## onoe-wifi-manager.h: ns3::WifiMode ns3::OnoeWifiRemoteStation::DoGetDataMode(uint32_t size) [member function] + cls.add_method('DoGetDataMode', + 'ns3::WifiMode', + [param('uint32_t', 'size')], + visibility='private', is_virtual=True) + ## onoe-wifi-manager.h: ns3::WifiMode ns3::OnoeWifiRemoteStation::DoGetRtsMode() [member function] + cls.add_method('DoGetRtsMode', + 'ns3::WifiMode', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3PropagationDelayModel_methods(root_module, cls): + ## propagation-delay-model.h: ns3::PropagationDelayModel::PropagationDelayModel(ns3::PropagationDelayModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PropagationDelayModel const &', 'arg0')]) + ## propagation-delay-model.h: ns3::PropagationDelayModel::PropagationDelayModel() [constructor] + cls.add_constructor([]) + ## propagation-delay-model.h: static ns3::TypeId ns3::PropagationDelayModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## propagation-delay-model.h: ns3::Time ns3::PropagationDelayModel::GetDelay(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetDelay', + 'ns3::Time', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3PropagationLossModel_methods(root_module, cls): + ## propagation-loss-model.h: ns3::PropagationLossModel::PropagationLossModel(ns3::PropagationLossModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::PropagationLossModel const &', 'arg0')]) + ## propagation-loss-model.h: ns3::PropagationLossModel::PropagationLossModel() [constructor] + cls.add_constructor([]) + ## propagation-loss-model.h: static ns3::TypeId ns3::PropagationLossModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## propagation-loss-model.h: double ns3::PropagationLossModel::GetLoss(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetLoss', + 'double', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3RandomPropagationDelayModel_methods(root_module, cls): + ## propagation-delay-model.h: ns3::RandomPropagationDelayModel::RandomPropagationDelayModel(ns3::RandomPropagationDelayModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomPropagationDelayModel const &', 'arg0')]) + ## propagation-delay-model.h: static ns3::TypeId ns3::RandomPropagationDelayModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## propagation-delay-model.h: ns3::RandomPropagationDelayModel::RandomPropagationDelayModel() [constructor] + cls.add_constructor([]) + ## propagation-delay-model.h: ns3::Time ns3::RandomPropagationDelayModel::GetDelay(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetDelay', + 'ns3::Time', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_const=True, is_virtual=True) + return + +def register_Ns3RandomPropagationLossModel_methods(root_module, cls): + ## propagation-loss-model.h: ns3::RandomPropagationLossModel::RandomPropagationLossModel(ns3::RandomPropagationLossModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RandomPropagationLossModel const &', 'arg0')]) + ## propagation-loss-model.h: static ns3::TypeId ns3::RandomPropagationLossModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## propagation-loss-model.h: ns3::RandomPropagationLossModel::RandomPropagationLossModel() [constructor] + cls.add_constructor([]) + ## propagation-loss-model.h: double ns3::RandomPropagationLossModel::GetLoss(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetLoss', + 'double', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_const=True, is_virtual=True) + return + +def register_Ns3RraaWifiRemoteStation_methods(root_module, cls): + ## rraa-wifi-manager.h: ns3::RraaWifiRemoteStation::RraaWifiRemoteStation(ns3::RraaWifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RraaWifiRemoteStation const &', 'arg0')]) + ## rraa-wifi-manager.h: ns3::RraaWifiRemoteStation::RraaWifiRemoteStation(ns3::Ptr stations) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::RraaWifiManager >', 'stations')]) + ## rraa-wifi-manager.h: bool ns3::RraaWifiRemoteStation::NeedRts(ns3::Ptr packet) [member function] + cls.add_method('NeedRts', + 'bool', + [param('ns3::Ptr< ns3::Packet const >', 'packet')], + is_virtual=True) + ## rraa-wifi-manager.h: void ns3::RraaWifiRemoteStation::DoReportRxOk(double rxSnr, ns3::WifiMode txMode) [member function] + cls.add_method('DoReportRxOk', + 'void', + [param('double', 'rxSnr'), param('ns3::WifiMode', 'txMode')], + visibility='protected', is_virtual=True) + ## rraa-wifi-manager.h: void ns3::RraaWifiRemoteStation::DoReportRtsFailed() [member function] + cls.add_method('DoReportRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## rraa-wifi-manager.h: void ns3::RraaWifiRemoteStation::DoReportDataFailed() [member function] + cls.add_method('DoReportDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## rraa-wifi-manager.h: void ns3::RraaWifiRemoteStation::DoReportRtsOk(double ctsSnr, ns3::WifiMode ctsMode, double rtsSnr) [member function] + cls.add_method('DoReportRtsOk', + 'void', + [param('double', 'ctsSnr'), param('ns3::WifiMode', 'ctsMode'), param('double', 'rtsSnr')], + visibility='protected', is_virtual=True) + ## rraa-wifi-manager.h: void ns3::RraaWifiRemoteStation::DoReportDataOk(double ackSnr, ns3::WifiMode ackMode, double dataSnr) [member function] + cls.add_method('DoReportDataOk', + 'void', + [param('double', 'ackSnr'), param('ns3::WifiMode', 'ackMode'), param('double', 'dataSnr')], + visibility='protected', is_virtual=True) + ## rraa-wifi-manager.h: void ns3::RraaWifiRemoteStation::DoReportFinalRtsFailed() [member function] + cls.add_method('DoReportFinalRtsFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## rraa-wifi-manager.h: void ns3::RraaWifiRemoteStation::DoReportFinalDataFailed() [member function] + cls.add_method('DoReportFinalDataFailed', + 'void', + [], + visibility='protected', is_virtual=True) + ## rraa-wifi-manager.h: ns3::Ptr ns3::RraaWifiRemoteStation::GetManager() const [member function] + cls.add_method('GetManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_const=True, visibility='private', is_virtual=True) + ## rraa-wifi-manager.h: ns3::WifiMode ns3::RraaWifiRemoteStation::DoGetDataMode(uint32_t size) [member function] + cls.add_method('DoGetDataMode', + 'ns3::WifiMode', + [param('uint32_t', 'size')], + visibility='private', is_virtual=True) + ## rraa-wifi-manager.h: ns3::WifiMode ns3::RraaWifiRemoteStation::DoGetRtsMode() [member function] + cls.add_method('DoGetRtsMode', + 'ns3::WifiMode', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3SsidChecker_methods(root_module, cls): + ## ssid.h: ns3::SsidChecker::SsidChecker(ns3::SsidChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SsidChecker const &', 'arg0')]) + ## ssid.h: ns3::SsidChecker::SsidChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3SsidValue_methods(root_module, cls): + ## ssid.h: ns3::SsidValue::SsidValue(ns3::SsidValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::SsidValue const &', 'arg0')]) + ## ssid.h: ns3::SsidValue::SsidValue() [constructor] + cls.add_constructor([]) + ## ssid.h: ns3::SsidValue::SsidValue(ns3::Ssid const & value) [constructor] + cls.add_constructor([param('ns3::Ssid const &', 'value')]) + ## ssid.h: void ns3::SsidValue::Set(ns3::Ssid const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::Ssid const &', 'value')]) + ## ssid.h: ns3::Ssid ns3::SsidValue::Get() const [member function] + cls.add_method('Get', + 'ns3::Ssid', + [], + is_const=True) + ## ssid.h: ns3::Ptr ns3::SsidValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## ssid.h: std::string ns3::SsidValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## ssid.h: bool ns3::SsidValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3WifiMac_methods(root_module, cls): + ## wifi-mac.h: ns3::WifiMac::WifiMac(ns3::WifiMac const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiMac const &', 'arg0')]) + ## wifi-mac.h: ns3::WifiMac::WifiMac() [constructor] + cls.add_constructor([]) + ## wifi-mac.h: static ns3::TypeId ns3::WifiMac::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## wifi-mac.h: void ns3::WifiMac::SetSlot(ns3::Time slotTime) [member function] + cls.add_method('SetSlot', + 'void', + [param('ns3::Time', 'slotTime')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetSifs(ns3::Time sifs) [member function] + cls.add_method('SetSifs', + 'void', + [param('ns3::Time', 'sifs')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetEifsNoDifs(ns3::Time eifsNoDifs) [member function] + cls.add_method('SetEifsNoDifs', + 'void', + [param('ns3::Time', 'eifsNoDifs')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetPifs(ns3::Time pifs) [member function] + cls.add_method('SetPifs', + 'void', + [param('ns3::Time', 'pifs')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetCtsTimeout(ns3::Time ctsTimeout) [member function] + cls.add_method('SetCtsTimeout', + 'void', + [param('ns3::Time', 'ctsTimeout')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetAckTimeout(ns3::Time ackTimeout) [member function] + cls.add_method('SetAckTimeout', + 'void', + [param('ns3::Time', 'ackTimeout')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetMaxPropagationDelay(ns3::Time delay) [member function] + cls.add_method('SetMaxPropagationDelay', + 'void', + [param('ns3::Time', 'delay')]) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetPifs() const [member function] + cls.add_method('GetPifs', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetSifs() const [member function] + cls.add_method('GetSifs', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetSlot() const [member function] + cls.add_method('GetSlot', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetEifsNoDifs() const [member function] + cls.add_method('GetEifsNoDifs', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetCtsTimeout() const [member function] + cls.add_method('GetCtsTimeout', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetAckTimeout() const [member function] + cls.add_method('GetAckTimeout', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetMsduLifetime() const [member function] + cls.add_method('GetMsduLifetime', + 'ns3::Time', + [], + is_const=True) + ## wifi-mac.h: ns3::Time ns3::WifiMac::GetMaxPropagationDelay() const [member function] + cls.add_method('GetMaxPropagationDelay', + 'ns3::Time', + [], + is_const=True) + ## wifi-mac.h: uint32_t ns3::WifiMac::GetMaxMsduSize() const [member function] + cls.add_method('GetMaxMsduSize', + 'uint32_t', + [], + is_const=True) + ## wifi-mac.h: ns3::Mac48Address ns3::WifiMac::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Mac48Address', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: ns3::Ssid ns3::WifiMac::GetSsid() const [member function] + cls.add_method('GetSsid', + 'ns3::Ssid', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetAddress(ns3::Mac48Address address) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Mac48Address', 'address')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetSsid(ns3::Ssid ssid) [member function] + cls.add_method('SetSsid', + 'void', + [param('ns3::Ssid', 'ssid')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: ns3::Mac48Address ns3::WifiMac::GetBssid() const [member function] + cls.add_method('GetBssid', + 'ns3::Mac48Address', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to, ns3::Mac48Address from) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to'), param('ns3::Mac48Address', 'from')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: bool ns3::WifiMac::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetWifiPhy(ns3::Ptr phy) [member function] + cls.add_method('SetWifiPhy', + 'void', + [param('ns3::Ptr< ns3::WifiPhy >', 'phy')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetWifiRemoteStationManager(ns3::Ptr stationManager) [member function] + cls.add_method('SetWifiRemoteStationManager', + 'void', + [param('ns3::Ptr< ns3::WifiRemoteStationManager >', 'stationManager')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetForwardUpCallback(ns3::Callback, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty> upCallback) [member function] + cls.add_method('SetForwardUpCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty >', 'upCallback')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetLinkUpCallback(ns3::Callback linkUp) [member function] + cls.add_method('SetLinkUpCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkUp')], + is_pure_virtual=True, is_virtual=True) + ## wifi-mac.h: void ns3::WifiMac::SetLinkDownCallback(ns3::Callback linkDown) [member function] + cls.add_method('SetLinkDownCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkDown')], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3WifiModeChecker_methods(root_module, cls): + ## wifi-mode.h: ns3::WifiModeChecker::WifiModeChecker(ns3::WifiModeChecker const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiModeChecker const &', 'arg0')]) + ## wifi-mode.h: ns3::WifiModeChecker::WifiModeChecker() [constructor] + cls.add_constructor([]) + return + +def register_Ns3WifiModeValue_methods(root_module, cls): + ## wifi-mode.h: ns3::WifiModeValue::WifiModeValue(ns3::WifiModeValue const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiModeValue const &', 'arg0')]) + ## wifi-mode.h: ns3::WifiModeValue::WifiModeValue() [constructor] + cls.add_constructor([]) + ## wifi-mode.h: ns3::WifiModeValue::WifiModeValue(ns3::WifiMode const & value) [constructor] + cls.add_constructor([param('ns3::WifiMode const &', 'value')]) + ## wifi-mode.h: void ns3::WifiModeValue::Set(ns3::WifiMode const & value) [member function] + cls.add_method('Set', + 'void', + [param('ns3::WifiMode const &', 'value')]) + ## wifi-mode.h: ns3::WifiMode ns3::WifiModeValue::Get() const [member function] + cls.add_method('Get', + 'ns3::WifiMode', + [], + is_const=True) + ## wifi-mode.h: ns3::Ptr ns3::WifiModeValue::Copy() const [member function] + cls.add_method('Copy', + 'ns3::Ptr< ns3::AttributeValue >', + [], + is_const=True, is_virtual=True) + ## wifi-mode.h: std::string ns3::WifiModeValue::SerializeToString(ns3::Ptr checker) const [member function] + cls.add_method('SerializeToString', + 'std::string', + [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_const=True, is_virtual=True) + ## wifi-mode.h: bool ns3::WifiModeValue::DeserializeFromString(std::string value, ns3::Ptr checker) [member function] + cls.add_method('DeserializeFromString', + 'bool', + [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], + is_virtual=True) + return + +def register_Ns3WifiPhy_methods(root_module, cls): + ## wifi-phy.h: ns3::WifiPhy::g_6mba [variable] + cls.add_static_attribute('g_6mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::g_9mba [variable] + cls.add_static_attribute('g_9mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::g_12mba [variable] + cls.add_static_attribute('g_12mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::g_18mba [variable] + cls.add_static_attribute('g_18mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::g_24mba [variable] + cls.add_static_attribute('g_24mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::g_36mba [variable] + cls.add_static_attribute('g_36mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::g_48mba [variable] + cls.add_static_attribute('g_48mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::g_54mba [variable] + cls.add_static_attribute('g_54mba', 'ns3::WifiMode', is_const=False) + ## wifi-phy.h: ns3::WifiPhy::WifiPhy(ns3::WifiPhy const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiPhy const &', 'arg0')]) + ## wifi-phy.h: static ns3::TypeId ns3::WifiPhy::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## wifi-phy.h: ns3::WifiPhy::WifiPhy() [constructor] + cls.add_constructor([]) + ## wifi-phy.h: double ns3::WifiPhy::GetTxPowerStart() const [member function] + cls.add_method('GetTxPowerStart', + 'double', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: double ns3::WifiPhy::GetTxPowerEnd() const [member function] + cls.add_method('GetTxPowerEnd', + 'double', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: uint32_t ns3::WifiPhy::GetNTxPower() const [member function] + cls.add_method('GetNTxPower', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhy::SetReceiveOkCallback(ns3::Callback,double,ns3::WifiMode,ns3::WifiPreamble,ns3::empty,ns3::empty> callback) [member function] + cls.add_method('SetReceiveOkCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet >, double, ns3::WifiMode, ns3::WifiPreamble, ns3::empty, ns3::empty >', 'callback')], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhy::SetReceiveErrorCallback(ns3::Callback,double,ns3::empty,ns3::empty,ns3::empty,ns3::empty> callback) [member function] + cls.add_method('SetReceiveErrorCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, double, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhy::SendPacket(ns3::Ptr packet, ns3::WifiMode mode, ns3::WifiPreamble preamble, uint8_t txPowerLevel) [member function] + cls.add_method('SendPacket', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::WifiMode', 'mode'), param('ns3::WifiPreamble', 'preamble'), param('uint8_t', 'txPowerLevel')], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: void ns3::WifiPhy::RegisterListener(ns3::WifiPhyListener * listener) [member function] + cls.add_method('RegisterListener', + 'void', + [param('ns3::WifiPhyListener *', 'listener')], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: bool ns3::WifiPhy::IsStateCcaBusy() [member function] + cls.add_method('IsStateCcaBusy', + 'bool', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: bool ns3::WifiPhy::IsStateIdle() [member function] + cls.add_method('IsStateIdle', + 'bool', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: bool ns3::WifiPhy::IsStateBusy() [member function] + cls.add_method('IsStateBusy', + 'bool', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: bool ns3::WifiPhy::IsStateSync() [member function] + cls.add_method('IsStateSync', + 'bool', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: bool ns3::WifiPhy::IsStateTx() [member function] + cls.add_method('IsStateTx', + 'bool', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: ns3::Time ns3::WifiPhy::GetStateDuration() [member function] + cls.add_method('GetStateDuration', + 'ns3::Time', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: ns3::Time ns3::WifiPhy::GetDelayUntilIdle() [member function] + cls.add_method('GetDelayUntilIdle', + 'ns3::Time', + [], + is_pure_virtual=True, is_virtual=True) + ## wifi-phy.h: ns3::Time ns3::WifiPhy::GetLastRxStartTime() const [member function] + cls.add_method('GetLastRxStartTime', + 'ns3::Time', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: ns3::Time ns3::WifiPhy::CalculateTxDuration(uint32_t size, ns3::WifiMode payloadMode, ns3::WifiPreamble preamble) const [member function] + cls.add_method('CalculateTxDuration', + 'ns3::Time', + [param('uint32_t', 'size'), param('ns3::WifiMode', 'payloadMode'), param('ns3::WifiPreamble', 'preamble')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: uint32_t ns3::WifiPhy::GetNModes() const [member function] + cls.add_method('GetNModes', + 'uint32_t', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: ns3::WifiMode ns3::WifiPhy::GetMode(uint32_t mode) const [member function] + cls.add_method('GetMode', + 'ns3::WifiMode', + [param('uint32_t', 'mode')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: double ns3::WifiPhy::CalculateSnr(ns3::WifiMode txMode, double ber) const [member function] + cls.add_method('CalculateSnr', + 'double', + [param('ns3::WifiMode', 'txMode'), param('double', 'ber')], + is_pure_virtual=True, is_const=True, is_virtual=True) + ## wifi-phy.h: ns3::Ptr ns3::WifiPhy::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::WifiChannel >', + [], + is_pure_virtual=True, is_const=True, is_virtual=True) + return + +def register_Ns3WifiRemoteStationManager_methods(root_module, cls): + ## wifi-remote-station-manager.h: ns3::WifiRemoteStationManager::WifiRemoteStationManager(ns3::WifiRemoteStationManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiRemoteStationManager const &', 'arg0')]) + ## wifi-remote-station-manager.h: static ns3::TypeId ns3::WifiRemoteStationManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## wifi-remote-station-manager.h: ns3::WifiRemoteStationManager::WifiRemoteStationManager() [constructor] + cls.add_constructor([]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::SetupPhy(ns3::Ptr phy) [member function] + cls.add_method('SetupPhy', + 'void', + [param('ns3::Ptr< ns3::WifiPhy >', 'phy')], + is_virtual=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStationManager::GetMaxSsrc() const [member function] + cls.add_method('GetMaxSsrc', + 'uint32_t', + [], + is_const=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStationManager::GetMaxSlrc() const [member function] + cls.add_method('GetMaxSlrc', + 'uint32_t', + [], + is_const=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStationManager::GetRtsCtsThreshold() const [member function] + cls.add_method('GetRtsCtsThreshold', + 'uint32_t', + [], + is_const=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStationManager::GetFragmentationThreshold() const [member function] + cls.add_method('GetFragmentationThreshold', + 'uint32_t', + [], + is_const=True) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::SetMaxSsrc(uint32_t maxSsrc) [member function] + cls.add_method('SetMaxSsrc', + 'void', + [param('uint32_t', 'maxSsrc')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::SetMaxSlrc(uint32_t maxSlrc) [member function] + cls.add_method('SetMaxSlrc', + 'void', + [param('uint32_t', 'maxSlrc')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::SetRtsCtsThreshold(uint32_t threshold) [member function] + cls.add_method('SetRtsCtsThreshold', + 'void', + [param('uint32_t', 'threshold')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::SetFragmentationThreshold(uint32_t threshold) [member function] + cls.add_method('SetFragmentationThreshold', + 'void', + [param('uint32_t', 'threshold')]) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::Reset() [member function] + cls.add_method('Reset', + 'void', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::AddBasicMode(ns3::WifiMode mode) [member function] + cls.add_method('AddBasicMode', + 'void', + [param('ns3::WifiMode', 'mode')]) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStationManager::GetDefaultMode() const [member function] + cls.add_method('GetDefaultMode', + 'ns3::WifiMode', + [], + is_const=True) + ## wifi-remote-station-manager.h: uint32_t ns3::WifiRemoteStationManager::GetNBasicModes() const [member function] + cls.add_method('GetNBasicModes', + 'uint32_t', + [], + is_const=True) + ## wifi-remote-station-manager.h: ns3::WifiMode ns3::WifiRemoteStationManager::GetBasicMode(uint32_t i) const [member function] + cls.add_method('GetBasicMode', + 'ns3::WifiMode', + [param('uint32_t', 'i')], + is_const=True) + ## wifi-remote-station-manager.h: __gnu_cxx::__normal_iterator > > ns3::WifiRemoteStationManager::BeginBasicModes() const [member function] + cls.add_method('BeginBasicModes', + '__gnu_cxx::__normal_iterator< ns3::WifiMode const *, std::vector< ns3::WifiMode > >', + [], + is_const=True) + ## wifi-remote-station-manager.h: __gnu_cxx::__normal_iterator > > ns3::WifiRemoteStationManager::EndBasicModes() const [member function] + cls.add_method('EndBasicModes', + '__gnu_cxx::__normal_iterator< ns3::WifiMode const *, std::vector< ns3::WifiMode > >', + [], + is_const=True) + ## wifi-remote-station-manager.h: bool ns3::WifiRemoteStationManager::IsLowLatency() const [member function] + cls.add_method('IsLowLatency', + 'bool', + [], + is_const=True) + ## wifi-remote-station-manager.h: ns3::WifiRemoteStation * ns3::WifiRemoteStationManager::Lookup(ns3::Mac48Address address) [member function] + cls.add_method('Lookup', + 'ns3::WifiRemoteStation *', + [param('ns3::Mac48Address', 'address')]) + ## wifi-remote-station-manager.h: ns3::WifiRemoteStation * ns3::WifiRemoteStationManager::LookupNonUnicast() [member function] + cls.add_method('LookupNonUnicast', + 'ns3::WifiRemoteStation *', + []) + ## wifi-remote-station-manager.h: void ns3::WifiRemoteStationManager::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='protected', is_virtual=True) + ## wifi-remote-station-manager.h: ns3::WifiRemoteStation * ns3::WifiRemoteStationManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + is_pure_virtual=True, visibility='private', is_virtual=True) + return + +def register_Ns3YansWifiPhy_methods(root_module, cls): + ## yans-wifi-phy.h: static ns3::TypeId ns3::YansWifiPhy::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## yans-wifi-phy.h: ns3::YansWifiPhy::YansWifiPhy() [constructor] + cls.add_constructor([]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetChannel(ns3::Ptr channel) [member function] + cls.add_method('SetChannel', + 'void', + [param('ns3::Ptr< ns3::YansWifiChannel >', 'channel')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::StartReceivePacket(ns3::Ptr packet, double rxPowerDbm, ns3::WifiMode mode, ns3::WifiPreamble preamble) [member function] + cls.add_method('StartReceivePacket', + 'void', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('double', 'rxPowerDbm'), param('ns3::WifiMode', 'mode'), param('ns3::WifiPreamble', 'preamble')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetStandard(ns3::WifiPhyStandard standard) [member function] + cls.add_method('SetStandard', + 'void', + [param('ns3::WifiPhyStandard', 'standard')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetRxNoise(double ratio) [member function] + cls.add_method('SetRxNoise', + 'void', + [param('double', 'ratio')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetTxPowerStart(double start) [member function] + cls.add_method('SetTxPowerStart', + 'void', + [param('double', 'start')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetTxPowerEnd(double end) [member function] + cls.add_method('SetTxPowerEnd', + 'void', + [param('double', 'end')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetNTxPower(uint32_t n) [member function] + cls.add_method('SetNTxPower', + 'void', + [param('uint32_t', 'n')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetTxGain(double gain) [member function] + cls.add_method('SetTxGain', + 'void', + [param('double', 'gain')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetRxGain(double gain) [member function] + cls.add_method('SetRxGain', + 'void', + [param('double', 'gain')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetEdThreshold(double threshold) [member function] + cls.add_method('SetEdThreshold', + 'void', + [param('double', 'threshold')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetCcaMode1Threshold(double threshold) [member function] + cls.add_method('SetCcaMode1Threshold', + 'void', + [param('double', 'threshold')]) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetErrorRateModel(ns3::Ptr rate) [member function] + cls.add_method('SetErrorRateModel', + 'void', + [param('ns3::Ptr< ns3::ErrorRateModel >', 'rate')]) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::GetRxNoise() const [member function] + cls.add_method('GetRxNoise', + 'double', + [], + is_const=True) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::GetTxGain() const [member function] + cls.add_method('GetTxGain', + 'double', + [], + is_const=True) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::GetRxGain() const [member function] + cls.add_method('GetRxGain', + 'double', + [], + is_const=True) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::GetEdThreshold() const [member function] + cls.add_method('GetEdThreshold', + 'double', + [], + is_const=True) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::GetCcaMode1Threshold() const [member function] + cls.add_method('GetCcaMode1Threshold', + 'double', + [], + is_const=True) + ## yans-wifi-phy.h: ns3::Ptr ns3::YansWifiPhy::GetErrorRateModel() const [member function] + cls.add_method('GetErrorRateModel', + 'ns3::Ptr< ns3::ErrorRateModel >', + [], + is_const=True) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::GetTxPowerStart() const [member function] + cls.add_method('GetTxPowerStart', + 'double', + [], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::GetTxPowerEnd() const [member function] + cls.add_method('GetTxPowerEnd', + 'double', + [], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: uint32_t ns3::YansWifiPhy::GetNTxPower() const [member function] + cls.add_method('GetNTxPower', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetReceiveOkCallback(ns3::Callback,double,ns3::WifiMode,ns3::WifiPreamble,ns3::empty,ns3::empty> callback) [member function] + cls.add_method('SetReceiveOkCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet >, double, ns3::WifiMode, ns3::WifiPreamble, ns3::empty, ns3::empty >', 'callback')], + is_virtual=True) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SetReceiveErrorCallback(ns3::Callback,double,ns3::empty,ns3::empty,ns3::empty,ns3::empty> callback) [member function] + cls.add_method('SetReceiveErrorCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet const >, double, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_virtual=True) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::SendPacket(ns3::Ptr packet, ns3::WifiMode mode, ns3::WifiPreamble preamble, uint8_t txPowerLevel) [member function] + cls.add_method('SendPacket', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::WifiMode', 'mode'), param('ns3::WifiPreamble', 'preamble'), param('uint8_t', 'txPowerLevel')], + is_virtual=True) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::RegisterListener(ns3::WifiPhyListener * listener) [member function] + cls.add_method('RegisterListener', + 'void', + [param('ns3::WifiPhyListener *', 'listener')], + is_virtual=True) + ## yans-wifi-phy.h: bool ns3::YansWifiPhy::IsStateCcaBusy() [member function] + cls.add_method('IsStateCcaBusy', + 'bool', + [], + is_virtual=True) + ## yans-wifi-phy.h: bool ns3::YansWifiPhy::IsStateIdle() [member function] + cls.add_method('IsStateIdle', + 'bool', + [], + is_virtual=True) + ## yans-wifi-phy.h: bool ns3::YansWifiPhy::IsStateBusy() [member function] + cls.add_method('IsStateBusy', + 'bool', + [], + is_virtual=True) + ## yans-wifi-phy.h: bool ns3::YansWifiPhy::IsStateSync() [member function] + cls.add_method('IsStateSync', + 'bool', + [], + is_virtual=True) + ## yans-wifi-phy.h: bool ns3::YansWifiPhy::IsStateTx() [member function] + cls.add_method('IsStateTx', + 'bool', + [], + is_virtual=True) + ## yans-wifi-phy.h: ns3::Time ns3::YansWifiPhy::GetStateDuration() [member function] + cls.add_method('GetStateDuration', + 'ns3::Time', + [], + is_virtual=True) + ## yans-wifi-phy.h: ns3::Time ns3::YansWifiPhy::GetDelayUntilIdle() [member function] + cls.add_method('GetDelayUntilIdle', + 'ns3::Time', + [], + is_virtual=True) + ## yans-wifi-phy.h: ns3::Time ns3::YansWifiPhy::GetLastRxStartTime() const [member function] + cls.add_method('GetLastRxStartTime', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: ns3::Time ns3::YansWifiPhy::CalculateTxDuration(uint32_t size, ns3::WifiMode payloadMode, ns3::WifiPreamble preamble) const [member function] + cls.add_method('CalculateTxDuration', + 'ns3::Time', + [param('uint32_t', 'size'), param('ns3::WifiMode', 'payloadMode'), param('ns3::WifiPreamble', 'preamble')], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: uint32_t ns3::YansWifiPhy::GetNModes() const [member function] + cls.add_method('GetNModes', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: ns3::WifiMode ns3::YansWifiPhy::GetMode(uint32_t mode) const [member function] + cls.add_method('GetMode', + 'ns3::WifiMode', + [param('uint32_t', 'mode')], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: double ns3::YansWifiPhy::CalculateSnr(ns3::WifiMode txMode, double ber) const [member function] + cls.add_method('CalculateSnr', + 'double', + [param('ns3::WifiMode', 'txMode'), param('double', 'ber')], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: ns3::Ptr ns3::YansWifiPhy::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::WifiChannel >', + [], + is_const=True, is_virtual=True) + ## yans-wifi-phy.h: void ns3::YansWifiPhy::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3AarfWifiRemoteStation_methods(root_module, cls): + ## aarf-wifi-manager.h: ns3::AarfWifiRemoteStation::AarfWifiRemoteStation(ns3::AarfWifiRemoteStation const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AarfWifiRemoteStation const &', 'arg0')]) + ## aarf-wifi-manager.h: ns3::AarfWifiRemoteStation::AarfWifiRemoteStation(ns3::Ptr stations, uint32_t minTimerThreshold, uint32_t minSuccessThreshold, double successK, uint32_t maxSuccessThreshold, double timerK) [constructor] + cls.add_constructor([param('ns3::Ptr< ns3::AarfWifiManager >', 'stations'), param('uint32_t', 'minTimerThreshold'), param('uint32_t', 'minSuccessThreshold'), param('double', 'successK'), param('uint32_t', 'maxSuccessThreshold'), param('double', 'timerK')]) + ## aarf-wifi-manager.h: void ns3::AarfWifiRemoteStation::ReportRecoveryFailure() [member function] + cls.add_method('ReportRecoveryFailure', + 'void', + [], + visibility='private', is_virtual=True) + ## aarf-wifi-manager.h: void ns3::AarfWifiRemoteStation::ReportFailure() [member function] + cls.add_method('ReportFailure', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3AdhocWifiMac_methods(root_module, cls): + ## adhoc-wifi-mac.h: static ns3::TypeId ns3::AdhocWifiMac::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## adhoc-wifi-mac.h: ns3::AdhocWifiMac::AdhocWifiMac() [constructor] + cls.add_constructor([]) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetSlot(ns3::Time slotTime) [member function] + cls.add_method('SetSlot', + 'void', + [param('ns3::Time', 'slotTime')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetSifs(ns3::Time sifs) [member function] + cls.add_method('SetSifs', + 'void', + [param('ns3::Time', 'sifs')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetEifsNoDifs(ns3::Time eifsNoDifs) [member function] + cls.add_method('SetEifsNoDifs', + 'void', + [param('ns3::Time', 'eifsNoDifs')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetAckTimeout(ns3::Time ackTimeout) [member function] + cls.add_method('SetAckTimeout', + 'void', + [param('ns3::Time', 'ackTimeout')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetCtsTimeout(ns3::Time ctsTimeout) [member function] + cls.add_method('SetCtsTimeout', + 'void', + [param('ns3::Time', 'ctsTimeout')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetPifs(ns3::Time pifs) [member function] + cls.add_method('SetPifs', + 'void', + [param('ns3::Time', 'pifs')], + is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Time ns3::AdhocWifiMac::GetSlot() const [member function] + cls.add_method('GetSlot', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Time ns3::AdhocWifiMac::GetSifs() const [member function] + cls.add_method('GetSifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Time ns3::AdhocWifiMac::GetEifsNoDifs() const [member function] + cls.add_method('GetEifsNoDifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Time ns3::AdhocWifiMac::GetAckTimeout() const [member function] + cls.add_method('GetAckTimeout', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Time ns3::AdhocWifiMac::GetCtsTimeout() const [member function] + cls.add_method('GetCtsTimeout', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Time ns3::AdhocWifiMac::GetPifs() const [member function] + cls.add_method('GetPifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetWifiPhy(ns3::Ptr phy) [member function] + cls.add_method('SetWifiPhy', + 'void', + [param('ns3::Ptr< ns3::WifiPhy >', 'phy')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetWifiRemoteStationManager(ns3::Ptr stationManager) [member function] + cls.add_method('SetWifiRemoteStationManager', + 'void', + [param('ns3::Ptr< ns3::WifiRemoteStationManager >', 'stationManager')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to, ns3::Mac48Address from) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to'), param('ns3::Mac48Address', 'from')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to')], + is_virtual=True) + ## adhoc-wifi-mac.h: bool ns3::AdhocWifiMac::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetForwardUpCallback(ns3::Callback, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty> upCallback) [member function] + cls.add_method('SetForwardUpCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty >', 'upCallback')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetLinkUpCallback(ns3::Callback linkUp) [member function] + cls.add_method('SetLinkUpCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkUp')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetLinkDownCallback(ns3::Callback linkDown) [member function] + cls.add_method('SetLinkDownCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkDown')], + is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Mac48Address ns3::AdhocWifiMac::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Mac48Address', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Ssid ns3::AdhocWifiMac::GetSsid() const [member function] + cls.add_method('GetSsid', + 'ns3::Ssid', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetAddress(ns3::Mac48Address address) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Mac48Address', 'address')], + is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::SetSsid(ns3::Ssid ssid) [member function] + cls.add_method('SetSsid', + 'void', + [param('ns3::Ssid', 'ssid')], + is_virtual=True) + ## adhoc-wifi-mac.h: ns3::Mac48Address ns3::AdhocWifiMac::GetBssid() const [member function] + cls.add_method('GetBssid', + 'ns3::Mac48Address', + [], + is_const=True, is_virtual=True) + ## adhoc-wifi-mac.h: void ns3::AdhocWifiMac::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3AmrrWifiManager_methods(root_module, cls): + ## amrr-wifi-manager.h: ns3::AmrrWifiManager::AmrrWifiManager(ns3::AmrrWifiManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AmrrWifiManager const &', 'arg0')]) + ## amrr-wifi-manager.h: static ns3::TypeId ns3::AmrrWifiManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## amrr-wifi-manager.h: ns3::AmrrWifiManager::AmrrWifiManager() [constructor] + cls.add_constructor([]) + ## amrr-wifi-manager.h: ns3::WifiRemoteStation * ns3::AmrrWifiManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3ArfWifiManager_methods(root_module, cls): + ## arf-wifi-manager.h: ns3::ArfWifiManager::ArfWifiManager(ns3::ArfWifiManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ArfWifiManager const &', 'arg0')]) + ## arf-wifi-manager.h: static ns3::TypeId ns3::ArfWifiManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## arf-wifi-manager.h: ns3::ArfWifiManager::ArfWifiManager() [constructor] + cls.add_constructor([]) + ## arf-wifi-manager.h: ns3::WifiRemoteStation * ns3::ArfWifiManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3CompositePropagationLossModel_methods(root_module, cls): + ## composite-propagation-loss-model.h: ns3::CompositePropagationLossModel::CompositePropagationLossModel(ns3::CompositePropagationLossModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::CompositePropagationLossModel const &', 'arg0')]) + ## composite-propagation-loss-model.h: static ns3::TypeId ns3::CompositePropagationLossModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## composite-propagation-loss-model.h: ns3::CompositePropagationLossModel::CompositePropagationLossModel() [constructor] + cls.add_constructor([]) + ## composite-propagation-loss-model.h: double ns3::CompositePropagationLossModel::GetLoss(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetLoss', + 'double', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_const=True, is_virtual=True) + ## composite-propagation-loss-model.h: void ns3::CompositePropagationLossModel::AddPropagationLossModel(ns3::Ptr pl) [member function] + cls.add_method('AddPropagationLossModel', + 'void', + [param('ns3::Ptr< ns3::PropagationLossModel >', 'pl')]) + ## composite-propagation-loss-model.h: void ns3::CompositePropagationLossModel::AddDefaults() [member function] + cls.add_method('AddDefaults', + 'void', + [], + visibility='protected', is_virtual=True) + return + +def register_Ns3ConstantRateWifiManager_methods(root_module, cls): + ## constant-rate-wifi-manager.h: ns3::ConstantRateWifiManager::ConstantRateWifiManager(ns3::ConstantRateWifiManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ConstantRateWifiManager const &', 'arg0')]) + ## constant-rate-wifi-manager.h: static ns3::TypeId ns3::ConstantRateWifiManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## constant-rate-wifi-manager.h: ns3::ConstantRateWifiManager::ConstantRateWifiManager() [constructor] + cls.add_constructor([]) + ## constant-rate-wifi-manager.h: ns3::WifiMode ns3::ConstantRateWifiManager::GetDataMode() const [member function] + cls.add_method('GetDataMode', + 'ns3::WifiMode', + [], + is_const=True) + ## constant-rate-wifi-manager.h: ns3::WifiMode ns3::ConstantRateWifiManager::GetCtlMode() const [member function] + cls.add_method('GetCtlMode', + 'ns3::WifiMode', + [], + is_const=True) + ## constant-rate-wifi-manager.h: ns3::WifiRemoteStation * ns3::ConstantRateWifiManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3ConstantSpeedPropagationDelayModel_methods(root_module, cls): + ## propagation-delay-model.h: ns3::ConstantSpeedPropagationDelayModel::ConstantSpeedPropagationDelayModel(ns3::ConstantSpeedPropagationDelayModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::ConstantSpeedPropagationDelayModel const &', 'arg0')]) + ## propagation-delay-model.h: static ns3::TypeId ns3::ConstantSpeedPropagationDelayModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## propagation-delay-model.h: ns3::ConstantSpeedPropagationDelayModel::ConstantSpeedPropagationDelayModel() [constructor] + cls.add_constructor([]) + ## propagation-delay-model.h: ns3::Time ns3::ConstantSpeedPropagationDelayModel::GetDelay(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetDelay', + 'ns3::Time', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_const=True, is_virtual=True) + ## propagation-delay-model.h: void ns3::ConstantSpeedPropagationDelayModel::SetSpeed(double speed) [member function] + cls.add_method('SetSpeed', + 'void', + [param('double', 'speed')]) + ## propagation-delay-model.h: double ns3::ConstantSpeedPropagationDelayModel::GetSpeed() const [member function] + cls.add_method('GetSpeed', + 'double', + [], + is_const=True) + return + +def register_Ns3FriisPropagationLossModel_methods(root_module, cls): + ## propagation-loss-model.h: ns3::FriisPropagationLossModel::FriisPropagationLossModel(ns3::FriisPropagationLossModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::FriisPropagationLossModel const &', 'arg0')]) + ## propagation-loss-model.h: static ns3::TypeId ns3::FriisPropagationLossModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## propagation-loss-model.h: ns3::FriisPropagationLossModel::FriisPropagationLossModel() [constructor] + cls.add_constructor([]) + ## propagation-loss-model.h: void ns3::FriisPropagationLossModel::SetLambda(double frequency, double speed) [member function] + cls.add_method('SetLambda', + 'void', + [param('double', 'frequency'), param('double', 'speed')]) + ## propagation-loss-model.h: void ns3::FriisPropagationLossModel::SetLambda(double lambda) [member function] + cls.add_method('SetLambda', + 'void', + [param('double', 'lambda')]) + ## propagation-loss-model.h: void ns3::FriisPropagationLossModel::SetSystemLoss(double systemLoss) [member function] + cls.add_method('SetSystemLoss', + 'void', + [param('double', 'systemLoss')]) + ## propagation-loss-model.h: void ns3::FriisPropagationLossModel::SetMinDistance(double minDistance) [member function] + cls.add_method('SetMinDistance', + 'void', + [param('double', 'minDistance')]) + ## propagation-loss-model.h: double ns3::FriisPropagationLossModel::GetMinDistance() const [member function] + cls.add_method('GetMinDistance', + 'double', + [], + is_const=True) + ## propagation-loss-model.h: double ns3::FriisPropagationLossModel::GetLambda() const [member function] + cls.add_method('GetLambda', + 'double', + [], + is_const=True) + ## propagation-loss-model.h: double ns3::FriisPropagationLossModel::GetSystemLoss() const [member function] + cls.add_method('GetSystemLoss', + 'double', + [], + is_const=True) + ## propagation-loss-model.h: double ns3::FriisPropagationLossModel::GetLoss(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetLoss', + 'double', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_const=True, is_virtual=True) + return + +def register_Ns3IdealWifiManager_methods(root_module, cls): + ## ideal-wifi-manager.h: ns3::IdealWifiManager::IdealWifiManager(ns3::IdealWifiManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::IdealWifiManager const &', 'arg0')]) + ## ideal-wifi-manager.h: static ns3::TypeId ns3::IdealWifiManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## ideal-wifi-manager.h: ns3::IdealWifiManager::IdealWifiManager() [constructor] + cls.add_constructor([]) + ## ideal-wifi-manager.h: void ns3::IdealWifiManager::SetupPhy(ns3::Ptr phy) [member function] + cls.add_method('SetupPhy', + 'void', + [param('ns3::Ptr< ns3::WifiPhy >', 'phy')], + is_virtual=True) + ## ideal-wifi-manager.h: double ns3::IdealWifiManager::GetSnrThreshold(ns3::WifiMode mode) const [member function] + cls.add_method('GetSnrThreshold', + 'double', + [param('ns3::WifiMode', 'mode')], + is_const=True) + ## ideal-wifi-manager.h: void ns3::IdealWifiManager::AddModeSnrThreshold(ns3::WifiMode mode, double ber) [member function] + cls.add_method('AddModeSnrThreshold', + 'void', + [param('ns3::WifiMode', 'mode'), param('double', 'ber')]) + ## ideal-wifi-manager.h: ns3::WifiRemoteStation * ns3::IdealWifiManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3JakesPropagationLossModel_methods(root_module, cls): + ## jakes-propagation-loss-model.h: ns3::JakesPropagationLossModel::JakesPropagationLossModel(ns3::JakesPropagationLossModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::JakesPropagationLossModel const &', 'arg0')]) + ## jakes-propagation-loss-model.h: static ns3::TypeId ns3::JakesPropagationLossModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## jakes-propagation-loss-model.h: ns3::JakesPropagationLossModel::JakesPropagationLossModel() [constructor] + cls.add_constructor([]) + ## jakes-propagation-loss-model.h: double ns3::JakesPropagationLossModel::GetLoss(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetLoss', + 'double', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_const=True, is_virtual=True) + ## jakes-propagation-loss-model.h: void ns3::JakesPropagationLossModel::SetNRays(uint8_t nRays) [member function] + cls.add_method('SetNRays', + 'void', + [param('uint8_t', 'nRays')]) + ## jakes-propagation-loss-model.h: void ns3::JakesPropagationLossModel::SetNOscillators(uint8_t nOscillators) [member function] + cls.add_method('SetNOscillators', + 'void', + [param('uint8_t', 'nOscillators')]) + return + +def register_Ns3LogDistancePropagationLossModel_methods(root_module, cls): + ## propagation-loss-model.h: ns3::LogDistancePropagationLossModel::LogDistancePropagationLossModel(ns3::LogDistancePropagationLossModel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::LogDistancePropagationLossModel const &', 'arg0')]) + ## propagation-loss-model.h: static ns3::TypeId ns3::LogDistancePropagationLossModel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## propagation-loss-model.h: ns3::LogDistancePropagationLossModel::LogDistancePropagationLossModel() [constructor] + cls.add_constructor([]) + ## propagation-loss-model.h: void ns3::LogDistancePropagationLossModel::SetPathLossExponent(double n) [member function] + cls.add_method('SetPathLossExponent', + 'void', + [param('double', 'n')]) + ## propagation-loss-model.h: double ns3::LogDistancePropagationLossModel::GetPathLossExponent() const [member function] + cls.add_method('GetPathLossExponent', + 'double', + [], + is_const=True) + ## propagation-loss-model.h: void ns3::LogDistancePropagationLossModel::SetReferenceModel(ns3::Ptr model) [member function] + cls.add_method('SetReferenceModel', + 'void', + [param('ns3::Ptr< ns3::PropagationLossModel >', 'model')]) + ## propagation-loss-model.h: void ns3::LogDistancePropagationLossModel::SetReferenceDistance(double referenceDistance) [member function] + cls.add_method('SetReferenceDistance', + 'void', + [param('double', 'referenceDistance')]) + ## propagation-loss-model.h: double ns3::LogDistancePropagationLossModel::GetLoss(ns3::Ptr a, ns3::Ptr b) const [member function] + cls.add_method('GetLoss', + 'double', + [param('ns3::Ptr< ns3::MobilityModel >', 'a'), param('ns3::Ptr< ns3::MobilityModel >', 'b')], + is_const=True, is_virtual=True) + return + +def register_Ns3NqapWifiMac_methods(root_module, cls): + ## nqap-wifi-mac.h: static ns3::TypeId ns3::NqapWifiMac::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## nqap-wifi-mac.h: ns3::NqapWifiMac::NqapWifiMac() [constructor] + cls.add_constructor([]) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetSlot(ns3::Time slotTime) [member function] + cls.add_method('SetSlot', + 'void', + [param('ns3::Time', 'slotTime')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetSifs(ns3::Time sifs) [member function] + cls.add_method('SetSifs', + 'void', + [param('ns3::Time', 'sifs')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetEifsNoDifs(ns3::Time eifsNoDifs) [member function] + cls.add_method('SetEifsNoDifs', + 'void', + [param('ns3::Time', 'eifsNoDifs')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetAckTimeout(ns3::Time ackTimeout) [member function] + cls.add_method('SetAckTimeout', + 'void', + [param('ns3::Time', 'ackTimeout')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetCtsTimeout(ns3::Time ctsTimeout) [member function] + cls.add_method('SetCtsTimeout', + 'void', + [param('ns3::Time', 'ctsTimeout')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetPifs(ns3::Time pifs) [member function] + cls.add_method('SetPifs', + 'void', + [param('ns3::Time', 'pifs')], + is_virtual=True) + ## nqap-wifi-mac.h: ns3::Time ns3::NqapWifiMac::GetSlot() const [member function] + cls.add_method('GetSlot', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: ns3::Time ns3::NqapWifiMac::GetSifs() const [member function] + cls.add_method('GetSifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: ns3::Time ns3::NqapWifiMac::GetEifsNoDifs() const [member function] + cls.add_method('GetEifsNoDifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: ns3::Time ns3::NqapWifiMac::GetAckTimeout() const [member function] + cls.add_method('GetAckTimeout', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: ns3::Time ns3::NqapWifiMac::GetCtsTimeout() const [member function] + cls.add_method('GetCtsTimeout', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: ns3::Time ns3::NqapWifiMac::GetPifs() const [member function] + cls.add_method('GetPifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetWifiPhy(ns3::Ptr phy) [member function] + cls.add_method('SetWifiPhy', + 'void', + [param('ns3::Ptr< ns3::WifiPhy >', 'phy')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetWifiRemoteStationManager(ns3::Ptr stationManager) [member function] + cls.add_method('SetWifiRemoteStationManager', + 'void', + [param('ns3::Ptr< ns3::WifiRemoteStationManager >', 'stationManager')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to, ns3::Mac48Address from) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to'), param('ns3::Mac48Address', 'from')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to')], + is_virtual=True) + ## nqap-wifi-mac.h: bool ns3::NqapWifiMac::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetForwardUpCallback(ns3::Callback, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty> upCallback) [member function] + cls.add_method('SetForwardUpCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty >', 'upCallback')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetLinkUpCallback(ns3::Callback linkUp) [member function] + cls.add_method('SetLinkUpCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkUp')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetLinkDownCallback(ns3::Callback linkDown) [member function] + cls.add_method('SetLinkDownCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkDown')], + is_virtual=True) + ## nqap-wifi-mac.h: ns3::Mac48Address ns3::NqapWifiMac::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Mac48Address', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: ns3::Ssid ns3::NqapWifiMac::GetSsid() const [member function] + cls.add_method('GetSsid', + 'ns3::Ssid', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetAddress(ns3::Mac48Address address) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Mac48Address', 'address')], + is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetSsid(ns3::Ssid ssid) [member function] + cls.add_method('SetSsid', + 'void', + [param('ns3::Ssid', 'ssid')], + is_virtual=True) + ## nqap-wifi-mac.h: ns3::Mac48Address ns3::NqapWifiMac::GetBssid() const [member function] + cls.add_method('GetBssid', + 'ns3::Mac48Address', + [], + is_const=True, is_virtual=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::SetBeaconInterval(ns3::Time interval) [member function] + cls.add_method('SetBeaconInterval', + 'void', + [param('ns3::Time', 'interval')]) + ## nqap-wifi-mac.h: ns3::Time ns3::NqapWifiMac::GetBeaconInterval() const [member function] + cls.add_method('GetBeaconInterval', + 'ns3::Time', + [], + is_const=True) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::StartBeaconing() [member function] + cls.add_method('StartBeaconing', + 'void', + []) + ## nqap-wifi-mac.h: void ns3::NqapWifiMac::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3NqstaWifiMac_methods(root_module, cls): + ## nqsta-wifi-mac.h: static ns3::TypeId ns3::NqstaWifiMac::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## nqsta-wifi-mac.h: ns3::NqstaWifiMac::NqstaWifiMac() [constructor] + cls.add_constructor([]) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetSlot(ns3::Time slotTime) [member function] + cls.add_method('SetSlot', + 'void', + [param('ns3::Time', 'slotTime')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetSifs(ns3::Time sifs) [member function] + cls.add_method('SetSifs', + 'void', + [param('ns3::Time', 'sifs')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetEifsNoDifs(ns3::Time eifsNoDifs) [member function] + cls.add_method('SetEifsNoDifs', + 'void', + [param('ns3::Time', 'eifsNoDifs')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetAckTimeout(ns3::Time ackTimeout) [member function] + cls.add_method('SetAckTimeout', + 'void', + [param('ns3::Time', 'ackTimeout')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetCtsTimeout(ns3::Time ctsTimeout) [member function] + cls.add_method('SetCtsTimeout', + 'void', + [param('ns3::Time', 'ctsTimeout')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetPifs(ns3::Time pifs) [member function] + cls.add_method('SetPifs', + 'void', + [param('ns3::Time', 'pifs')], + is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Time ns3::NqstaWifiMac::GetSlot() const [member function] + cls.add_method('GetSlot', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Time ns3::NqstaWifiMac::GetSifs() const [member function] + cls.add_method('GetSifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Time ns3::NqstaWifiMac::GetEifsNoDifs() const [member function] + cls.add_method('GetEifsNoDifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Time ns3::NqstaWifiMac::GetAckTimeout() const [member function] + cls.add_method('GetAckTimeout', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Time ns3::NqstaWifiMac::GetCtsTimeout() const [member function] + cls.add_method('GetCtsTimeout', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Time ns3::NqstaWifiMac::GetPifs() const [member function] + cls.add_method('GetPifs', + 'ns3::Time', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetWifiPhy(ns3::Ptr phy) [member function] + cls.add_method('SetWifiPhy', + 'void', + [param('ns3::Ptr< ns3::WifiPhy >', 'phy')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetWifiRemoteStationManager(ns3::Ptr stationManager) [member function] + cls.add_method('SetWifiRemoteStationManager', + 'void', + [param('ns3::Ptr< ns3::WifiRemoteStationManager >', 'stationManager')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to, ns3::Mac48Address from) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to'), param('ns3::Mac48Address', 'from')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::Enqueue(ns3::Ptr packet, ns3::Mac48Address to) [member function] + cls.add_method('Enqueue', + 'void', + [param('ns3::Ptr< ns3::Packet const >', 'packet'), param('ns3::Mac48Address', 'to')], + is_virtual=True) + ## nqsta-wifi-mac.h: bool ns3::NqstaWifiMac::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetForwardUpCallback(ns3::Callback, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty> upCallback) [member function] + cls.add_method('SetForwardUpCallback', + 'void', + [param('ns3::Callback< void, ns3::Ptr< ns3::Packet >, ns3::Mac48Address, ns3::Mac48Address, ns3::empty, ns3::empty, ns3::empty >', 'upCallback')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetLinkUpCallback(ns3::Callback linkUp) [member function] + cls.add_method('SetLinkUpCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkUp')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetLinkDownCallback(ns3::Callback linkDown) [member function] + cls.add_method('SetLinkDownCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'linkDown')], + is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Mac48Address ns3::NqstaWifiMac::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Mac48Address', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Ssid ns3::NqstaWifiMac::GetSsid() const [member function] + cls.add_method('GetSsid', + 'ns3::Ssid', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetAddress(ns3::Mac48Address address) [member function] + cls.add_method('SetAddress', + 'void', + [param('ns3::Mac48Address', 'address')], + is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetSsid(ns3::Ssid ssid) [member function] + cls.add_method('SetSsid', + 'void', + [param('ns3::Ssid', 'ssid')], + is_virtual=True) + ## nqsta-wifi-mac.h: ns3::Mac48Address ns3::NqstaWifiMac::GetBssid() const [member function] + cls.add_method('GetBssid', + 'ns3::Mac48Address', + [], + is_const=True, is_virtual=True) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetMaxMissedBeacons(uint32_t missed) [member function] + cls.add_method('SetMaxMissedBeacons', + 'void', + [param('uint32_t', 'missed')]) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetProbeRequestTimeout(ns3::Time timeout) [member function] + cls.add_method('SetProbeRequestTimeout', + 'void', + [param('ns3::Time', 'timeout')]) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::SetAssocRequestTimeout(ns3::Time timeout) [member function] + cls.add_method('SetAssocRequestTimeout', + 'void', + [param('ns3::Time', 'timeout')]) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::StartActiveAssociation() [member function] + cls.add_method('StartActiveAssociation', + 'void', + []) + ## nqsta-wifi-mac.h: void ns3::NqstaWifiMac::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3OnoeWifiManager_methods(root_module, cls): + ## onoe-wifi-manager.h: ns3::OnoeWifiManager::OnoeWifiManager(ns3::OnoeWifiManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::OnoeWifiManager const &', 'arg0')]) + ## onoe-wifi-manager.h: static ns3::TypeId ns3::OnoeWifiManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## onoe-wifi-manager.h: ns3::OnoeWifiManager::OnoeWifiManager() [constructor] + cls.add_constructor([]) + ## onoe-wifi-manager.h: ns3::WifiRemoteStation * ns3::OnoeWifiManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3RraaWifiManager_methods(root_module, cls): + ## rraa-wifi-manager.h: ns3::RraaWifiManager::RraaWifiManager(ns3::RraaWifiManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::RraaWifiManager const &', 'arg0')]) + ## rraa-wifi-manager.h: static ns3::TypeId ns3::RraaWifiManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## rraa-wifi-manager.h: ns3::RraaWifiManager::RraaWifiManager() [constructor] + cls.add_constructor([]) + ## rraa-wifi-manager.h: bool ns3::RraaWifiManager::OnlyBasic() [member function] + cls.add_method('OnlyBasic', + 'bool', + []) + ## rraa-wifi-manager.h: ns3::Time ns3::RraaWifiManager::GetTimeout() const [member function] + cls.add_method('GetTimeout', + 'ns3::Time', + [], + is_const=True) + ## rraa-wifi-manager.h: ns3::ThresholdsItem ns3::RraaWifiManager::GetThresholds(ns3::WifiMode mode) const [member function] + cls.add_method('GetThresholds', + 'ns3::ThresholdsItem', + [param('ns3::WifiMode', 'mode')], + is_const=True) + ## rraa-wifi-manager.h: ns3::WifiRemoteStation * ns3::RraaWifiManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3WifiChannel_methods(root_module, cls): + ## wifi-channel.h: ns3::WifiChannel::WifiChannel(ns3::WifiChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiChannel const &', 'arg0')]) + ## wifi-channel.h: ns3::WifiChannel::WifiChannel() [constructor] + cls.add_constructor([]) + ## wifi-channel.h: static ns3::TypeId ns3::WifiChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## wifi-channel.h: ns3::Ptr ns3::WifiChannel::CreatePhy(ns3::Ptr device, ns3::Ptr mobility, ns3::UnsafeAttributeList list) [member function] + cls.add_method('CreatePhy', + 'ns3::Ptr< ns3::WifiPhy >', + [param('ns3::Ptr< ns3::WifiNetDevice >', 'device'), param('ns3::Ptr< ns3::Object >', 'mobility'), param('ns3::UnsafeAttributeList', 'list')], + is_pure_virtual=True, is_virtual=True) + return + +def register_Ns3WifiNetDevice_methods(root_module, cls): + ## wifi-net-device.h: ns3::WifiNetDevice::WifiNetDevice(ns3::WifiNetDevice const & arg0) [copy constructor] + cls.add_constructor([param('ns3::WifiNetDevice const &', 'arg0')]) + ## wifi-net-device.h: static ns3::TypeId ns3::WifiNetDevice::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## wifi-net-device.h: ns3::WifiNetDevice::WifiNetDevice() [constructor] + cls.add_constructor([]) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetMac(ns3::Ptr mac) [member function] + cls.add_method('SetMac', + 'void', + [param('ns3::Ptr< ns3::WifiMac >', 'mac')]) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetPhy(ns3::Ptr phy) [member function] + cls.add_method('SetPhy', + 'void', + [param('ns3::Ptr< ns3::WifiPhy >', 'phy')]) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetRemoteStationManager(ns3::Ptr manager) [member function] + cls.add_method('SetRemoteStationManager', + 'void', + [param('ns3::Ptr< ns3::WifiRemoteStationManager >', 'manager')]) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetChannel(ns3::Ptr channel) [member function] + cls.add_method('SetChannel', + 'void', + [param('ns3::Ptr< ns3::WifiChannel >', 'channel')]) + ## wifi-net-device.h: ns3::Ptr ns3::WifiNetDevice::GetMac() const [member function] + cls.add_method('GetMac', + 'ns3::Ptr< ns3::WifiMac >', + [], + is_const=True) + ## wifi-net-device.h: ns3::Ptr ns3::WifiNetDevice::GetPhy() const [member function] + cls.add_method('GetPhy', + 'ns3::Ptr< ns3::WifiPhy >', + [], + is_const=True) + ## wifi-net-device.h: ns3::Ptr ns3::WifiNetDevice::GetRemoteStationManager() const [member function] + cls.add_method('GetRemoteStationManager', + 'ns3::Ptr< ns3::WifiRemoteStationManager >', + [], + is_const=True) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetName(std::string const name) [member function] + cls.add_method('SetName', + 'void', + [param('std::string const', 'name')], + is_virtual=True) + ## wifi-net-device.h: std::string ns3::WifiNetDevice::GetName() const [member function] + cls.add_method('GetName', + 'std::string', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetIfIndex(uint32_t const index) [member function] + cls.add_method('SetIfIndex', + 'void', + [param('uint32_t const', 'index')], + is_virtual=True) + ## wifi-net-device.h: uint32_t ns3::WifiNetDevice::GetIfIndex() const [member function] + cls.add_method('GetIfIndex', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: ns3::Ptr ns3::WifiNetDevice::GetChannel() const [member function] + cls.add_method('GetChannel', + 'ns3::Ptr< ns3::Channel >', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: ns3::Address ns3::WifiNetDevice::GetAddress() const [member function] + cls.add_method('GetAddress', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::SetMtu(uint16_t const mtu) [member function] + cls.add_method('SetMtu', + 'bool', + [param('uint16_t const', 'mtu')], + is_virtual=True) + ## wifi-net-device.h: uint16_t ns3::WifiNetDevice::GetMtu() const [member function] + cls.add_method('GetMtu', + 'uint16_t', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::IsLinkUp() const [member function] + cls.add_method('IsLinkUp', + 'bool', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetLinkChangeCallback(ns3::Callback callback) [member function] + cls.add_method('SetLinkChangeCallback', + 'void', + [param('ns3::Callback< void, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')], + is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::IsBroadcast() const [member function] + cls.add_method('IsBroadcast', + 'bool', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: ns3::Address ns3::WifiNetDevice::GetBroadcast() const [member function] + cls.add_method('GetBroadcast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::IsMulticast() const [member function] + cls.add_method('IsMulticast', + 'bool', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: ns3::Address ns3::WifiNetDevice::GetMulticast() const [member function] + cls.add_method('GetMulticast', + 'ns3::Address', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: ns3::Address ns3::WifiNetDevice::MakeMulticastAddress(ns3::Ipv4Address multicastGroup) const [member function] + cls.add_method('MakeMulticastAddress', + 'ns3::Address', + [param('ns3::Ipv4Address', 'multicastGroup')], + is_const=True, is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::IsPointToPoint() const [member function] + cls.add_method('IsPointToPoint', + 'bool', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::Send(ns3::Ptr packet, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('Send', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## wifi-net-device.h: ns3::Ptr ns3::WifiNetDevice::GetNode() const [member function] + cls.add_method('GetNode', + 'ns3::Ptr< ns3::Node >', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetNode(ns3::Ptr node) [member function] + cls.add_method('SetNode', + 'void', + [param('ns3::Ptr< ns3::Node >', 'node')], + is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::NeedsArp() const [member function] + cls.add_method('NeedsArp', + 'bool', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::empty, ns3::empty> cb) [member function] + cls.add_method('SetReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::empty, ns3::empty >', 'cb')], + is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::SendFrom(ns3::Ptr packet, ns3::Address const & source, ns3::Address const & dest, uint16_t protocolNumber) [member function] + cls.add_method('SendFrom', + 'bool', + [param('ns3::Ptr< ns3::Packet >', 'packet'), param('ns3::Address const &', 'source'), param('ns3::Address const &', 'dest'), param('uint16_t', 'protocolNumber')], + is_virtual=True) + ## wifi-net-device.h: void ns3::WifiNetDevice::SetPromiscReceiveCallback(ns3::Callback, ns3::Ptr, unsigned short, ns3::Address const&, ns3::Address const&, ns3::NetDevice::PacketType> cb) [member function] + cls.add_method('SetPromiscReceiveCallback', + 'void', + [param('ns3::Callback< bool, ns3::Ptr< ns3::NetDevice >, ns3::Ptr< ns3::Packet const >, unsigned short, ns3::Address const &, ns3::Address const &, ns3::NetDevice::PacketType >', 'cb')], + is_virtual=True) + ## wifi-net-device.h: bool ns3::WifiNetDevice::SupportsSendFrom() const [member function] + cls.add_method('SupportsSendFrom', + 'bool', + [], + is_const=True, is_virtual=True) + ## wifi-net-device.h: void ns3::WifiNetDevice::DoDispose() [member function] + cls.add_method('DoDispose', + 'void', + [], + visibility='private', is_virtual=True) + return + +def register_Ns3YansWifiChannel_methods(root_module, cls): + ## yans-wifi-channel.h: ns3::YansWifiChannel::YansWifiChannel(ns3::YansWifiChannel const & arg0) [copy constructor] + cls.add_constructor([param('ns3::YansWifiChannel const &', 'arg0')]) + ## yans-wifi-channel.h: static ns3::TypeId ns3::YansWifiChannel::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## yans-wifi-channel.h: ns3::YansWifiChannel::YansWifiChannel() [constructor] + cls.add_constructor([]) + ## yans-wifi-channel.h: uint32_t ns3::YansWifiChannel::GetNDevices() const [member function] + cls.add_method('GetNDevices', + 'uint32_t', + [], + is_const=True, is_virtual=True) + ## yans-wifi-channel.h: ns3::Ptr ns3::YansWifiChannel::GetDevice(uint32_t i) const [member function] + cls.add_method('GetDevice', + 'ns3::Ptr< ns3::NetDevice >', + [param('uint32_t', 'i')], + is_const=True, is_virtual=True) + ## yans-wifi-channel.h: ns3::Ptr ns3::YansWifiChannel::CreatePhy(ns3::Ptr device, ns3::Ptr mobility, ns3::UnsafeAttributeList list) [member function] + cls.add_method('CreatePhy', + 'ns3::Ptr< ns3::WifiPhy >', + [param('ns3::Ptr< ns3::WifiNetDevice >', 'device'), param('ns3::Ptr< ns3::Object >', 'mobility'), param('ns3::UnsafeAttributeList', 'list')], + is_virtual=True) + ## yans-wifi-channel.h: void ns3::YansWifiChannel::SetPropagationLossModel(ns3::Ptr loss) [member function] + cls.add_method('SetPropagationLossModel', + 'void', + [param('ns3::Ptr< ns3::PropagationLossModel >', 'loss')]) + ## yans-wifi-channel.h: void ns3::YansWifiChannel::SetPropagationDelayModel(ns3::Ptr delay) [member function] + cls.add_method('SetPropagationDelayModel', + 'void', + [param('ns3::Ptr< ns3::PropagationDelayModel >', 'delay')]) + ## yans-wifi-channel.h: void ns3::YansWifiChannel::Send(ns3::Ptr sender, ns3::Ptr packet, double txPowerDbm, ns3::WifiMode wifiMode, ns3::WifiPreamble preamble) const [member function] + cls.add_method('Send', + 'void', + [param('ns3::Ptr< ns3::YansWifiPhy >', 'sender'), param('ns3::Ptr< ns3::Packet const >', 'packet'), param('double', 'txPowerDbm'), param('ns3::WifiMode', 'wifiMode'), param('ns3::WifiPreamble', 'preamble')], + is_const=True) + return + +def register_Ns3AarfWifiManager_methods(root_module, cls): + ## aarf-wifi-manager.h: ns3::AarfWifiManager::AarfWifiManager(ns3::AarfWifiManager const & arg0) [copy constructor] + cls.add_constructor([param('ns3::AarfWifiManager const &', 'arg0')]) + ## aarf-wifi-manager.h: static ns3::TypeId ns3::AarfWifiManager::GetTypeId() [member function] + cls.add_method('GetTypeId', + 'ns3::TypeId', + [], + is_static=True) + ## aarf-wifi-manager.h: ns3::AarfWifiManager::AarfWifiManager() [constructor] + cls.add_constructor([]) + ## aarf-wifi-manager.h: ns3::WifiRemoteStation * ns3::AarfWifiManager::CreateStation() [member function] + cls.add_method('CreateStation', + 'ns3::WifiRemoteStation *', + [], + visibility='private', is_virtual=True) + return + +def register_functions(root_module): + module = root_module + ## wifi-mode.h: extern ns3::Ptr ns3::MakeWifiModeChecker() [free function] + module.add_function('MakeWifiModeChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + ## ssid.h: extern ns3::Ptr ns3::MakeSsidChecker() [free function] + module.add_function('MakeSsidChecker', + 'ns3::Ptr< ns3::AttributeChecker const >', + []) + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + diff --git a/bindings/python/ns3module_helpers.cc b/bindings/python/ns3module_helpers.cc new file mode 100644 index 000000000..03dc52445 --- /dev/null +++ b/bindings/python/ns3module_helpers.cc @@ -0,0 +1,222 @@ +#include "ns3module.h" + + +namespace ns3{ + +void PythonCompleteConstruct (Ptr object, TypeId typeId, const AttributeList &attributes) +{ + object->SetTypeId (typeId); + object->Object::Construct (attributes); +} + +} + + + +class PythonEventImpl : public ns3::EventImpl +{ +private: + PyObject *m_callback; + PyObject *m_args; +public: + PythonEventImpl (PyObject *callback, PyObject *args) + { + m_callback = callback; + Py_INCREF(m_callback); + m_args = args; + Py_INCREF(m_args); + } + virtual ~PythonEventImpl () + { + PyGILState_STATE __py_gil_state; + __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0); + + Py_DECREF(m_callback); + Py_DECREF(m_args); + + if (PyEval_ThreadsInitialized()) + PyGILState_Release(__py_gil_state); + } + virtual void Notify () + { + PyGILState_STATE __py_gil_state; + __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0); + + PyObject *retval = PyObject_CallObject(m_callback, m_args); + if (retval) { + if (retval != Py_None) { + PyErr_SetString(PyExc_TypeError, "event callback should return None"); + PyErr_Print(); + } + Py_DECREF(retval); + } else { + PyErr_Print(); + } + + if (PyEval_ThreadsInitialized()) + PyGILState_Release(__py_gil_state); + } +}; + + +PyObject * +_wrap_Simulator_Schedule(PyNs3Simulator *PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs, + PyObject **return_exception) +{ + PyObject *exc_type, *traceback; + PyObject *py_time; + PyObject *py_callback; + PyObject *user_args; + ns3::Ptr py_event_impl; + PyNs3EventId *py_EventId; + + if (kwargs && PyObject_Length(kwargs) > 0) { + PyErr_SetString(PyExc_TypeError, "keyword arguments not supported"); + goto error; + } + + if (PyTuple_GET_SIZE(args) < 2) { + PyErr_SetString(PyExc_TypeError, "ns3.Simulator.Schedule needs at least 2 arguments"); + goto error; + } + py_time = PyTuple_GET_ITEM(args, 0); + py_callback = PyTuple_GET_ITEM(args, 1); + + if (!PyObject_IsInstance(py_time, (PyObject*) &PyNs3Time_Type)) { + PyErr_SetString(PyExc_TypeError, "Parameter 1 should be a ns3.Time instance"); + goto error; + } + if (!PyCallable_Check(py_callback)) { + PyErr_SetString(PyExc_TypeError, "Parameter 2 should be callable"); + goto error; + } + user_args = PyTuple_GetSlice(args, 2, PyTuple_GET_SIZE(args)); + py_event_impl = ns3::Create(py_callback, user_args); + Py_DECREF(user_args); + + py_EventId = PyObject_New(PyNs3EventId, &PyNs3EventId_Type); + py_EventId->obj = new ns3::EventId( + ns3::Simulator::Schedule(*((PyNs3Time *) py_time)->obj, py_event_impl)); + return (PyObject *) py_EventId; + +error: + PyErr_Fetch(&exc_type, return_exception, &traceback); + Py_XDECREF(exc_type); + Py_XDECREF(traceback); + return NULL; +} + + +PyObject * +_wrap_Simulator_ScheduleNow(PyNs3Simulator *PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs, + PyObject **return_exception) +{ + PyObject *exc_type, *traceback; + PyObject *py_callback; + PyObject *user_args; + ns3::Ptr py_event_impl; + PyNs3EventId *py_EventId; + + if (kwargs && PyObject_Length(kwargs) > 0) { + PyErr_SetString(PyExc_TypeError, "keyword arguments not supported"); + goto error; + } + + if (PyTuple_GET_SIZE(args) < 1) { + PyErr_SetString(PyExc_TypeError, "ns3.Simulator.Schedule needs at least 1 argument"); + goto error; + } + py_callback = PyTuple_GET_ITEM(args, 0); + + if (!PyCallable_Check(py_callback)) { + PyErr_SetString(PyExc_TypeError, "Parameter 2 should be callable"); + goto error; + } + user_args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); + py_event_impl = ns3::Create(py_callback, user_args); + Py_DECREF(user_args); + + py_EventId = PyObject_New(PyNs3EventId, &PyNs3EventId_Type); + py_EventId->obj = new ns3::EventId(ns3::Simulator::ScheduleNow(py_event_impl)); + return (PyObject *) py_EventId; + +error: + PyErr_Fetch(&exc_type, return_exception, &traceback); + Py_XDECREF(exc_type); + Py_XDECREF(traceback); + return NULL; +} + + +PyObject * +_wrap_Simulator_ScheduleDestroy(PyNs3Simulator *PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs, + PyObject **return_exception) +{ + PyObject *exc_type, *traceback; + PyObject *py_callback; + PyObject *user_args; + ns3::Ptr py_event_impl; + PyNs3EventId *py_EventId; + + if (kwargs && PyObject_Length(kwargs) > 0) { + PyErr_SetString(PyExc_TypeError, "keyword arguments not supported"); + goto error; + } + + if (PyTuple_GET_SIZE(args) < 1) { + PyErr_SetString(PyExc_TypeError, "ns3.Simulator.Schedule needs at least 1 argument"); + goto error; + } + py_callback = PyTuple_GET_ITEM(args, 0); + + if (!PyCallable_Check(py_callback)) { + PyErr_SetString(PyExc_TypeError, "Parameter 2 should be callable"); + goto error; + } + user_args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); + py_event_impl = ns3::Create(py_callback, user_args); + Py_DECREF(user_args); + + py_EventId = PyObject_New(PyNs3EventId, &PyNs3EventId_Type); + py_EventId->obj = new ns3::EventId(ns3::Simulator::ScheduleDestroy(py_event_impl)); + return (PyObject *) py_EventId; + +error: + PyErr_Fetch(&exc_type, return_exception, &traceback); + Py_XDECREF(exc_type); + Py_XDECREF(traceback); + return NULL; +} + + +PyObject * +_wrap_TypeId_LookupByNameFailSafe(PyNs3TypeId *PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs, + PyObject **return_exception) +{ + bool ok; + const char *name; + Py_ssize_t name_len; + ns3::TypeId tid; + PyNs3TypeId *py_tid; + const char *keywords[] = {"name", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &name, &name_len)) { + PyObject *exc_type, *traceback; + PyErr_Fetch(&exc_type, return_exception, &traceback); + Py_XDECREF(exc_type); + Py_XDECREF(traceback); + return NULL; + } + ok = ns3::TypeId::LookupByNameFailSafe(std::string(name, name_len), &tid); + if (!ok) + { + PyErr_Format(PyExc_KeyError, "The ns3 type with name `%s' is not registered", name); + return NULL; + } + + py_tid = PyObject_New(PyNs3TypeId, &PyNs3TypeId_Type); + py_tid->obj = new ns3::TypeId (tid); + PyNs3TypeId_wrapper_registry[(void *) py_tid->obj] = (PyObject *) py_tid; + + return (PyObject *) py_tid; +} diff --git a/bindings/python/ns3modulegen.py b/bindings/python/ns3modulegen.py new file mode 100755 index 000000000..7cd34e182 --- /dev/null +++ b/bindings/python/ns3modulegen.py @@ -0,0 +1,145 @@ + +LOCAL_MODULES = [ + #'my_extra_api_definitions', + ] + + + +import sys +import os + +from pybindgen import FileCodeSink, write_preamble +from pybindgen.module import MultiSectionFactory +import pybindgen.settings + +from ns3modulegen_generated import module_init, register_types, register_methods, register_functions +import ns3modulegen_core_customizations +import callbacks_list + +this_script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + +class ErrorHandler(pybindgen.settings.ErrorHandler): + def handle_error(self, wrapper, exception, traceback_): + try: + stack = wrapper.stack_where_defined + except AttributeError: + print >> sys.stderr, "??:??: %s / %r" % (wrapper, exception) + else: + stack = list(stack) + stack.reverse() + for (filename, line_number, function_name, text) in stack: + file_dir = os.path.dirname(os.path.abspath(filename)) + if file_dir == this_script_dir: + print >> sys.stderr, "%s:%i: %r" % (os.path.join("..", "bindings", "python", os.path.basename(filename)), + line_number, exception) + break + return True +pybindgen.settings.error_handler = ErrorHandler() + +pybindgen.settings.wrapper_registry = pybindgen.settings.StdMapWrapperRegistry + + +class MyMultiSectionFactory(MultiSectionFactory): + + def __init__(self, main_file_name, modules): + super(MyMultiSectionFactory, self).__init__() + self.main_file_name = main_file_name + self.main_sink = FileCodeSink(open(main_file_name, "wt")) + self.header_name = "ns3module.h" + header_file_name = os.path.join(os.path.dirname(self.main_file_name), self.header_name) + self.header_sink = FileCodeSink(open(header_file_name, "wt")) + self.section_sinks = {'__main__': self.main_sink} + + for module in modules: + section_name = 'ns3_module_%s' % module.replace('-', '_') + file_name = os.path.join(os.path.dirname(self.main_file_name), "%s.cc" % section_name) + sink = FileCodeSink(open(file_name, "wt")) + self.section_sinks[section_name] = sink + + def get_section_code_sink(self, section_name): + return self.section_sinks[section_name] + + def get_main_code_sink(self): + return self.main_sink + + def get_common_header_code_sink(self): + return self.header_sink + + def get_common_header_include(self): + return '"%s"' % self.header_name + + def close(self): + self.header_sink.file.close() + self.main_sink.file.close() + for sink in self.section_sinks.itervalues(): + sink.file.close() + + + +def main(): + out = MyMultiSectionFactory(sys.argv[1], sys.argv[2:]) + root_module = module_init() + root_module.add_include('"everything.h"') + + register_types(root_module) + + ns3modulegen_core_customizations.Simulator_customizations(root_module) + ns3modulegen_core_customizations.CommandLine_customizations(root_module) + ns3modulegen_core_customizations.TypeId_customizations(root_module) + + + for local_module in LOCAL_MODULES: + mod = __import__(local_module) + mod.register_types(root_module) + + ns3modulegen_core_customizations.generate_callback_classes(root_module.after_forward_declarations, + callbacks_list.callback_classes) + + + register_methods(root_module) + + for local_module in LOCAL_MODULES: + mod = __import__(local_module) + mod.register_methods(root_module) + + ns3modulegen_core_customizations.Object_customizations(root_module) + ns3modulegen_core_customizations.Attribute_customizations(root_module) + + register_functions(root_module) + + for local_module in LOCAL_MODULES: + mod = __import__(local_module) + mod.register_functions(root_module) + + enabled_features = os.environ['NS3_ENABLED_FEATURES'].split(',') + + # if GtkConfigStore support is disabled, disable the class wrapper + if 'GtkConfigStore' not in enabled_features: + try: + root_module.classes.remove(root_module['ns3::GtkConfigStore']) + except KeyError: + pass + + # if no sqlite, the class SqliteDataOutput is disabled + if 'SqliteDataOutput' not in enabled_features: + try: + root_module.classes.remove(root_module['ns3::SqliteDataOutput']) + except KeyError: + pass + + if 'Threading' not in enabled_features: + for clsname in ['SystemThread', 'SystemMutex', 'SystemCondition', 'CriticalSection']: + root_module.classes.remove(root_module['ns3::%s' % clsname]) + + if 'RealTime' not in enabled_features: + for clsname in ['WallClockSynchronizer', 'RealtimeSimulatorImpl', 'RealtimeEventLock']: + root_module.classes.remove(root_module['ns3::%s' % clsname]) + root_module.enums.remove(root_module['ns3::RealtimeSimulatorImpl::SynchronizationMode']) + + root_module.generate(out, '_ns3') + + out.close() + +if __name__ == '__main__': + main() + diff --git a/bindings/python/ns3modulegen_core_customizations.py b/bindings/python/ns3modulegen_core_customizations.py new file mode 100644 index 000000000..abbf5ba80 --- /dev/null +++ b/bindings/python/ns3modulegen_core_customizations.py @@ -0,0 +1,527 @@ +import re + +from pybindgen.typehandlers import base as typehandlers +from pybindgen import ReturnValue, Parameter +from pybindgen.cppmethod import CustomCppMethodWrapper, CustomCppConstructorWrapper +from pybindgen.typehandlers.codesink import MemoryCodeSink +from pybindgen.typehandlers import ctypeparser +from pybindgen import cppclass +import warnings + +from pybindgen.typehandlers.base import CodeGenerationError + +import sys + +class SmartPointerTransformation(typehandlers.TypeTransformation): + """ + This class provides a "type transformation" that tends to support + NS-3 smart pointers. Parameters such as "Ptr foo" are + transformed into something like Parameter.new("Foo*", "foo", + transfer_ownership=False). Return values such as Ptr are + transformed into ReturnValue.new("Foo*", + caller_owns_return=False). Since the underlying objects have + reference counting, PyBindGen does the right thing. + """ + def __init__(self): + super(SmartPointerTransformation, self).__init__() + self.rx = re.compile(r'(ns3::|::ns3::|)Ptr<([^>]+)>') + + def _get_untransformed_type_traits(self, name): + m = self.rx.match(name) + is_const = False + if m is None: + return None, False + else: + name1 = m.group(2).strip() + if name1.startswith('const '): + name1 = name1[len('const '):] + is_const = True + if name1.endswith(' const'): + name1 = name1[:-len(' const')] + is_const = True + new_name = name1+' *' + + if new_name.startswith('::'): + new_name = new_name[2:] + return new_name, is_const + + def get_untransformed_name(self, name): + new_name, dummy_is_const = self._get_untransformed_type_traits(name) + return new_name + + def create_type_handler(self, type_handler, *args, **kwargs): + if issubclass(type_handler, Parameter): + kwargs['transfer_ownership'] = False + elif issubclass(type_handler, ReturnValue): + kwargs['caller_owns_return'] = False + else: + raise AssertionError + + ## fix the ctype, add ns3:: namespace + orig_ctype, is_const = self._get_untransformed_type_traits(args[0]) + if is_const: + correct_ctype = 'ns3::Ptr< %s const >' % orig_ctype[:-2] + else: + correct_ctype = 'ns3::Ptr< %s >' % orig_ctype[:-2] + args = tuple([correct_ctype] + list(args[1:])) + + handler = type_handler(*args, **kwargs) + handler.set_tranformation(self, orig_ctype) + return handler + + def untransform(self, type_handler, declarations, code_block, expression): + return 'const_cast<%s> (ns3::PeekPointer (%s))' % (type_handler.untransformed_ctype, expression) + + def transform(self, type_handler, declarations, code_block, expression): + assert type_handler.untransformed_ctype[-1] == '*' + return 'ns3::Ptr< %s > (%s)' % (type_handler.untransformed_ctype[:-1], expression) + +## register the type transformation +transf = SmartPointerTransformation() +typehandlers.return_type_matcher.register_transformation(transf) +typehandlers.param_type_matcher.register_transformation(transf) +del transf + + +class ArgvParam(Parameter): + """ + Converts a python list-of-strings argument to a pair of 'int argc, + char *argv[]' arguments to pass into C. + + One Python argument becomes two C function arguments -> it's a miracle! + + Note: this parameter type handler is not registered by any name; + must be used explicitly. + """ + + DIRECTIONS = [Parameter.DIRECTION_IN] + CTYPES = [] + + def convert_c_to_python(self, wrapper): + raise NotImplementedError + + def convert_python_to_c(self, wrapper): + py_name = wrapper.declarations.declare_variable('PyObject*', 'py_' + self.name) + argc_var = wrapper.declarations.declare_variable('int', 'argc') + name = wrapper.declarations.declare_variable('char**', self.name) + idx = wrapper.declarations.declare_variable('Py_ssize_t', 'idx') + wrapper.parse_params.add_parameter('O!', ['&PyList_Type', '&'+py_name], self.name) + + #wrapper.before_call.write_error_check('!PyList_Check(%s)' % py_name) # XXX + + wrapper.before_call.write_code("%s = (char **) malloc(sizeof(char*)*PyList_Size(%s));" + % (name, py_name)) + wrapper.before_call.add_cleanup_code('free(%s);' % name) + wrapper.before_call.write_code(''' +for (%(idx)s = 0; %(idx)s < PyList_Size(%(py_name)s); %(idx)s++) +{ +''' % vars()) + wrapper.before_call.sink.indent() + wrapper.before_call.write_code(''' +PyObject *item = PyList_GET_ITEM(%(py_name)s, %(idx)s); +''' % vars()) + #wrapper.before_call.write_error_check('item == NULL') + wrapper.before_call.write_error_check( + '!PyString_Check(item)', + failure_cleanup=('PyErr_SetString(PyExc_TypeError, ' + '"argument %s must be a list of strings");') % self.name) + wrapper.before_call.write_code( + '%s[%s] = PyString_AsString(item);' % (name, idx)) + wrapper.before_call.sink.unindent() + wrapper.before_call.write_code('}') + wrapper.before_call.write_code('%s = PyList_Size(%s);' % (argc_var, py_name)) + + wrapper.call_params.append(argc_var) + wrapper.call_params.append(name) + + +class CallbackImplProxyMethod(typehandlers.ReverseWrapperBase): + """ + Class that generates a proxy virtual method that calls a similarly named python method. + """ + + def __init__(self, return_value, parameters): + super(CallbackImplProxyMethod, self).__init__(return_value, parameters) + + def generate_python_call(self): + """code to call the python method""" + build_params = self.build_params.get_parameters(force_tuple_creation=True) + if build_params[0][0] == '"': + build_params[0] = '(char *) ' + build_params[0] + args = self.before_call.declare_variable('PyObject*', 'args') + self.before_call.write_code('%s = Py_BuildValue(%s);' + % (args, ', '.join(build_params))) + self.before_call.add_cleanup_code('Py_DECREF(%s);' % args) + self.before_call.write_code('py_retval = PyObject_CallObject(m_callback, %s);' % args) + self.before_call.write_error_check('py_retval == NULL') + self.before_call.add_cleanup_code('Py_DECREF(py_retval);') + + + + +def generate_callback_classes(out, callbacks): + for callback_impl_num, template_parameters in enumerate(callbacks): + sink = MemoryCodeSink() + cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) + #print >> sys.stderr, "***** trying to register callback: %r" % cls_name + class_name = "PythonCallbackImpl%i" % callback_impl_num + sink.writeln(''' +class %s : public ns3::CallbackImpl<%s> +{ +public: + PyObject *m_callback; + %s(PyObject *callback) + { + Py_INCREF(callback); + m_callback = callback; + } + virtual ~%s() + { + Py_DECREF(m_callback); + m_callback = NULL; + } + + virtual bool IsEqual(ns3::Ptr other_base) const + { + const %s *other = dynamic_cast (ns3::PeekPointer (other_base)); + if (other != NULL) + return (other->m_callback == m_callback); + else + return false; + } + +''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) + sink.indent() + callback_return = template_parameters[0] + return_ctype = ctypeparser.parse_type(callback_return) + if ('const' in return_ctype.remove_modifiers()): + kwargs = {'is_const': True} + else: + kwargs = {} + try: + return_type = ReturnValue.new(str(return_ctype), **kwargs) + except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: + warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r" + % (callback_return, cls_name, ex), + Warning) + continue + + arguments = [] + ok = True + callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty'] + for arg_num, arg_type in enumerate(callback_parameters): + arg_name = 'arg%i' % (arg_num+1) + + param_ctype = ctypeparser.parse_type(arg_type) + if ('const' in param_ctype.remove_modifiers()): + kwargs = {'is_const': True} + else: + kwargs = {} + try: + arguments.append(Parameter.new(str(param_ctype), arg_name, **kwargs)) + except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError), ex: + warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r" + % (arg_type, arg_name, cls_name, ex), + Warning) + ok = False + if not ok: + continue + + wrapper = CallbackImplProxyMethod(return_type, arguments) + wrapper.generate(sink, 'operator()', decl_modifiers=[]) + + sink.unindent() + sink.writeln('};\n') + sink.flush_to(out) + + class PythonCallbackParameter(Parameter): + "Class handlers" + CTYPES = [cls_name] + #print >> sys.stderr, "***** registering callback handler: %r" % ctypeparser.normalize_type_string(cls_name) + DIRECTIONS = [Parameter.DIRECTION_IN] + PYTHON_CALLBACK_IMPL_NAME = class_name + TEMPLATE_ARGS = template_parameters + + def convert_python_to_c(self, wrapper): + "parses python args to get C++ value" + assert isinstance(wrapper, typehandlers.ForwardWrapperBase) + + py_callback = wrapper.declarations.declare_variable('PyObject*', self.name) + wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name) + wrapper.before_call.write_error_check( + '!PyCallable_Check(%s)' % py_callback, + 'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name) + callback_impl = wrapper.declarations.declare_variable( + 'ns3::Ptr<%s>' % self.PYTHON_CALLBACK_IMPL_NAME, + '%s_cb_impl' % self.name) + wrapper.before_call.write_code("%s = ns3::Create<%s> (%s);" + % (callback_impl, self.PYTHON_CALLBACK_IMPL_NAME, py_callback)) + wrapper.call_params.append( + 'ns3::Callback<%s> (%s)' % (', '.join(self.TEMPLATE_ARGS), callback_impl)) + + def convert_c_to_python(self, wrapper): + raise typehandlers.NotSupportedError("Reverse wrappers for ns3::Callback<...> types " + "(python using callbacks defined in C++) not implemented.") + + +# def write_preamble(out): +# pybindgen.write_preamble(out) +# out.writeln("#include \"ns3/everything.h\"") + + + +def Simulator_customizations(module): + Simulator = module['ns3::Simulator'] + + ## Simulator::Schedule(delay, callback, ...user..args...) + Simulator.add_custom_method_wrapper("Schedule", "_wrap_Simulator_Schedule", + flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) + + + ## Simulator::ScheduleNow(callback, ...user..args...) + Simulator.add_custom_method_wrapper("ScheduleNow", "_wrap_Simulator_ScheduleNow", + flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) + + + ## Simulator::ScheduleDestroy(callback, ...user..args...) + Simulator.add_custom_method_wrapper("ScheduleDestroy", "_wrap_Simulator_ScheduleDestroy", + flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) + + +def CommandLine_customizations(module): + CommandLine = module['ns3::CommandLine'] + CommandLine.add_method('Parse', None, [ArgvParam(None, 'argv')], + is_static=False) + + +def Object_customizations(module): + ## --------------------------------------------------------------------- + ## Here we generate custom constructor code for all classes that + ## derive from ns3::Object. The custom constructors are needed in + ## order to support kwargs only and to translate kwargs into ns3 + ## attributes, etc. + ## --------------------------------------------------------------------- + Object = module['ns3::Object'] + + + ## add a GetTypeId method to all generatd helper classes + def helper_class_hook(helper_class): + decl = """ +static ns3::TypeId GetTypeId (void) +{ + static ns3::TypeId tid = ns3::TypeId ("%s") + .SetParent< %s > () + ; + return tid; +}""" % (helper_class.name, helper_class.class_.full_name) + + helper_class.add_custom_method(decl) + helper_class.add_post_generation_code( + "NS_OBJECT_ENSURE_REGISTERED (%s);" % helper_class.name) + Object.add_helper_class_hook(helper_class_hook) + + ## Replace all class constructors with a generic constructor based on CreateObject (AttributeList) + module.header.writeln(''' +namespace ns3 { + +void PythonCompleteConstruct (Ptr object, TypeId typeId, const AttributeList &attributes); + +template +Ptr CreateObjectPython (PyObject *pyobj, const AttributeList &attributes) +{ + Ptr p = Ptr (new T (), false); + p->set_pyobj (pyobj); + PythonCompleteConstruct (p, T::GetTypeId (), attributes); + return p; +} + +} // namespace ns3 + +''') + + for cls in module.classes: + if not cls.is_subclass(Object): + continue + cls.constructors = [] # clear the list of constructors + + ## add our own custom constructor, if possible + try: + construct_name = cls.get_construct_name() + except CodeGenerationError: + construct_name = None + + if construct_name and not cls.helper_class: + construct_code = ''' + ns3::Ptr< %(CONSTRUCT_NAME)s > obj = ns3::CreateObject< %(CONSTRUCT_NAME)s > (attrList); + obj->Ref (); + self->obj = ns3::PeekPointer (obj); +''' % dict (CONSTRUCT_NAME=construct_name) + + elif not construct_name and not cls.helper_class: + continue + + elif not construct_name and cls.helper_class: + construct_code = ''' + if (self->ob_type != &%(PYTYPESTRUCT)s) + { + ns3::Ptr< %(HELPER_CLASS_NAME)s > obj = ns3::CreateObjectPython< %(HELPER_CLASS_NAME)s > ((PyObject *)self, attrList); + obj->Ref (); + self->obj = ns3::PeekPointer (obj); + } else { + PyErr_SetString(PyExc_TypeError, "Class cannot be constructed (unless subclassed)"); + { + PyObject *exc_type, *traceback; + PyErr_Fetch(&exc_type, return_exception, &traceback); + Py_XDECREF(exc_type); + Py_XDECREF(traceback); + } + return -1; + } +''' % dict (CONSTRUCT_NAME=construct_name, HELPER_CLASS_NAME=cls.helper_class.name, + PYTYPESTRUCT=cls.pytypestruct) + + elif construct_name and cls.helper_class: + construct_code = ''' + if (self->ob_type != &%(PYTYPESTRUCT)s) + { + ns3::Ptr< %(HELPER_CLASS_NAME)s > obj = ns3::CreateObjectPython< %(HELPER_CLASS_NAME)s > ((PyObject *)self, attrList); + obj->Ref (); + self->obj = ns3::PeekPointer (obj); + } else { + ns3::Ptr< %(CONSTRUCT_NAME)s > obj = ns3::CreateObject< %(CONSTRUCT_NAME)s > (attrList); + obj->Ref (); + self->obj = ns3::PeekPointer (obj); + } +''' % dict (CONSTRUCT_NAME=construct_name, HELPER_CLASS_NAME=cls.helper_class.name, + PYTYPESTRUCT=cls.pytypestruct) + else: + raise AssertionError + + wrapper_name = "_wrap_create_object_%s" % (cls.mangled_full_name,) + constructor = ''' +static int %(WRAPPER_NAME)s (%(PYSTRUCT)s *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) +{ + if (PyTuple_Size(args)) { + PyErr_SetString(PyExc_TypeError, "positional arguments not supported " + "for ns3.Object constructors, only keyword arguments" + " should be used (AttributeName=Value)"); + { + PyObject *exc_type, *traceback; + PyErr_Fetch(&exc_type, return_exception, &traceback); + Py_XDECREF(exc_type); + Py_XDECREF(traceback); + } + return -1; + } + ns3::AttributeList attrList; + if (kwargs && KwargsToAttributeList(kwargs, %(CLASS_NAME)s::GetTypeId(), attrList)) { + { + PyObject *exc_type, *traceback; + PyErr_Fetch(&exc_type, return_exception, &traceback); + Py_XDECREF(exc_type); + Py_XDECREF(traceback); + } + return -1; + } + %(CONSTRUCT_CODE)s + PyNs3ObjectBase_wrapper_registry[(void *) self->obj] = (PyObject *) self; + return 0; +} +''' % dict(WRAPPER_NAME=wrapper_name, PYSTRUCT=cls.pystruct, CLASS_NAME=cls.full_name, + CONSTRUCT_CODE=construct_code, PURE_VIRTUALS=cls.have_pure_virtual_methods) + cls.add_constructor(CustomCppConstructorWrapper(wrapper_name, constructor)) + + + # Generate conversion function from PyObject* to AttributeValue +# sink = module.body +# sink.writeln(''' +# Ptr AttributeValueFromPyObject (PyObject *obj) +# { +# // note: needs to check for bool first, because bool is a subclass of int +# if (PyBool_Check(obj)) { +# return Create(PyObject_IsTrue(obj)); +# } else if (PyInt_Check(obj)) { +# return Create(PyInt_AsLong(obj)); +# } else if (PyLong_Check(obj)) { +# return Create(PyLong_AsLongLong(obj)); +# } else if (PyFloat_Check(obj)) { +# return Create(PyFloat_AsDouble(obj)); +# } + +# ''') + + + + ## --------------------------------------------------------------------- + ## -------------- write the KwargsToAttributeList function ------------- + ## --------------------------------------------------------------------- + Attribute = module['ns3::AttributeValue'] + module.after_forward_declarations.writeln( + 'int KwargsToAttributeList(PyObject *kwargs, ns3::TypeId tid, ns3::AttributeList &oAttrList);') + + module.body.writeln( +''' +int KwargsToAttributeList(PyObject *kwargs, ns3::TypeId tid, ns3::AttributeList &oAttrList) +{ + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(kwargs, &pos, &key, &value)) { + if (!PyString_Check(key)) { + PyErr_SetString(PyExc_TypeError, "kwargs keys must be strings"); + return -1; + } + if (PyObject_IsInstance(value, (PyObject*) &%s)) { + oAttrList.SetWithTid(tid, PyString_AsString(key), *((%s *) value)->obj);''' \ + % (Attribute.pytypestruct, Attribute.pystruct)) + + for conversion_source in Attribute.get_all_implicit_conversions(): + module.body.writeln(''' + } else if (PyObject_IsInstance(value, (PyObject*) &%s)) { + oAttrList.SetWithTid(tid, PyString_AsString(key), *((%s *) value)->obj);''' \ + % (conversion_source.pytypestruct, conversion_source.pystruct)) + + possible_type_names = ", ".join([cls.name for cls in [Attribute] + Attribute.get_all_implicit_conversions()]) + module.body.writeln(''' + } else { + PyErr_Format(PyExc_TypeError, \"parameter must an instance of one of the types (%s), not %%s\", value->ob_type->tp_name); + return -1; + }''' % (possible_type_names)) + + module.body.writeln( +''' + } + return 0; +} +''') + + +def Attribute_customizations(module): + # Fix up for the "const AttributeValue &v = EmptyAttribute()" + # case, as used extensively by helper classes. + + # Here's why we need to do this: pybindgen.gccxmlscanner, when + # scanning parameter default values, is only provided with the + # value as a simple C expression string. (py)gccxml does not + # report the type of the default value. + + # As a workaround, here we iterate over all parameters of all + # methods of all classes and tell pybindgen what is the type of + # the default value for attributes. + + for cls in module.classes: + for meth in cls.get_all_methods(): + for param in meth.parameters: + if isinstance(param, cppclass.CppClassRefParameter): + if param.cpp_class.name == 'AttributeValue' \ + and param.default_value is not None \ + and param.default_value_type is None: + param.default_value_type = 'ns3::EmptyAttributeValue' + + +def TypeId_customizations(module): + TypeId = module['ns3::TypeId'] + TypeId.add_custom_method_wrapper("LookupByNameFailSafe", "_wrap_TypeId_LookupByNameFailSafe", + flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) + + diff --git a/bindings/python/ns3modulegen_generated.py b/bindings/python/ns3modulegen_generated.py new file mode 100644 index 000000000..c2aad704d --- /dev/null +++ b/bindings/python/ns3modulegen_generated.py @@ -0,0 +1,712 @@ +from pybindgen import Module, FileCodeSink, param, retval, cppclass + + +import pybindgen.settings +import warnings + +class ErrorHandler(pybindgen.settings.ErrorHandler): + def handle_error(self, wrapper, exception, traceback_): + warnings.warn("exception %r in wrapper %s" % (exception, wrapper)) + return True +pybindgen.settings.error_handler = ErrorHandler() + + +import sys +import ns3_module_core +import ns3_module_simulator +import ns3_module_mobility +import ns3_module_common +import ns3_module_contrib +import ns3_module_node +import ns3_module_point_to_point +import ns3_module_stats +import ns3_module_internet_stack +import ns3_module_wifi +import ns3_module_csma +import ns3_module_bridge +import ns3_module_packet_sink +import ns3_module_global_routing +import ns3_module_onoff +import ns3_module_olsr +import ns3_module_udp_echo +import ns3_module_helper + +def module_init(): + root_module = Module('ns3', cpp_namespace='::ns3') + return root_module + +def register_types(module): + root_module = module.get_root() + + root_module.begin_section('ns3_module_core') + ns3_module_core.register_types(module) + + try: + import ns3_module_core__local + except ImportError: + pass + else: + ns3_module_core__local.register_types(module) + + root_module.end_section('ns3_module_core') + root_module.begin_section('ns3_module_simulator') + ns3_module_simulator.register_types(module) + + try: + import ns3_module_simulator__local + except ImportError: + pass + else: + ns3_module_simulator__local.register_types(module) + + root_module.end_section('ns3_module_simulator') + root_module.begin_section('ns3_module_mobility') + ns3_module_mobility.register_types(module) + + try: + import ns3_module_mobility__local + except ImportError: + pass + else: + ns3_module_mobility__local.register_types(module) + + root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_common') + ns3_module_common.register_types(module) + + try: + import ns3_module_common__local + except ImportError: + pass + else: + ns3_module_common__local.register_types(module) + + root_module.end_section('ns3_module_common') + root_module.begin_section('ns3_module_contrib') + ns3_module_contrib.register_types(module) + + try: + import ns3_module_contrib__local + except ImportError: + pass + else: + ns3_module_contrib__local.register_types(module) + + root_module.end_section('ns3_module_contrib') + root_module.begin_section('ns3_module_node') + ns3_module_node.register_types(module) + + try: + import ns3_module_node__local + except ImportError: + pass + else: + ns3_module_node__local.register_types(module) + + root_module.end_section('ns3_module_node') + root_module.begin_section('ns3_module_point_to_point') + ns3_module_point_to_point.register_types(module) + + try: + import ns3_module_point_to_point__local + except ImportError: + pass + else: + ns3_module_point_to_point__local.register_types(module) + + root_module.end_section('ns3_module_point_to_point') + root_module.begin_section('ns3_module_stats') + ns3_module_stats.register_types(module) + + try: + import ns3_module_stats__local + except ImportError: + pass + else: + ns3_module_stats__local.register_types(module) + + root_module.end_section('ns3_module_stats') + root_module.begin_section('ns3_module_internet_stack') + ns3_module_internet_stack.register_types(module) + + try: + import ns3_module_internet_stack__local + except ImportError: + pass + else: + ns3_module_internet_stack__local.register_types(module) + + root_module.end_section('ns3_module_internet_stack') + root_module.begin_section('ns3_module_wifi') + ns3_module_wifi.register_types(module) + + try: + import ns3_module_wifi__local + except ImportError: + pass + else: + ns3_module_wifi__local.register_types(module) + + root_module.end_section('ns3_module_wifi') + root_module.begin_section('ns3_module_csma') + ns3_module_csma.register_types(module) + + try: + import ns3_module_csma__local + except ImportError: + pass + else: + ns3_module_csma__local.register_types(module) + + root_module.end_section('ns3_module_csma') + root_module.begin_section('ns3_module_bridge') + ns3_module_bridge.register_types(module) + + try: + import ns3_module_bridge__local + except ImportError: + pass + else: + ns3_module_bridge__local.register_types(module) + + root_module.end_section('ns3_module_bridge') + root_module.begin_section('ns3_module_packet_sink') + ns3_module_packet_sink.register_types(module) + + try: + import ns3_module_packet_sink__local + except ImportError: + pass + else: + ns3_module_packet_sink__local.register_types(module) + + root_module.end_section('ns3_module_packet_sink') + root_module.begin_section('ns3_module_global_routing') + ns3_module_global_routing.register_types(module) + + try: + import ns3_module_global_routing__local + except ImportError: + pass + else: + ns3_module_global_routing__local.register_types(module) + + root_module.end_section('ns3_module_global_routing') + root_module.begin_section('ns3_module_onoff') + ns3_module_onoff.register_types(module) + + try: + import ns3_module_onoff__local + except ImportError: + pass + else: + ns3_module_onoff__local.register_types(module) + + root_module.end_section('ns3_module_onoff') + root_module.begin_section('ns3_module_olsr') + ns3_module_olsr.register_types(module) + + try: + import ns3_module_olsr__local + except ImportError: + pass + else: + ns3_module_olsr__local.register_types(module) + + root_module.end_section('ns3_module_olsr') + root_module.begin_section('ns3_module_udp_echo') + ns3_module_udp_echo.register_types(module) + + try: + import ns3_module_udp_echo__local + except ImportError: + pass + else: + ns3_module_udp_echo__local.register_types(module) + + root_module.end_section('ns3_module_udp_echo') + root_module.begin_section('ns3_module_helper') + ns3_module_helper.register_types(module) + + try: + import ns3_module_helper__local + except ImportError: + pass + else: + ns3_module_helper__local.register_types(module) + + root_module.end_section('ns3_module_helper') + module.add_container('std::vector< unsigned int >', 'unsigned int', container_type='vector') + module.add_container('std::list< unsigned int >', 'unsigned int', container_type='list') + + ## Register a nested module for the namespace internal + + nested_module = module.add_cpp_namespace('internal') + register_types_ns3_internal(nested_module) + + + ## Register a nested module for the namespace TimeStepPrecision + + nested_module = module.add_cpp_namespace('TimeStepPrecision') + register_types_ns3_TimeStepPrecision(nested_module) + + + ## Register a nested module for the namespace Config + + nested_module = module.add_cpp_namespace('Config') + register_types_ns3_Config(nested_module) + + + ## Register a nested module for the namespace olsr + + nested_module = module.add_cpp_namespace('olsr') + register_types_ns3_olsr(nested_module) + + +def register_types_ns3_internal(module): + root_module = module.get_root() + + +def register_types_ns3_TimeStepPrecision(module): + root_module = module.get_root() + + +def register_types_ns3_Config(module): + root_module = module.get_root() + + module.add_container('std::vector< std::string >', 'std::string', container_type='vector') + +def register_types_ns3_olsr(module): + root_module = module.get_root() + + +def register_methods(root_module): + root_module.begin_section('ns3_module_core') + ns3_module_core.register_methods(root_module) + + try: + import ns3_module_core__local + except ImportError: + pass + else: + ns3_module_core__local.register_methods(root_module) + + root_module.end_section('ns3_module_core') + root_module.begin_section('ns3_module_simulator') + ns3_module_simulator.register_methods(root_module) + + try: + import ns3_module_simulator__local + except ImportError: + pass + else: + ns3_module_simulator__local.register_methods(root_module) + + root_module.end_section('ns3_module_simulator') + root_module.begin_section('ns3_module_mobility') + ns3_module_mobility.register_methods(root_module) + + try: + import ns3_module_mobility__local + except ImportError: + pass + else: + ns3_module_mobility__local.register_methods(root_module) + + root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_common') + ns3_module_common.register_methods(root_module) + + try: + import ns3_module_common__local + except ImportError: + pass + else: + ns3_module_common__local.register_methods(root_module) + + root_module.end_section('ns3_module_common') + root_module.begin_section('ns3_module_contrib') + ns3_module_contrib.register_methods(root_module) + + try: + import ns3_module_contrib__local + except ImportError: + pass + else: + ns3_module_contrib__local.register_methods(root_module) + + root_module.end_section('ns3_module_contrib') + root_module.begin_section('ns3_module_node') + ns3_module_node.register_methods(root_module) + + try: + import ns3_module_node__local + except ImportError: + pass + else: + ns3_module_node__local.register_methods(root_module) + + root_module.end_section('ns3_module_node') + root_module.begin_section('ns3_module_point_to_point') + ns3_module_point_to_point.register_methods(root_module) + + try: + import ns3_module_point_to_point__local + except ImportError: + pass + else: + ns3_module_point_to_point__local.register_methods(root_module) + + root_module.end_section('ns3_module_point_to_point') + root_module.begin_section('ns3_module_stats') + ns3_module_stats.register_methods(root_module) + + try: + import ns3_module_stats__local + except ImportError: + pass + else: + ns3_module_stats__local.register_methods(root_module) + + root_module.end_section('ns3_module_stats') + root_module.begin_section('ns3_module_internet_stack') + ns3_module_internet_stack.register_methods(root_module) + + try: + import ns3_module_internet_stack__local + except ImportError: + pass + else: + ns3_module_internet_stack__local.register_methods(root_module) + + root_module.end_section('ns3_module_internet_stack') + root_module.begin_section('ns3_module_wifi') + ns3_module_wifi.register_methods(root_module) + + try: + import ns3_module_wifi__local + except ImportError: + pass + else: + ns3_module_wifi__local.register_methods(root_module) + + root_module.end_section('ns3_module_wifi') + root_module.begin_section('ns3_module_csma') + ns3_module_csma.register_methods(root_module) + + try: + import ns3_module_csma__local + except ImportError: + pass + else: + ns3_module_csma__local.register_methods(root_module) + + root_module.end_section('ns3_module_csma') + root_module.begin_section('ns3_module_bridge') + ns3_module_bridge.register_methods(root_module) + + try: + import ns3_module_bridge__local + except ImportError: + pass + else: + ns3_module_bridge__local.register_methods(root_module) + + root_module.end_section('ns3_module_bridge') + root_module.begin_section('ns3_module_packet_sink') + ns3_module_packet_sink.register_methods(root_module) + + try: + import ns3_module_packet_sink__local + except ImportError: + pass + else: + ns3_module_packet_sink__local.register_methods(root_module) + + root_module.end_section('ns3_module_packet_sink') + root_module.begin_section('ns3_module_global_routing') + ns3_module_global_routing.register_methods(root_module) + + try: + import ns3_module_global_routing__local + except ImportError: + pass + else: + ns3_module_global_routing__local.register_methods(root_module) + + root_module.end_section('ns3_module_global_routing') + root_module.begin_section('ns3_module_onoff') + ns3_module_onoff.register_methods(root_module) + + try: + import ns3_module_onoff__local + except ImportError: + pass + else: + ns3_module_onoff__local.register_methods(root_module) + + root_module.end_section('ns3_module_onoff') + root_module.begin_section('ns3_module_olsr') + ns3_module_olsr.register_methods(root_module) + + try: + import ns3_module_olsr__local + except ImportError: + pass + else: + ns3_module_olsr__local.register_methods(root_module) + + root_module.end_section('ns3_module_olsr') + root_module.begin_section('ns3_module_udp_echo') + ns3_module_udp_echo.register_methods(root_module) + + try: + import ns3_module_udp_echo__local + except ImportError: + pass + else: + ns3_module_udp_echo__local.register_methods(root_module) + + root_module.end_section('ns3_module_udp_echo') + root_module.begin_section('ns3_module_helper') + ns3_module_helper.register_methods(root_module) + + try: + import ns3_module_helper__local + except ImportError: + pass + else: + ns3_module_helper__local.register_methods(root_module) + + root_module.end_section('ns3_module_helper') + return + +def register_functions(root_module): + module = root_module + root_module.begin_section('ns3_module_core') + ns3_module_core.register_functions(root_module) + + try: + import ns3_module_core__local + except ImportError: + pass + else: + ns3_module_core__local.register_functions(root_module) + + root_module.end_section('ns3_module_core') + root_module.begin_section('ns3_module_simulator') + ns3_module_simulator.register_functions(root_module) + + try: + import ns3_module_simulator__local + except ImportError: + pass + else: + ns3_module_simulator__local.register_functions(root_module) + + root_module.end_section('ns3_module_simulator') + root_module.begin_section('ns3_module_mobility') + ns3_module_mobility.register_functions(root_module) + + try: + import ns3_module_mobility__local + except ImportError: + pass + else: + ns3_module_mobility__local.register_functions(root_module) + + root_module.end_section('ns3_module_mobility') + root_module.begin_section('ns3_module_common') + ns3_module_common.register_functions(root_module) + + try: + import ns3_module_common__local + except ImportError: + pass + else: + ns3_module_common__local.register_functions(root_module) + + root_module.end_section('ns3_module_common') + root_module.begin_section('ns3_module_contrib') + ns3_module_contrib.register_functions(root_module) + + try: + import ns3_module_contrib__local + except ImportError: + pass + else: + ns3_module_contrib__local.register_functions(root_module) + + root_module.end_section('ns3_module_contrib') + root_module.begin_section('ns3_module_node') + ns3_module_node.register_functions(root_module) + + try: + import ns3_module_node__local + except ImportError: + pass + else: + ns3_module_node__local.register_functions(root_module) + + root_module.end_section('ns3_module_node') + root_module.begin_section('ns3_module_point_to_point') + ns3_module_point_to_point.register_functions(root_module) + + try: + import ns3_module_point_to_point__local + except ImportError: + pass + else: + ns3_module_point_to_point__local.register_functions(root_module) + + root_module.end_section('ns3_module_point_to_point') + root_module.begin_section('ns3_module_stats') + ns3_module_stats.register_functions(root_module) + + try: + import ns3_module_stats__local + except ImportError: + pass + else: + ns3_module_stats__local.register_functions(root_module) + + root_module.end_section('ns3_module_stats') + root_module.begin_section('ns3_module_internet_stack') + ns3_module_internet_stack.register_functions(root_module) + + try: + import ns3_module_internet_stack__local + except ImportError: + pass + else: + ns3_module_internet_stack__local.register_functions(root_module) + + root_module.end_section('ns3_module_internet_stack') + root_module.begin_section('ns3_module_wifi') + ns3_module_wifi.register_functions(root_module) + + try: + import ns3_module_wifi__local + except ImportError: + pass + else: + ns3_module_wifi__local.register_functions(root_module) + + root_module.end_section('ns3_module_wifi') + root_module.begin_section('ns3_module_csma') + ns3_module_csma.register_functions(root_module) + + try: + import ns3_module_csma__local + except ImportError: + pass + else: + ns3_module_csma__local.register_functions(root_module) + + root_module.end_section('ns3_module_csma') + root_module.begin_section('ns3_module_bridge') + ns3_module_bridge.register_functions(root_module) + + try: + import ns3_module_bridge__local + except ImportError: + pass + else: + ns3_module_bridge__local.register_functions(root_module) + + root_module.end_section('ns3_module_bridge') + root_module.begin_section('ns3_module_packet_sink') + ns3_module_packet_sink.register_functions(root_module) + + try: + import ns3_module_packet_sink__local + except ImportError: + pass + else: + ns3_module_packet_sink__local.register_functions(root_module) + + root_module.end_section('ns3_module_packet_sink') + root_module.begin_section('ns3_module_global_routing') + ns3_module_global_routing.register_functions(root_module) + + try: + import ns3_module_global_routing__local + except ImportError: + pass + else: + ns3_module_global_routing__local.register_functions(root_module) + + root_module.end_section('ns3_module_global_routing') + root_module.begin_section('ns3_module_onoff') + ns3_module_onoff.register_functions(root_module) + + try: + import ns3_module_onoff__local + except ImportError: + pass + else: + ns3_module_onoff__local.register_functions(root_module) + + root_module.end_section('ns3_module_onoff') + root_module.begin_section('ns3_module_olsr') + ns3_module_olsr.register_functions(root_module) + + try: + import ns3_module_olsr__local + except ImportError: + pass + else: + ns3_module_olsr__local.register_functions(root_module) + + root_module.end_section('ns3_module_olsr') + root_module.begin_section('ns3_module_udp_echo') + ns3_module_udp_echo.register_functions(root_module) + + try: + import ns3_module_udp_echo__local + except ImportError: + pass + else: + ns3_module_udp_echo__local.register_functions(root_module) + + root_module.end_section('ns3_module_udp_echo') + root_module.begin_section('ns3_module_helper') + ns3_module_helper.register_functions(root_module) + + try: + import ns3_module_helper__local + except ImportError: + pass + else: + ns3_module_helper__local.register_functions(root_module) + + root_module.end_section('ns3_module_helper') + register_functions_ns3_internal(module.get_submodule('internal'), root_module) + register_functions_ns3_TimeStepPrecision(module.get_submodule('TimeStepPrecision'), root_module) + register_functions_ns3_Config(module.get_submodule('Config'), root_module) + register_functions_ns3_olsr(module.get_submodule('olsr'), root_module) + return + +def register_functions_ns3_internal(module, root_module): + return + +def register_functions_ns3_TimeStepPrecision(module, root_module): + return + +def register_functions_ns3_Config(module, root_module): + return + +def register_functions_ns3_olsr(module, root_module): + return + +def main(): + out = FileCodeSink(sys.stdout) + root_module = module_init() + register_types(root_module) + register_methods(root_module) + register_functions(root_module) + root_module.generate(out) + +if __name__ == '__main__': + main() + diff --git a/bindings/python/ns3modulescan.py b/bindings/python/ns3modulescan.py new file mode 100644 index 000000000..4b0684879 --- /dev/null +++ b/bindings/python/ns3modulescan.py @@ -0,0 +1,295 @@ +#! /usr/bin/env python + +import sys +import os.path + +import pybindgen.settings +from pybindgen.gccxmlparser import ModuleParser, PygenClassifier, PygenSection, WrapperWarning +from pybindgen.typehandlers.codesink import FileCodeSink +from pygccxml.declarations import templates +from pygccxml.declarations.class_declaration import class_t +from pygccxml.declarations.calldef import free_function_t, member_function_t, constructor_t + + +## we need the smart pointer type transformation to be active even +## during gccxml scanning. +import ns3modulegen_core_customizations + + +## silence gccxmlparser errors; we only want error handling in the +## generated python script, not while scanning. +class ErrorHandler(pybindgen.settings.ErrorHandler): + def handle_error(self, dummy_wrapper, dummy_exception, dummy_traceback_): + return True +pybindgen.settings.error_handler = ErrorHandler() +import warnings +warnings.filterwarnings(category=WrapperWarning, action='ignore') + +type_annotations = { + '::ns3::RefCountBase': { + 'incref_method': 'Ref', + 'decref_method': 'Unref', + 'peekref_method': 'GetReferenceCount', + 'automatic_type_narrowing': 'true', + }, + '::ns3::Object': { + 'incref_method': 'Ref', + 'decref_method': 'Unref', + 'peekref_method': 'GetReferenceCount', + 'automatic_type_narrowing': 'true', + }, + '::ns3::Packet': { + 'incref_method': 'Ref', + 'decref_method': 'Unref', + 'peekref_method': 'GetReferenceCount', + }, + '::ns3::CallbackImplBase': { + 'incref_method': 'Ref', + 'decref_method': 'Unref', + 'peekref_method': 'GetReferenceCount', + }, + '::ns3::AttributeChecker': { + 'automatic_type_narrowing': 'true', + 'allow_subclassing': 'false', + }, + '::ns3::AttributeValue': { + 'automatic_type_narrowing': 'true', + 'allow_subclassing': 'false', + }, + 'ns3::RandomVariable::RandomVariable(ns3::RandomVariableBase const & variable) [constructor]': { + 'ignore': None, + }, + 'ns3::RandomVariableBase * ns3::RandomVariable::Peek() const [member function]': { + 'ignore': None, + }, + 'void ns3::RandomVariable::GetSeed(uint32_t * seed) const [member function]': { + 'params': {'seed':{'direction':'out', + 'array_length':'6'}} + }, + 'bool ns3::TypeId::LookupAttributeByName(std::string name, ns3::TypeId::AttributeInfo * info) const [member function]': { + 'params': {'info':{'transfer_ownership': 'false'}} + }, + 'static bool ns3::TypeId::LookupByNameFailSafe(std::string name, ns3::TypeId * tid) [member function]': { + 'ignore': None, # manually wrapped in + }, + 'bool ns3::TraceSourceAccessor::ConnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': { + 'params': {'obj': {'transfer_ownership':'false'}} + }, + 'bool ns3::TraceSourceAccessor::Connect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': { + 'params': {'obj': {'transfer_ownership':'false'}} + }, + 'bool ns3::TraceSourceAccessor::DisconnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': { + 'params': {'obj': {'transfer_ownership':'false'}} + }, + 'bool ns3::TraceSourceAccessor::Disconnect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': { + 'params': {'obj': {'transfer_ownership':'false'}} + }, + 'bool ns3::AttributeAccessor::Set(ns3::ObjectBase * object, ns3::AttributeValue const & value) const [member function]': { + 'params': {'object': {'transfer_ownership':'false'}} + }, + 'ns3::EmpiricalVariable::EmpiricalVariable(ns3::RandomVariableBase const & variable) [constructor]': { + 'ignore': None + }, + 'static ns3::AttributeList * ns3::AttributeList::GetGlobal() [member function]': { + 'caller_owns_return': 'false' + }, + 'void ns3::CommandLine::Parse(int argc, char * * argv) const [member function]': { + 'ignore': None # manually wrapped + }, + 'extern void ns3::PythonCompleteConstruct(ns3::Ptr object, ns3::TypeId typeId, ns3::AttributeList const & attributes) [free function]': { + 'ignore': None # used transparently by, should not be wrapped + }, + } + +def get_ns3_relative_path(path): + l = [] + head = path + while head: + head, tail = os.path.split(head) + if tail == 'ns3': + return os.path.join(*l) + l.insert(0, tail) + raise AssertionError("is the path %r inside ns3?!" % path) + + +def pre_scan_hook(dummy_module_parser, + pygccxml_definition, + global_annotations, + parameter_annotations): + ns3_header = get_ns3_relative_path(pygccxml_definition.location.file_name) + + ## Note: we don't include line numbers in the comments because + ## those numbers are very likely to change frequently, which would + ## cause needless changes, since the generated python files are + ## kept under version control. + + #global_annotations['pygen_comment'] = "%s:%i: %s" % \ + # (ns3_header, pygccxml_definition.location.line, pygccxml_definition) + global_annotations['pygen_comment'] = "%s: %s" % \ + (ns3_header, pygccxml_definition) + + + ## handle ns3::Object::GetObject (left to its own devices, + ## pybindgen will generate a mangled name containing the template + ## argument type name). + if isinstance(pygccxml_definition, member_function_t) \ + and pygccxml_definition.parent.name == 'Object' \ + and pygccxml_definition.name == 'GetObject': + template_args = templates.args(pygccxml_definition.demangled_name) + if template_args == ['ns3::Object']: + global_annotations['template_instance_names'] = 'ns3::Object=>GetObject' + + ## Don't wrap Simulator::Schedule* (manually wrapped) + if isinstance(pygccxml_definition, member_function_t) \ + and pygccxml_definition.parent.name == 'Simulator' \ + and pygccxml_definition.name.startswith('Schedule'): + global_annotations['ignore'] = None + + # unblock python threads for Simulator::Run + if isinstance(pygccxml_definition, member_function_t) \ + and pygccxml_definition.parent.name == 'Simulator' \ + and pygccxml_definition.name == 'Run': + global_annotations['unblock_threads'] = True + + + ## classes + if isinstance(pygccxml_definition, class_t): + # no need for helper classes to allow subclassing in Python, I think... + if pygccxml_definition.name.endswith('Helper'): + global_annotations['allow_subclassing'] = 'false' + + if pygccxml_definition.decl_string.startswith('::ns3::Callback<'): + # manually handled in ns3modulegen_core_customizations.py + global_annotations['ignore'] = None + return + + if pygccxml_definition.decl_string.startswith('::ns3::TracedCallback<'): + global_annotations['ignore'] = None + return + + if pygccxml_definition.decl_string.startswith('::ns3::Ptr<'): + # handled by pybindgen "type transformation" + global_annotations['ignore'] = None + return + + # table driven class customization + try: + annotations = type_annotations[pygccxml_definition.decl_string] + except KeyError: + pass + else: + global_annotations.update(annotations) + + ## free functions + if isinstance(pygccxml_definition, free_function_t): + if pygccxml_definition.name == 'PeekPointer': + global_annotations['ignore'] = None + return + + ## table driven methods/constructors/functions customization + if isinstance(pygccxml_definition, (free_function_t, member_function_t, constructor_t)): + try: + annotations = type_annotations[str(pygccxml_definition)] + except KeyError: + pass + else: + for key,value in annotations.items(): + if key == 'params': + parameter_annotations.update (value) + del annotations['params'] + global_annotations.update(annotations) + + +# def post_scan_hook(dummy_module_parser, dummy_pygccxml_definition, pybindgen_wrapper): +# ## classes +# if isinstance(pybindgen_wrapper, CppClass): +# if pybindgen_wrapper.name.endswith('Checker'): +# print >> sys.stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", pybindgen_wrapper +# #pybindgen_wrapper.set_instance_creation_function(AttributeChecker_instance_creation_function) + + +def scan_callback_classes(module_parser, callback_classes_file): + callback_classes_file.write("callback_classes = [\n") + for cls in module_parser.module_namespace.classes(function=module_parser.location_filter, + recursive=False): + if not cls.name.startswith("Callback<"): + continue + assert templates.is_instantiation(cls.decl_string), "%s is not a template instantiation" % cls + dummy_cls_name, template_parameters = templates.split(cls.decl_string) + callback_classes_file.write(" %r,\n" % template_parameters) + callback_classes_file.write("]\n") + + +class MyPygenClassifier(PygenClassifier): + def __init__(self, headers_map): + self.headers_map = headers_map + + def classify(self, pygccxml_definition): + name = os.path.basename(pygccxml_definition.location.file_name) + try: + return self.headers_map[name] + except KeyError: + return '__main__' + + +def ns3_module_scan(top_builddir, pygen_file_name, everything_h): + + ns3_modules = eval(sys.stdin.read()) + + ## do a topological sort on the modules graph + from topsort import topsort + graph = [] + for ns3_module_name, (ns3_module_deps, dummy) in ns3_modules.iteritems(): + for dep in ns3_module_deps: + graph.append((dep, ns3_module_name)) + sorted_ns3_modules = topsort(graph) + #print >> sys.stderr, "******* topological sort: ", sorted_ns3_modules + + sections = [PygenSection('__main__', FileCodeSink(open(pygen_file_name, "wt")))] + headers_map = {} # header_name -> section_name + for ns3_module in sorted_ns3_modules: + section_name = "ns3_module_%s" % ns3_module.replace('-', '_') + file_name = os.path.join(os.path.dirname(pygen_file_name), "%s.py" % section_name) + sections.append(PygenSection(section_name, FileCodeSink(open(file_name, "wt")), + section_name + "__local")) + for header in ns3_modules[ns3_module][1]: + headers_map[header] = section_name + + module_parser = ModuleParser('ns3', 'ns3') + + module_parser.add_pre_scan_hook(pre_scan_hook) + #module_parser.add_post_scan_hook(post_scan_hook) + + gccxml_options = dict( + include_paths=[top_builddir], + define_symbols={ + #'NS3_ASSERT_ENABLE': None, + #'NS3_LOG_ENABLE': None, + } + ) + + module_parser.parse_init([everything_h], + None, whitelist_paths=[top_builddir, os.path.dirname(everything_h)], + #includes=['"ns3/everything.h"'], + pygen_sink=sections, + pygen_classifier=MyPygenClassifier(headers_map), + gccxml_options=gccxml_options) + module_parser.scan_types() + + callback_classes_file = open(os.path.join(os.path.dirname(pygen_file_name), "callbacks_list.py"), "wt") + scan_callback_classes(module_parser, callback_classes_file) + callback_classes_file.close() + + + module_parser.scan_methods() + module_parser.scan_functions() + module_parser.parse_finalize() + + for section in sections: + section.code_sink.file.close() + + + +if __name__ == '__main__': + ns3_module_scan(sys.argv[1], sys.argv[3], sys.argv[2]) + diff --git a/bindings/python/rad_util.py b/bindings/python/rad_util.py new file mode 100644 index 000000000..bf6fc5592 --- /dev/null +++ b/bindings/python/rad_util.py @@ -0,0 +1,909 @@ +# Copyright (c) 2007 RADLogic +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +"""Provide various handy Python functions. + +Running this script directly will execute the doctests. + +Functions: +int2bin(i, n) -- Convert integer to binary string. +bin2int(bin_string) -- Convert binary string to integer. +reverse(input_string) -- Reverse a string. +transpose(matrix) -- Transpose a list of lists. +polygon_area(points_list) -- Calculate the area of an arbitrary polygon. +timestamp() -- Return string containing current time stamp. +pt2str(point) -- Return prettier string version of point tuple. +gcf(a, b) -- Return the greatest common factor of two numbers. +lcm(a, b) -- Return the least common multiple of two numbers. +permutations(input_list) -- Generate all permutations of a list of items. +reduce_fraction(fraction) -- Reduce fraction (num, denom) to simplest form. +quantile(l, p) -- Return p quantile of list l. E.g. p=0.25 for q1. +trim(l) -- Discard values in list more than 1.5*IQR outside IQR. +nice_units(value) -- Return value converted to human readable units. +uniquify(seq) -- Return sequence with duplicate items in sequence seq removed. +reverse_dict(d) -- Return the dictionary with the items as keys and vice-versa. +lsb(x, n) -- Return the n least significant bits of x. +gray_encode(i) -- Gray encode the given integer. +random_vec(bits, max_value=None) -- Return a random binary vector. +binary_range(bits) -- Return list of all possible binary numbers width=bits. +float_range([start], stop, [step]) -- Return range of floats. +find_common_fixes(s1, s2) -- Find common (prefix, suffix) of two strings. +is_rotated(seq1, seq2) -- Return true if the list is a rotation of other list. +getmodule(obj) -- Return the module that contains the object definition of obj. + (use inspect.getmodule instead, though) +get_args(argv) -- Store command-line args in a dictionary. + +This module requires Python >= 2.2 + +""" +__author__ = 'Tim Wegener ' +__date__ = '$Date: 2007/03/27 03:15:06 $' +__version__ = '$Revision: 0.45 $' +__credits__ = """ + David Chandler, for polygon area algorithm. + (http://www.davidchandler.com/AreaOfAGeneralPolygon.pdf) + """ + +import re +import sys +import time +import random + +try: + True, False +except NameError: + True, False = (1==1, 0==1) + + +def int2bin(i, n): + """Convert decimal integer i to n-bit binary number (string). + + >>> int2bin(0, 8) + '00000000' + + >>> int2bin(123, 8) + '01111011' + + >>> int2bin(123L, 8) + '01111011' + + >>> int2bin(15, 2) + Traceback (most recent call last): + ValueError: Value too large for given number of bits. + + """ + hex2bin = {'0': '0000', '1': '0001', '2': '0010', '3': '0011', + '4': '0100', '5': '0101', '6': '0110', '7': '0111', + '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', + 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'} + # Convert to hex then map each hex digit to binary equivalent. + result = ''.join([hex2bin[x] for x in hex(i).lower().replace('l','')[2:]]) + + # Shrink result to appropriate length. + # Raise an error if the value is changed by the truncation. + if '1' in result[:-n]: + raise ValueError("Value too large for given number of bits.") + result = result[-n:] + # Zero-pad if length longer than mapped result. + result = '0'*(n-len(result)) + result + return result + + +def bin2int(bin_string): + """Convert binary number string to decimal integer. + + Note: Python > v2 has int(bin_string, 2) + + >>> bin2int('1111') + 15 + + >>> bin2int('0101') + 5 + + """ +## result = 0 +## bin_list = list(bin_string) +## if len(filter(lambda x: x in ('1','0'), bin_list)) < len(bin_list): +## raise Exception ("bin2int: Error - not a binary number: %s" +## % bin_string) +## bit_list = map(int, bin_list) +## bit_list.reverse() # Make most significant bit have highest index. +## for bit_place in range(len(bit_list)): +## result = result + ((2**bit_place) * bit_list[bit_place]) +## return result + return int(bin_string, 2) + + +def reverse(input_string): + """Reverse a string. Useful for strings of binary numbers. + + >>> reverse('abc') + 'cba' + + """ + str_list = list(input_string) + str_list.reverse() + return ''.join(str_list) + + +def transpose(matrix): + """Transpose a list of lists. + + >>> transpose([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]) + [['a', 'd', 'g'], ['b', 'e', 'h'], ['c', 'f', 'i']] + + >>> transpose([['a', 'b', 'c'], ['d', 'e', 'f']]) + [['a', 'd'], ['b', 'e'], ['c', 'f']] + + >>> transpose([['a', 'b'], ['d', 'e'], ['g', 'h']]) + [['a', 'd', 'g'], ['b', 'e', 'h']] + + """ + result = zip(*matrix) + # Convert list of tuples to list of lists. + # map is faster than a list comprehension since it is being used with + # a built-in function as an argument. + result = map(list, result) + return result + + +def polygon_area(points_list, precision=100): + """Calculate area of an arbitrary polygon using an algorithm from the web. + + Return the area of the polygon as a positive float. + + Arguments: + points_list -- list of point tuples [(x0, y0), (x1, y1), (x2, y2), ...] + (Unclosed polygons will be closed automatically. + precision -- Internal arithmetic precision (integer arithmetic). + + >>> polygon_area([(0, 0), (0, 1), (1, 1), (1, 2), (2, 2), (2, 0), (0, 0)]) + 3.0 + + Credits: + Area of a General Polygon by David Chandler + http://www.davidchandler.com/AreaOfAGeneralPolygon.pdf + + """ + # Scale up co-ordinates and convert them to integers. + for i in range(len(points_list)): + points_list[i] = (int(points_list[i][0] * precision), + int(points_list[i][1] * precision)) + # Close polygon if not closed. + if points_list[-1] != points_list[0]: + points_list.append(points_list[0]) + # Calculate area. + area = 0 + for i in range(len(points_list)-1): + (x_i, y_i) = points_list[i] + (x_i_plus_1, y_i_plus_1) = points_list[i+1] + area = area + (x_i_plus_1 * y_i) - (y_i_plus_1 * x_i) + area = abs(area / 2) + # Unscale area. + area = float(area)/(precision**2) + return area + + +def timestamp(): + """Return string containing current time stamp. + + Note: In Python 2 onwards can use time.asctime() with no arguments. + + """ + + return time.asctime() + + +def pt2str(point): + """Return prettier string version of point tuple. + + >>> pt2str((1.8, 1.9)) + '(1.8, 1.9)' + + """ + return "(%s, %s)" % (str(point[0]), str(point[1])) + + +def gcf(a, b, epsilon=1e-16): + """Return the greatest common factor of a and b, using Euclidean algorithm. + + Arguments: + a, b -- two numbers + If both numbers are integers return an integer result, + otherwise return a float result. + epsilon -- floats less than this magnitude are considered to be zero + (default: 1e-16) + + Examples: + + >>> gcf(12, 34) + 2 + + >>> gcf(13.5, 4) + 0.5 + + >>> gcf(-2, 4) + 2 + + >>> gcf(5, 0) + 5 + + By (a convenient) definition: + >>> gcf(0, 0) + 0 + + """ + result = max(a, b) + remainder = min(a, b) + while remainder and abs(remainder) > epsilon: + new_remainder = result % remainder + result = remainder + remainder = new_remainder + return abs(result) + +def lcm(a, b, precision=None): + """Return the least common multiple of a and b, using the gcf function. + + Arguments: + a, b -- two numbers. If both are integers return an integer result, + otherwise a return a float result. + precision -- scaling factor if a and/or b are floats. + + >>> lcm(21, 6) + 42 + + >>> lcm(2.5, 3.5) + 17.5 + + >>> str(lcm(1.5e-8, 2.5e-8, precision=1e9)) + '7.5e-08' + + By (an arbitary) definition: + >>> lcm(0, 0) + 0 + + """ + # Note: Dummy precision argument is for backwards compatibility. + # Do the division first. + # (See http://en.wikipedia.org/wiki/Least_common_multiple ) + denom = gcf(a, b) + if denom == 0: + result = 0 + else: + result = a * (b / denom) + return result + + +def permutations(input_list): + """Return a list containing all permutations of the input list. + + Note: This is a recursive function. + + >>> perms = permutations(['a', 'b', 'c']) + >>> perms.sort() + >>> for perm in perms: + ... print perm + ['a', 'b', 'c'] + ['a', 'c', 'b'] + ['b', 'a', 'c'] + ['b', 'c', 'a'] + ['c', 'a', 'b'] + ['c', 'b', 'a'] + + """ + out_lists = [] + if len(input_list) > 1: + # Extract first item in list. + item = input_list[0] + # Find all permutations of remainder of list. (Recursive call.) + sub_lists = permutations(input_list[1:]) + # For every permutation of the sub list... + for sub_list in sub_lists: + # Insert the extracted first item at every position of the list. + for i in range(len(input_list)): + new_list = sub_list[:] + new_list.insert(i, item) + out_lists.append(new_list) + else: + # Termination condition: only one item in input list. + out_lists = [input_list] + return out_lists + + +def reduce_fraction(fraction): + """Reduce fraction tuple to simplest form. fraction=(num, denom) + + >>> reduce_fraction((14, 7)) + (2, 1) + + >>> reduce_fraction((-2, 4)) + (-1, 2) + + >>> reduce_fraction((0, 4)) + (0, 1) + + >>> reduce_fraction((4, 0)) + (1, 0) + + """ + (numerator, denominator) = fraction + common_factor = abs(gcf(numerator, denominator)) + result = (numerator/common_factor, denominator/common_factor) + return result + + +def quantile(l, p): + """Return p quantile of list l. E.g. p=0.25 for q1. + + See: + http://rweb.stat.umn.edu/R/library/base/html/quantile.html + + """ + l_sort = l[:] + l_sort.sort() + n = len(l) + r = 1 + ((n - 1) * p) + i = int(r) + f = r - i + if i < n: + result = (1-f)*l_sort[i-1] + f*l_sort[i] + else: + result = l_sort[i-1] + return result + + +def trim(l): + """Discard values in list more than 1.5*IQR outside IQR. + + (IQR is inter-quartile-range) + + This function uses rad_util.quantile + + 1.5*IQR -- mild outlier + 3*IQR -- extreme outlier + + See: + http://wind.cc.whecn.edu/~pwildman/statnew/section_7_-_exploratory_data_analysis.htm + + """ + l_sort = l[:] + l_sort.sort() + # Calculate medianscore (based on stats.py lmedianscore by Gary Strangman) + if len(l_sort) % 2 == 0: + # If even number of scores, average middle 2. + index = int(len(l_sort) / 2) # Integer division correct + median = float(l_sort[index] + l_sort[index-1]) / 2 + else: + # int divsion gives mid value when count from 0 + index = int(len(l_sort) / 2) + median = l_sort[index] + # Calculate IQR. + q1 = quantile(l_sort, 0.25) + q3 = quantile(l_sort, 0.75) + iqr = q3 - q1 + iqr_extra = iqr * 1.5 + def in_interval(x, i=iqr_extra, q1=q1, q3=q3): + return (x >= q1-i and x <= q3+i) + l_trimmed = [x for x in l_sort if in_interval(x)] + return l_trimmed + + +def nice_units(value, dp=0, sigfigs=None, suffix='', space=' ', + use_extra_prefixes=False, use_full_name=False, mode='si'): + """Return value converted to human readable units eg milli, micro, etc. + + Arguments: + value -- number in base units + dp -- number of decimal places to display (rounded) + sigfigs -- number of significant figures to display (rounded) + This overrides dp if set. + suffix -- optional unit suffix to append to unit multiplier + space -- seperator between value and unit multiplier (default: ' ') + use_extra_prefixes -- use hecto, deka, deci and centi as well if set. + (default: False) + use_full_name -- use full name for multiplier symbol, + e.g. milli instead of m + (default: False) + mode -- 'si' for SI prefixes, 'bin' for binary multipliers (1024, etc.) + (Default: 'si') + + SI prefixes from: + http://physics.nist.gov/cuu/Units/prefixes.html + (Greek mu changed to u.) + Binary prefixes based on: + http://physics.nist.gov/cuu/Units/binary.html + + >>> nice_units(2e-11) + '20 p' + + >>> nice_units(2e-11, space='') + '20p' + + """ + si_prefixes = {1e24: ('Y', 'yotta'), + 1e21: ('Z', 'zetta'), + 1e18: ('E', 'exa'), + 1e15: ('P', 'peta'), + 1e12: ('T', 'tera'), + 1e9: ('G', 'giga'), + 1e6: ('M', 'mega'), + 1e3: ('k', 'kilo'), + 1e-3: ('m', 'milli'), + 1e-6: ('u', 'micro'), + 1e-9: ('n', 'nano'), + 1e-12: ('p', 'pico'), + 1e-15: ('f', 'femto'), + 1e-18: ('a', 'atto'), + 1e-21: ('z', 'zepto'), + 1e-24: ('y', 'yocto') + } + if use_extra_prefixes: + si_prefixes.update({1e2: ('h', 'hecto'), + 1e1: ('da', 'deka'), + 1e-1: ('d', 'deci'), + 1e-2: ('c', 'centi') + }) + bin_prefixes = {2**10: ('K', 'kilo'), + 2**20: ('M', 'mega'), + 2**30: ('G', 'mega'), + 2**40: ('T', 'tera'), + 2**50: ('P', 'peta'), + 2**60: ('E', 'exa') + } + if mode == 'bin': + prefixes = bin_prefixes + else: + prefixes = si_prefixes + prefixes[1] = ('', '') # Unity. + # Determine appropriate multiplier. + multipliers = prefixes.keys() + multipliers.sort() + mult = None + for i in range(len(multipliers) - 1): + lower_mult = multipliers[i] + upper_mult = multipliers[i+1] + if lower_mult <= value < upper_mult: + mult_i = i + break + if mult is None: + if value < multipliers[0]: + mult_i = 0 + elif value >= multipliers[-1]: + mult_i = len(multipliers) - 1 + mult = multipliers[mult_i] + # Convert value for this multiplier. + new_value = value / mult + # Deal with special case due to rounding. + if sigfigs is None: + if mult_i < (len(multipliers) - 1) and \ + round(new_value, dp) == \ + round((multipliers[mult_i+1] / mult), dp): + mult = multipliers[mult_i + 1] + new_value = value / mult + # Concatenate multiplier symbol. + if use_full_name: + label_type = 1 + else: + label_type = 0 + # Round and truncate to appropriate precision. + if sigfigs is None: + str_value = eval('"%.'+str(dp)+'f" % new_value', locals(), {}) + else: + str_value = eval('"%.'+str(sigfigs)+'g" % new_value', locals(), {}) + return str_value + space + prefixes[mult][label_type] + suffix + + +def uniquify(seq, preserve_order=False): + """Return sequence with duplicate items in sequence seq removed. + + The code is based on usenet post by Tim Peters. + + This code is O(N) if the sequence items are hashable, O(N**2) if not. + + Peter Bengtsson has a blog post with an empirical comparison of other + approaches: + http://www.peterbe.com/plog/uniqifiers-benchmark + + If order is not important and the sequence items are hashable then + list(set(seq)) is readable and efficient. + + If order is important and the sequence items are hashable generator + expressions can be used (in py >= 2.4) (useful for large sequences): + seen = set() + do_something(x for x in seq if x not in seen or seen.add(x)) + + Arguments: + seq -- sequence + preserve_order -- if not set the order will be arbitrary + Using this option will incur a speed penalty. + (default: False) + + Example showing order preservation: + + >>> uniquify(['a', 'aa', 'b', 'b', 'ccc', 'ccc', 'd'], preserve_order=True) + ['a', 'aa', 'b', 'ccc', 'd'] + + Example using a sequence of un-hashable items: + + >>> uniquify([['z'], ['x'], ['y'], ['z']], preserve_order=True) + [['z'], ['x'], ['y']] + + The sorted output or the non-order-preserving approach should equal + that of the sorted order-preserving approach output: + + >>> unordered = uniquify([3, 3, 1, 2], preserve_order=False) + >>> unordered.sort() + >>> ordered = uniquify([3, 3, 1, 2], preserve_order=True) + >>> ordered.sort() + >>> ordered + [1, 2, 3] + >>> int(ordered == unordered) + 1 + + """ + try: + # Attempt fast algorithm. + d = {} + if preserve_order: + # This is based on Dave Kirby's method (f8) noted in the post: + # http://www.peterbe.com/plog/uniqifiers-benchmark + return [x for x in seq if (x not in d) and not d.__setitem__(x, 0)] + else: + for x in seq: + d[x] = 0 + return d.keys() + except TypeError: + # Have an unhashable object, so use slow algorithm. + result = [] + app = result.append + for x in seq: + if x not in result: + app(x) + return result + +# Alias to noun form for backward compatibility. +unique = uniquify + + +def reverse_dict(d): + """Reverse a dictionary so the items become the keys and vice-versa. + + Note: The results will be arbitrary if the items are not unique. + + >>> d = reverse_dict({'a': 1, 'b': 2}) + >>> d_items = d.items() + >>> d_items.sort() + >>> d_items + [(1, 'a'), (2, 'b')] + + """ + result = {} + for key, value in d.items(): + result[value] = key + return result + + +def lsb(x, n): + """Return the n least significant bits of x. + + >>> lsb(13, 3) + 5 + + """ + return x & ((2 ** n) - 1) + + +def gray_encode(i): + """Gray encode the given integer.""" + + return i ^ (i >> 1) + + +def random_vec(bits, max_value=None): + """Generate a random binary vector of length bits and given max value.""" + + vector = "" + for _ in range(int(bits / 10) + 1): + i = int((2**10) * random.random()) + vector += int2bin(i, 10) + + if max_value and (max_value < 2 ** bits - 1): + vector = int2bin((int(vector, 2) / (2 ** bits - 1)) * max_value, bits) + + return vector[0:bits] + + +def binary_range(bits): + """Return a list of all possible binary numbers in order with width=bits. + + It would be nice to extend it to match the + functionality of python's range() built-in function. + + """ + l = [] + v = ['0'] * bits + + toggle = [1] + [0] * bits + + while toggle[bits] != 1: + v_copy = v[:] + v_copy.reverse() + l.append(''.join(v_copy)) + + toggle = [1] + [0]*bits + i = 0 + while i < bits and toggle[i] == 1: + if toggle[i]: + if v[i] == '0': + v[i] = '1' + toggle[i+1] = 0 + else: + v[i] = '0' + toggle[i+1] = 1 + i += 1 + return l + + +def float_range(start, stop=None, step=None): + """Return a list containing an arithmetic progression of floats. + + Return a list of floats between 0.0 (or start) and stop with an + increment of step. + + This is in functionality to python's range() built-in function + but can accept float increments. + + As with range(), stop is omitted from the list. + + """ + if stop is None: + stop = float(start) + start = 0.0 + + if step is None: + step = 1.0 + + cur = float(start) + l = [] + while cur < stop: + l.append(cur) + cur += step + + return l + + +def find_common_fixes(s1, s2): + """Find common (prefix, suffix) of two strings. + + >>> find_common_fixes('abc', 'def') + ('', '') + + >>> find_common_fixes('abcelephantdef', 'abccowdef') + ('abc', 'def') + + >>> find_common_fixes('abcelephantdef', 'abccow') + ('abc', '') + + >>> find_common_fixes('elephantdef', 'abccowdef') + ('', 'def') + + """ + prefix = [] + suffix = [] + + i = 0 + common_len = min(len(s1), len(s2)) + while i < common_len: + if s1[i] != s2[i]: + break + + prefix.append(s1[i]) + i += 1 + + i = 1 + while i < (common_len + 1): + if s1[-i] != s2[-i]: + break + + suffix.append(s1[-i]) + i += 1 + + suffix.reverse() + + prefix = ''.join(prefix) + suffix = ''.join(suffix) + + return (prefix, suffix) + + +def is_rotated(seq1, seq2): + """Return true if the first sequence is a rotation of the second sequence. + + >>> seq1 = ['A', 'B', 'C', 'D'] + >>> seq2 = ['C', 'D', 'A', 'B'] + >>> int(is_rotated(seq1, seq2)) + 1 + + >>> seq2 = ['C', 'D', 'B', 'A'] + >>> int(is_rotated(seq1, seq2)) + 0 + + >>> seq1 = ['A', 'B', 'C', 'A'] + >>> seq2 = ['A', 'A', 'B', 'C'] + >>> int(is_rotated(seq1, seq2)) + 1 + + >>> seq2 = ['A', 'B', 'C', 'A'] + >>> int(is_rotated(seq1, seq2)) + 1 + + >>> seq2 = ['A', 'A', 'C', 'B'] + >>> int(is_rotated(seq1, seq2)) + 0 + + """ + # Do a sanity check. + if len(seq1) != len(seq2): + return False + # Look for occurrences of second sequence head item in first sequence. + start_indexes = [] + head_item = seq2[0] + for index1 in range(len(seq1)): + if seq1[index1] == head_item: + start_indexes.append(index1) + # Check that wrapped sequence matches. + double_seq1 = seq1 + seq1 + for index1 in start_indexes: + if double_seq1[index1:index1+len(seq1)] == seq2: + return True + return False + +def getmodule(obj): + """Return the module that contains the object definition of obj. + + Note: Use inspect.getmodule instead. + + Arguments: + obj -- python obj, generally a class or a function + + Examples: + + A function: + >>> module = getmodule(random.choice) + >>> module.__name__ + 'random' + >>> module is random + 1 + + A class: + >>> module = getmodule(random.Random) + >>> module.__name__ + 'random' + >>> module is random + 1 + + A class inheriting from a class in another module: + (note: The inheriting class must define at least one function.) + >>> class MyRandom(random.Random): + ... def play(self): + ... pass + >>> module = getmodule(MyRandom) + >>> if __name__ == '__main__': + ... name = 'rad_util' + ... else: + ... name = module.__name__ + >>> name + 'rad_util' + >>> module is sys.modules[__name__] + 1 + + Discussion: + This approach is slightly hackish, and won't work in various situations. + However, this was the approach recommended by GvR, so it's as good as + you'll get. + + See GvR's post in this thread: + http://groups.google.com.au/group/comp.lang.python/browse_thread/thread/966a7bdee07e3b34/c3cab3f41ea84236?lnk=st&q=python+determine+class+module&rnum=4&hl=en#c3cab3f41ea84236 + + """ + if hasattr(obj, 'func_globals'): + func = obj + else: + # Handle classes. + func = None + for item in obj.__dict__.values(): + if hasattr(item, 'func_globals'): + func = item + break + if func is None: + raise ValueError("No functions attached to object: %r" % obj) + module_name = func.func_globals['__name__'] + # Get module. + module = sys.modules[module_name] + return module + + +def round_grid(value, grid, mode=0): + """Round off the given value to the given grid size. + + Arguments: + value -- value to be roudne + grid -- result must be a multiple of this + mode -- 0 nearest, 1 up, -1 down + + Examples: + + >>> round_grid(7.5, 5) + 10 + + >>> round_grid(7.5, 5, mode=-1) + 5 + + >>> round_grid(7.3, 5, mode=1) + 10 + + >>> round_grid(7.3, 5.0, mode=1) + 10.0 + + """ + off_grid = value % grid + if mode == 0: + add_one = int(off_grid >= (grid / 2.0)) + elif mode == 1 and off_grid: + add_one = 1 + elif mode == -1 and off_grid: + add_one = 0 + result = ((int(value / grid) + add_one) * grid) + return result + + +def get_args(argv): + """Store command-line args in a dictionary. + + -, -- prefixes are removed + Items not prefixed with - or -- are stored as a list, indexed by 'args' + + For options that take a value use --option=value + + Consider using optparse or getopt (in Python standard library) instead. + + """ + d = {} + args = [] + + for arg in argv: + + if arg.startswith('-'): + parts = re.sub(r'^-+', '', arg).split('=') + if len(parts) == 2: + d[parts[0]] = parts[1] + else: + d[parts[0]] = None + else: + args.append(arg) + + d['args'] = args + + return d + + +if __name__ == '__main__': + import doctest + doctest.testmod(sys.modules['__main__']) + diff --git a/bindings/python/topsort.py b/bindings/python/topsort.py new file mode 100644 index 000000000..fc7d2663c --- /dev/null +++ b/bindings/python/topsort.py @@ -0,0 +1,392 @@ +# topsort - dependency (topological) sorting and cycle finding functions +# Copyright (C) 2007 RADLogic +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; +# version 2.1 of the License. +# +# This library 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 +# Lesser General Public License for more details. +# +# See http://www.fsf.org/licensing/licenses/lgpl.txt for full license text. +"""Provide toplogical sorting (i.e. dependency sorting) functions. + +The topsort function is based on code posted on Usenet by Tim Peters. + +Modifications: +- added doctests +- changed some bits to use current Python idioms + (listcomp instead of filter, +=/-=, inherit from Exception) +- added a topsort_levels version that ports items in each dependency level + into a sub-list +- added find_cycles to aid in cycle debugging + +Run this module directly to run the doctests (unittests). +Make sure they all pass before checking in any modifications. + +Requires Python >= 2.2 +(For Python 2.2 also requires separate sets.py module) + +This requires the rad_util.py module. + +""" + +# Provide support for Python 2.2* +from __future__ import generators + +__version__ = '$Revision: 0.9 $' +__date__ = '$Date: 2007/03/27 04:15:26 $' +__credits__ = '''Tim Peters -- original topsort code +Tim Wegener -- doctesting, updating to current idioms, topsort_levels, + find_cycles +''' + +# Make Python 2.3 sets look like Python 2.4 sets. +try: + set +except NameError: + from sets import Set as set + +from rad_util import is_rotated + + +class CycleError(Exception): + """Cycle Error""" + pass + + +def topsort(pairlist): + """Topologically sort a list of (parent, child) pairs. + + Return a list of the elements in dependency order (parent to child order). + + >>> print topsort( [(1,2), (3,4), (5,6), (1,3), (1,5), (1,6), (2,5)] ) + [1, 2, 3, 5, 4, 6] + + >>> print topsort( [(1,2), (1,3), (2,4), (3,4), (5,6), (4,5)] ) + [1, 2, 3, 4, 5, 6] + + >>> print topsort( [(1,2), (2,3), (3,2)] ) + Traceback (most recent call last): + CycleError: ([1], {2: 1, 3: 1}, {2: [3], 3: [2]}) + + """ + num_parents = {} # element -> # of predecessors + children = {} # element -> list of successors + for parent, child in pairlist: + # Make sure every element is a key in num_parents. + if not num_parents.has_key( parent ): + num_parents[parent] = 0 + if not num_parents.has_key( child ): + num_parents[child] = 0 + + # Since child has a parent, increment child's num_parents count. + num_parents[child] += 1 + + # ... and parent gains a child. + children.setdefault(parent, []).append(child) + + # Suck up everything without a parent. + answer = [x for x in num_parents.keys() if num_parents[x] == 0] + + # For everything in answer, knock down the parent count on its children. + # Note that answer grows *in* the loop. + for parent in answer: + del num_parents[parent] + if children.has_key( parent ): + for child in children[parent]: + num_parents[child] -= 1 + if num_parents[child] == 0: + answer.append( child ) + # Following "del" isn't needed; just makes + # CycleError details easier to grasp. + del children[parent] + + if num_parents: + # Everything in num_parents has at least one child -> + # there's a cycle. + raise CycleError(answer, num_parents, children) + return answer + +def topsort_levels(pairlist): + """Topologically sort a list of (parent, child) pairs into depth levels. + + This returns a generator. + Turn this into a an iterator using the iter built-in function. + (if you iterate over the iterator, each element gets generated when + it is asked for, rather than generating the whole list up-front.) + + Each generated element is a list of items at that dependency level. + + >>> dependency_pairs = [(1,2), (3,4), (5,6), (1,3), (1,5), (1,6), (2,5)] + >>> for level in iter(topsort_levels( dependency_pairs )): + ... print level + [1] + [2, 3] + [4, 5] + [6] + + >>> dependency_pairs = [(1,2), (1,3), (2,4), (3,4), (5,6), (4,5)] + >>> for level in iter(topsort_levels( dependency_pairs )): + ... print level + [1] + [2, 3] + [4] + [5] + [6] + + >>> dependency_pairs = [(1,2), (2,3), (3,4), (4, 3)] + >>> try: + ... for level in iter(topsort_levels( dependency_pairs )): + ... print level + ... except CycleError, exc: + ... print 'CycleError:', exc + [1] + [2] + CycleError: ({3: 1, 4: 1}, {3: [4], 4: [3]}) + + + The cycle error should look like. + CycleError: ({3: 1, 4: 1}, {3: [4], 4: [3]}) + # todo: Make the doctest more robust (i.e. handle arbitrary dict order). + + """ + num_parents = {} # element -> # of predecessors + children = {} # element -> list of successors + for parent, child in pairlist: + # Make sure every element is a key in num_parents. + if not num_parents.has_key( parent ): + num_parents[parent] = 0 + if not num_parents.has_key( child ): + num_parents[child] = 0 + + # Since child has a parent, increment child's num_parents count. + num_parents[child] += 1 + + # ... and parent gains a child. + children.setdefault(parent, []).append(child) + + return topsort_levels_core(num_parents, children) + +def topsort_levels_core(num_parents, children): + """Topologically sort a bunch of interdependent items based on dependency. + + This returns a generator. + Turn this into a an iterator using the iter built-in function. + (if you iterate over the iterator, each element gets generated when + it is asked for, rather than generating the whole list up-front.) + + Each generated element is a list of items at that dependency level. + + >>> list(topsort_levels_core( + ... {1: 0, 2: 1, 3: 1, 4: 1, 5: 2, 6: 2}, + ... {1: [2, 3, 5, 6], 2: [5], 3: [4], 4: [], 5: [6]})) + [[1], [2, 3], [4, 5], [6]] + + >>> list(topsort_levels_core( + ... {1: 0, 2: 2, 3: 1}, + ... {1: [2], 2: [3], 3: [2]})) + Traceback (most recent call last): + CycleError: ({2: 1, 3: 1}, {2: [3], 3: [2]}) + + This function has a more complicated interface than topsort_levels, + but is useful if the data is easier to generate in this form. + + Arguments: + num_parents -- key: item, value: number of parents (predecessors) + children -- key: item, value: list of children (successors) + + """ + while 1: + # Suck up everything without a predecessor. + level_parents = [x for x in num_parents.keys() if num_parents[x] == 0] + + if not level_parents: + break + + # Offer the next generated item, + # which is a list of the items at this dependency level. + yield level_parents + + # For everything item in this level, + # decrement the parent count, + # since we have accounted for its parent. + for level_parent in level_parents: + + del num_parents[level_parent] + + if children.has_key(level_parent): + for level_parent_child in children[level_parent]: + num_parents[level_parent_child] -= 1 + del children[level_parent] + + if num_parents: + # Everything in num_parents has at least one child -> + # there's a cycle. + raise CycleError(num_parents, children) + else: + # This is the end of the generator. + raise StopIteration + + +def find_cycles(parent_children): + """Yield cycles. Each result is a list of items comprising a cycle. + + Use a 'stack' based approach to find all the cycles. + This is a generator, so yields each cycle as it finds it. + + It is implicit that the last item in each cycle list is a parent of the + first item (thereby forming a cycle). + + Arguments: + parent_children -- parent -> collection of children + + Simplest cycle: + >>> cycles = list(find_cycles({'A': ['B'], 'B': ['A']})) + >>> len(cycles) + 1 + >>> cycle = cycles[0] + >>> cycle.sort() + >>> print cycle + ['A', 'B'] + + Simplest cycle with extra baggage at the start and the end: + >>> cycles = list(find_cycles(parent_children={'A': ['B'], + ... 'B': ['C'], + ... 'C': ['B', 'D'], + ... 'D': [], + ... })) + >>> len(cycles) + 1 + >>> cycle = cycles[0] + >>> cycle.sort() + >>> print cycle + ['B', 'C'] + + Double cycle: + >>> cycles = list(find_cycles(parent_children={'A': ['B'], + ... 'B': ['C1', 'C2'], + ... 'C1': ['D1'], + ... 'D1': ['E1'], + ... 'E1': ['D1'], + ... 'C2': ['D2'], + ... 'D2': ['E2'], + ... 'E2': ['D2'], + ... })) + >>> len(cycles) + 2 + >>> for cycle in cycles: + ... cycle.sort() + >>> cycles.sort() + >>> cycle1 = cycles[0] + >>> cycle1.sort() + >>> print cycle1 + ['D1', 'E1'] + >>> cycle2 = cycles[1] + >>> cycle2.sort() + >>> print cycle2 + ['D2', 'E2'] + + Simple cycle with children not specified for one item: + # todo: Should this barf instead? + >>> cycles = list(find_cycles(parent_children={'A': ['B'], + ... 'B': ['A'], + ... 'C': ['D']})) + >>> len(cycles) + 1 + >>> cycle = cycles[0] + >>> cycle.sort() + >>> print cycle + ['A', 'B'] + + Diamond cycle + >>> cycles = list(find_cycles(parent_children={'A': ['B1', 'B2'], + ... 'B1': ['C'], + ... 'B2': ['C'], + ... 'C': ['A', 'B1']})) + >>> len(cycles) + 3 + >>> sorted_cycles = [] + >>> for cycle in cycles: + ... cycle = list(cycle) + ... cycle.sort() + ... sorted_cycles.append(cycle) + >>> sorted_cycles.sort() + >>> for cycle in sorted_cycles: + ... print cycle + ['A', 'B1', 'C'] + ['A', 'B2', 'C'] + ['B1', 'C'] + + Hairy case (order can matter if something is wrong): + (Note order of B and C in the list.) + >>> cycles = list(find_cycles(parent_children={ + ... 'TD': ['DD'], + ... 'TC': ['DC'], + ... 'DC': ['DQ'], + ... 'C': ['DQ'], + ... 'DQ': ['IA', 'TO'], + ... 'IA': ['A'], + ... 'A': ['B', 'C'], + ... })) + >>> len(cycles) + 1 + >>> cycle = cycles[0] + >>> cycle.sort() + >>> print cycle + ['A', 'C', 'DQ', 'IA'] + + """ + cycles = [] + visited_nodes = set() + + for parent in parent_children: + if parent in visited_nodes: + # This node is part of a path that has already been traversed. + continue + + paths = [[parent]] + while paths: + path = paths.pop() + + parent = path[-1] + + try: + children = parent_children[parent] + except KeyError: + continue + + for child in children: + # Keeping a set of the path nodes, for O(1) lookups at the + # expense of more memory and complexity, actually makes speed + # worse. (Due to construction of sets.) + # This is O(N). + if child in path: + # This is a cycle. + cycle = path[path.index(child):] + # Check that this is not a dup cycle. + is_dup = False + for other_cycle in cycles: + if is_rotated(other_cycle, cycle): + is_dup = True + break + if not is_dup: + cycles.append(cycle) + yield cycle + else: + # Push this new path onto the 'stack'. + # This is probably the most expensive part of the algorithm + # (a list copy). + paths.append(path + [child]) + # Mark the node as visited. + visited_nodes.add(child) + + +if __name__ == '__main__': + # Run the doctest tests. + import sys + import doctest + doctest.testmod(sys.modules['__main__']) diff --git a/bindings/python/waf b/bindings/python/waf new file mode 100644 index 000000000..3dcf598bc --- /dev/null +++ b/bindings/python/waf @@ -0,0 +1 @@ +exec "`dirname "$0"`"/../../waf "$@" \ No newline at end of file diff --git a/bindings/python/wscript b/bindings/python/wscript new file mode 100644 index 000000000..4efa378e8 --- /dev/null +++ b/bindings/python/wscript @@ -0,0 +1,476 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +import re +import Params +import Configure +import Object +import Action +import os +import Task +import pproc as subprocess +from Params import fatal, warning +import shutil +import sys + +## Adjust python path to look for our local copy of pybindgen +LOCAL_PYBINDGEN_PATH = os.path.join(os.getcwd(), "bindings", "python", "pybindgen") +#PYBINDGEN_BRANCH = 'lp:pybindgen' +PYBINDGEN_BRANCH = 'https://launchpad.net/pybindgen' +if os.environ.get('PYTHONPATH', ''): + os.environ['PYTHONPATH'] = LOCAL_PYBINDGEN_PATH + os.pathsep + os.environ.get('PYTHONPATH') +else: + os.environ['PYTHONPATH'] = LOCAL_PYBINDGEN_PATH + +## https://launchpad.net/pybindgen/ +REQUIRED_PYBINDGEN_VERSION = (0, 9, 0, 600) +REQUIRED_PYGCCXML_VERSION = (0, 9, 5) + + +def set_options(opt): + opt.tool_options('python') + opt.add_option('--disable-python', + help=("Don't build Python bindings."), + action="store_true", default=False, + dest='python_disable') + opt.add_option('--python-scan', + help=("Rescan Python bindings. Needs working GCCXML / pygccxml environment."), + action="store_true", default=False, + dest='python_scan') + opt.add_option('--pybindgen-checkout', + help=("During configure, force checkout of pybingen inside ns-3, " + "instead of using the system installed version."), + action="store_true", default=False, + dest='pybindgen_checkout') + +def fetch_pybindgen(conf): + """ + Fetches pybindgen from launchpad as bindings/python/pybindgen. + Returns True if successful, False it not. + """ + bzr = conf.find_program("bzr") + if not bzr: + warning("the program 'bzr' is needed in order to fetch pybindgen") + return False + if len(REQUIRED_PYBINDGEN_VERSION) == 4: + rev = "-rrevno:%i" % REQUIRED_PYBINDGEN_VERSION[3] + else: + rev = "-rtag:%s" % '.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION]) + + if os.path.exists(LOCAL_PYBINDGEN_PATH): + print "Trying to update pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip." + + cmd = [bzr, "pull", rev, PYBINDGEN_BRANCH] + print " => ", ' '.join(cmd) + try: + if subprocess.Popen(cmd, cwd=LOCAL_PYBINDGEN_PATH).wait(): + return False + except KeyboardInterrupt: + print "Interrupted; Python bindings will be disabled." + return False + print "Update was successful." + else: + print "Trying to fetch pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip." + cmd = [bzr, "checkout", rev, PYBINDGEN_BRANCH, LOCAL_PYBINDGEN_PATH] + print " => ", ' '.join(cmd) + try: + if subprocess.Popen(cmd).wait(): + return False + except KeyboardInterrupt: + print "Interrupted; Python bindings will be disabled." + shutil.rmtree(LOCAL_PYBINDGEN_PATH, True) + return False + print "Fetch was successful." + + ## generate a fake version.py file in pybindgen it's safer this + ## way, since the normal version generation process requires + ## bazaar python bindings, which may not be available. + vfile = open(os.path.join(LOCAL_PYBINDGEN_PATH, "pybindgen", "version.py"), "wt") + vfile.write(""" +# (fake version generated by ns-3) +__version__ = %r +""" % list(REQUIRED_PYBINDGEN_VERSION)) + vfile.close() + + return True + + +def configure(conf): + conf.env['ENABLE_PYTHON_BINDINGS'] = False + if Params.g_options.python_disable: + conf.report_optional_feature("python", "Python Bindings", False, + "disabled by user request") + return + + conf.check_tool('misc') + + if sys.platform == 'cygwin': + conf.report_optional_feature("python", "Python Bindings", False, + "unsupported platform 'cygwin'") + warning("Python is not supported in CygWin environment. Try MingW instead.") + return + + ## Check for Python + try: + conf.check_tool('python') + conf.check_python_version((2,3)) + conf.check_python_headers() + except Configure.ConfigurationError, ex: + conf.report_optional_feature("python", "Python Bindings", False, str(ex)) + return + + ## Check for pybindgen + if Params.g_options.pybindgen_checkout: + fetch_pybindgen(conf) + + try: + conf.check_python_module('pybindgen') + except Configure.ConfigurationError: + warning("pybindgen missing") + if not fetch_pybindgen(conf): + conf.report_optional_feature("python", "Python Bindings", False, + "PyBindGen missing and could not be retrieved") + return + else: + out = subprocess.Popen([conf.env['PYTHON'], "-c", + "import pybindgen.version; " + "print '.'.join([str(x) for x in pybindgen.version.__version__])"], + stdout=subprocess.PIPE).communicate()[0] + pybindgen_version_str = out.strip() + pybindgen_version = tuple([int(x) for x in pybindgen_version_str.split('.')]) + conf.check_message('pybindgen', 'version', + (pybindgen_version >= REQUIRED_PYBINDGEN_VERSION), + pybindgen_version_str) + if not (pybindgen_version >= REQUIRED_PYBINDGEN_VERSION): + warning("pybindgen (found %s) is too old (need %s)" % + (pybindgen_version_str, + '.'.join([str(x) for x in REQUIRED_PYBINDGEN_VERSION]))) + if not fetch_pybindgen(conf): + conf.report_optional_feature("python", "Python Bindings", False, + "PyBindGen too old and newer version could not be retrieved") + return + + ## If all has gone well, we finally enable the Python bindings + conf.env['ENABLE_PYTHON_BINDINGS'] = True + conf.report_optional_feature("python", "Python Bindings", True, None) + + ## Check for pygccxml + try: + conf.check_python_module('pygccxml') + except Configure.ConfigurationError: + conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, + "Missing 'pygccxml' Python module") + return + + out = subprocess.Popen([conf.env['PYTHON'], "-c", + "import pygccxml; print pygccxml.__version__"], + stdout=subprocess.PIPE).communicate()[0] + pygccxml_version_str = out.strip() + pygccxml_version = tuple([int(x) for x in pygccxml_version_str.split('.')]) + conf.check_message('pygccxml', 'version', + (pygccxml_version >= REQUIRED_PYGCCXML_VERSION), + pygccxml_version_str) + if not (pygccxml_version >= REQUIRED_PYGCCXML_VERSION): + warning("pygccxml (found %s) is too old (need %s) => " + "automatic scanning of API definitions will not be possible" % + (pygccxml_version_str, + '.'.join([str(x) for x in REQUIRED_PYGCCXML_VERSION]))) + conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, + "pygccxml too old") + return + + + ## Check gccxml version + gccxml = conf.find_program('gccxml', var='GCCXML') + if not gccxml: + warning("gccxml missing; automatic scanning of API definitions will not be possible") + conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, + "gccxml missing") + return + + gccxml_version_line = os.popen(gccxml + " --version").readline().strip() + m = re.match( "^GCC-XML version (\d\.\d(\.\d)?)$", gccxml_version_line) + gccxml_version = m.group(1) + gccxml_version_ok = ([int(s) for s in gccxml_version.split('.')] >= [0, 9]) + conf.check_message('gccxml', 'version', True, gccxml_version) + if not gccxml_version_ok: + warning("gccxml too old, need version >= 0.9; automatic scanning of API definitions will not be possible") + conf.report_optional_feature("pygccxml", "Python API Scanning Support", False, + "gccxml too old") + return + + ## If we reached + conf.env['ENABLE_PYTHON_SCANNING'] = True + conf.report_optional_feature("pygccxml", "Python API Scanning Support", True, None) + + +prio_headers = { + -2: ( + "string.h", # work around http://www.gccxml.org/Bug/view.php?id=6682 + ), + -1: ( + "propagation-delay-model.h", + "propagation-loss-model.h", + "net-device.h", + ) + } + +def get_header_prio(header): + for prio, headers in prio_headers.iteritems(): + if header in headers: + return prio + return 1 + + +def calc_header_include(path): + (head, tail) = os.path.split (path) + if tail == 'ns3': + return '' + else: + return os.path.join (calc_header_include (head), tail) + + +def gen_ns3_metaheader(task): + assert len(task.m_outputs) == 1 + + header_files = [calc_header_include(node.abspath(task.m_env)) for node in task.m_inputs] + outfile = file(task.m_outputs[0].bldpath(task.m_env), "w") + + def sort_func(h1, h2): + return cmp((get_header_prio(h1), h1), (get_header_prio(h1), h2)) + + header_files.sort(sort_func) + + for header in header_files: + print >> outfile, "#include \"ns3/%s\"" % (header,) + + print >> outfile, """ +namespace ns3 { +static inline Ptr +__dummy_function_to_force_template_instantiation (Ptr obj, TypeId typeId) +{ + return obj->GetObject (typeId); +} + + +static inline void +__dummy_function_to_force_template_instantiation_v2 () +{ + Time t1, t2, t3; + t1 = t2 + t3; + t1 = t2 - t3; + TimeSquare tsq = t2*t3; + Time tsqdiv = tsq/Seconds(1); + Scalar scal = t2/t3; + TimeInvert inv = scal/t3; + t1 = scal*t1; + t1 = t1/scal; + t1 < t2; + t1 <= t2; + t1 == t2; + t1 != t2; + t1 >= t2; + t1 > t2; +} + +} +""" + outfile.close() + return 0 + + + +class all_ns3_headers_taskgen(Object.task_gen): + """Generates a 'everything.h' header file that includes some/all public ns3 headers. + This single header file is to be parsed only once by gccxml, for greater efficiency. + """ + def __init__(self, *features): + Object.task_gen.__init__(self, *features) + self.inst_var = 0#'INCLUDEDIR' + #self.inst_dir = 'ns3' + + def apply(self): + ## get all of the ns3 headers + ns3_dir_node = Params.g_build.m_srcnode.find_dir("ns3") + all_headers_inputs = [] + + for filename in self.to_list(self.source): + src_node = ns3_dir_node.find_build(filename) + if src_node is None: + Params.fatal("source ns3 header file %s not found" % (filename,)) + all_headers_inputs.append(src_node) + + ## if self.source was empty, include all ns3 headers in enabled modules + if not all_headers_inputs: + for ns3headers in Object.g_allobjs: + if type(ns3headers).__name__ == 'ns3header_taskgen': # XXX: find less hackish way to compare + ## skip headers not part of enabled modules + if self.env['NS3_ENABLED_MODULES']: + if ("ns3-%s" % ns3headers.module) not in self.env['NS3_ENABLED_MODULES']: + continue + + for source in ns3headers.to_list(ns3headers.source): + #source = os.path.basename(source) + node = ns3_dir_node.find_build(source) + if node is None: + fatal("missing header file %s" % (source,)) + all_headers_inputs.append(node) + assert all_headers_inputs + all_headers_outputs = [self.path.find_build("everything.h")] + task = self.create_task('gen-ns3-metaheader', self.env, 4) + task.set_inputs(all_headers_inputs) + task.set_outputs(all_headers_outputs) + + def install(self): + pass + + +def get_modules_and_headers(): + """ + Gets a dict of + module_name => ([module_dep1, module_dep2, ...], [module_header1, module_header2, ...]) + tuples, one for each module. + """ + + retval = {} + for module in Object.g_allobjs: + if not module.name.startswith('ns3-'): + continue + module_name = module.name[4:] # strip the ns3- prefix + ## find the headers object for this module + headers = [] + for ns3headers in Object.g_allobjs: + if type(ns3headers).__name__ != 'ns3header_taskgen': # XXX: find less hackish way to compare + continue + if ns3headers.module != module_name: + continue + for source in ns3headers.to_list(ns3headers.source): + headers.append(source) + retval[module_name] = (list(module.module_deps), headers) + return retval + + + +class PythonScanTask(Task.TaskBase): + """Uses gccxml to scan the file 'everything.h' and extract API definitions. + """ + def __init__(self, curdirnode, env): + self.m_display = 'python-scan' + self.prio = 5 # everything.h has prio 4 + super(PythonScanTask, self).__init__() + self.curdirnode = curdirnode + self.env = env + + def run(self): + #print "Rescanning the python bindings..." + argv = [ + self.env['PYTHON'], + os.path.join(self.curdirnode.abspath(), 'ns3modulescan.py'), # scanning script + self.curdirnode.find_dir('../..').abspath(self.env), # include path (where the ns3 include dir is) + self.curdirnode.find_build('everything.h').abspath(self.env), + os.path.join(self.curdirnode.abspath(), 'ns3modulegen_generated.py'), # output file + ] + scan = subprocess.Popen(argv, stdin=subprocess.PIPE) + scan.stdin.write(repr(get_modules_and_headers())) + scan.stdin.close() + if scan.wait(): + raise SystemExit(1) + raise SystemExit(0) + +def build(bld): + if Params.g_options.python_disable: + return + + env = bld.env_of_name('default') + curdir = bld.m_curdirnode.abspath() + + #Object.register('all-ns3-headers', AllNs3Headers) + Action.Action('gen-ns3-metaheader', func=gen_ns3_metaheader, color='BLUE') + + if env['ENABLE_PYTHON_BINDINGS']: + obj = bld.create_obj('all_ns3_headers') + + if Params.g_options.python_scan: + if not env['ENABLE_PYTHON_SCANNING']: + Params.fatal("Cannot re-scan python bindings: (py)gccxml not available") + PythonScanTask(bld.m_curdirnode, env) + + ## Get a list of scanned modules; the set of scanned modules + ## may be smaller than the set of all modules, in case a new + ## ns3 module is being developed which wasn't scanned yet. + scanned_modules = [] + for filename in os.listdir(curdir): + m = re.match(r"^ns3_module_(.+)\.py$", filename) + if m is None: + continue + name = m.group(1) + if name.endswith("__local"): + continue + scanned_modules.append(name) + + if env['ENABLE_PYTHON_BINDINGS']: + bindgen = bld.create_obj('command-output') + bindgen.name = 'pybindgen' + bindgen.command = env['PYTHON'] + bindgen.command_is_external = True + bindgen.stderr = 'ns3modulegen.log' + bindgen.argv = [ + #'-m', 'pdb', + bindgen.input_file("ns3modulegen.py"), + bindgen.output_file("ns3module.cc"), + ] + bindgen.argv.extend(get_modules_and_headers().iterkeys()) + bindgen.hidden_inputs = ['ns3modulegen_generated.py', + 'ns3modulegen_core_customizations.py'] + + for module in scanned_modules: + bindgen.hidden_inputs.append("ns3_module_%s.py" % module) + local = "ns3_module_%s__local.py" % module + if os.path.exists(os.path.join(curdir, local)): + bindgen.hidden_inputs.append(local) + + bindgen.hidden_outputs = ['ns3module.h'] + for module in scanned_modules: + bindgen.hidden_outputs.append("ns3_module_%s.cc" % module) + + bindgen.prio = 50 + + bindgen.os_env = dict(os.environ) + features = [] + for (name, caption, was_enabled, reason_not_enabled) in env['NS3_OPTIONAL_FEATURES']: + if was_enabled: + features.append(name) + bindgen.os_env['NS3_ENABLED_FEATURES'] = ','.join(features) + + + ## we build python bindings if either we have the tools to + ## generate them or if the pregenerated source file is already + ## present in the source dir. + if env['ENABLE_PYTHON_BINDINGS'] \ + or os.path.exists(os.path.join(bld.m_curdirnode.abspath(), 'ns3module.cc')): + pymod = bld.create_obj('cpp', 'shlib', 'pyext') + pymod.source = ['ns3module.cc', 'ns3module_helpers.cc'] + pymod.includes = '.' + for module in scanned_modules: + pymod.source.append("ns3_module_%s.cc" % module) + pymod.target = 'ns3/_ns3' + pymod.name = 'ns3module' + pymod.uselib_local = "ns3" + pymod.env.append_value('CXXDEFINES', ['NS_DEPRECATED=""', 'NS3_DEPRECATED_H']) + + # copy the __init__.py file to the build dir waf can't handle + # this, it's against waf's principles to have build dir files + # with the same name as source dir files, apparently. + dirnode = bld.m_curdirnode.find_dir('ns3') + src = os.path.join(dirnode.abspath(), '__init__.py') + dst = os.path.join(dirnode.abspath(env), '__init__.py') + try: + need_copy = os.stat(src).st_mtime > os.stat(dst).st_mtime + except OSError: + need_copy = True + if need_copy: + try: + os.mkdir(os.path.dirname(dst)) + except OSError: + pass + print "%r -> %r" % (src, dst) + shutil.copy2(src, dst) diff --git a/doc/build.txt b/doc/build.txt index 95bc068e1..090b83408 100644 --- a/doc/build.txt +++ b/doc/build.txt @@ -1,6 +1,10 @@ The Waf build system is used to build ns-3. Waf is a Python-based build system (http://www.freehackers.org/~tnagy/waf.html) +Note: We've added a wiki page with more complete build instructions +than the quick ones you find below: +http://www.nsnam.org/wiki/index.php/Installation + === Installing Waf === The top-level ns-3 directory should contain a current waf script. @@ -63,7 +67,6 @@ with --enable-gcov) It includes all files in the source directory, except some particular extensions that are blacklisted, such as back files (ending in ~). - === Extending ns-3 === To add new modules: diff --git a/doc/howtos/howtos-application.h b/doc/howtos/howtos-application.h new file mode 100644 index 000000000..33ba848c3 --- /dev/null +++ b/doc/howtos/howtos-application.h @@ -0,0 +1,203 @@ +/*! + \page application How to create a traffic generator ? + \anchor howtos-application + + Question: How do I create a new traffic generator ? + + Answer: It is possible to instanciate \ref ns3::Packet "Packet" + objects, schedule events, and call functions from any piece of code + in ns-3 so, technically, there is no single answer to the question of + how we can write a new traffic generator. However, the + \ref ns3::Socket "Socket" API was really designed to be the single + point of entry for traffic generators or traffic analysers and the + \ref ns3::Application "Application" class was designed to hold + together any number of sockets. + + Implementing a new traffic generator thus boils down to: +- implementing a new subclass of the \ref ns3::Application "Application" + base class +- instanciate one or many sockets within that application +- start scheduling events when \ref ns3::Application::StartApplication "StartApplication" + is called +- stop scheduling events when \ref ns3::Application::StopApplication "StopApplication" + is called +- create packets and send them over one or many sockets in each event + +The following "random" generator generates packets separated by a random +delay and with a random size. + +\code +class RandomGenerator : public Application +{ +public: + RandomGenerator (); + void SetDelay (RandomVariable delay); + void SetSize (RandomVariable size); + void SetRemote (std::string socketType, + Address remote); +private: + virtual void StartApplication (void); + virtual void StopApplication (void); + void DoGenerate (void); + + RandomVariable m_delay; + RandomVariable m_size; + Ptr m_socket; +}; +\endcode + +The socket is created in the SetRemote method: +\code +void +RandomGenerator::SetRemote (std::string socketType, + Address remote) +{ + TypeId tid = TypeId::LookupByName (socketType); + m_socket = Socket::CreateSocket (GetNode (), tid); + m_socket->Bind (); + m_socket->ShutdownRecv (); + m_socket->Connect (remote); +} +\endcode +While the the crux of the logic is located in the DoGenerate method +which is called from within StartApplication: +\code +void +RandomGenerator::DoGenerate (void) +{ + m_next = Simulator::Schedule (Seconds (m_delay.GetValue ()), + &RandomGenerator::DoGenerate, this); + Ptr p = Create (m_size.GetIntValue ()); + m_socket->Send (p); +} +\endcode + +To make that application more integrated in ns-3, it needs an associated +helper class: +\code +class RandomAppHelper +{ +public: + RandomAppHelper (std::string protocol, Address remote); + void SetPacketSize (RandomVariable packetSize); + void SetDelay (RandomVariable delay); + ApplicationContainer Install (NodeContainer nodes); +private: + std::string m_protocol; + Address m_remote; + RandomVariable m_packetSize; + RandomVariable m_delay; +}; +\endcode + +which could be trivially implemented as: +\code +ApplicationContainer +RandomAppHelper::Install (NodeContainer nodes) +{ + ApplicationContainer applications; + for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i) + { + Ptr app = CreateObject (); + app->SetSize (m_packetSize); + app->SetDelay (m_delay); + app->SetRemote (m_protocol, m_remote); + (*i)->AddApplication (app); + applications.Add (app); + } + return applications; +} +\endcode + +Despite being functional, this API is not very consistant with the style of +the other helper classes, all of which allow you to control the parameters +of the underlying class through attributes and not explicit setters. The +following API thus replaces the pair SetPacketSize/SetDelay with a single +method SetAttribute: +\code +class RandomAppHelper +{ +public: + RandomAppHelper (std::string protocol, Address remote); + void SetAttribute (std::string name, const AttributeValue &value); + ApplicationContainer Install (NodeContainer c); +private: + std::string m_protocol; + Address m_remote; + ObjectFactory m_factory; +}; +\endcode + +And which can be used as follows: +\code +RandomAppHelper app = RandomAppHelper ("ns3::TcpSocketFactory", + InetSocketAddress (Ipv4Address ("192.168.1.10"), 10)); +app.SetAttribute ("Delay", StringValue ("Constant:2.5")); +app.SetAttribute ("Size", StringValue ("Constant:2100")); +app.Install (nodes); +\endcode + +The implementation, in this case, is not necessarily longer but its +simplicity hides a lot of behind-the-scenes complexity: + +\code +void +RandomAppHelper::SetAttribute (std::string name, const AttributeValue &value) +{ + m_factory.Set (name, value); +} +ApplicationContainer +RandomAppHelper::Install (NodeContainer nodes) +{ + ApplicationContainer applications; + for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i) + { + Ptr app = m_factory.Create (); + app->SetRemote (m_socketType, m_remote); + (*i)->AddApplication (app); + applications.Add (app); + } + return applications; +} +\endcode + +The key difference between this implementation and the previous one +is that this helper does not handle explicitely the attributes +delay and packet size. Instead, it stores them in an +\ref ns3::ObjectFactory "ObjectFactory" object. This, of course, +does not work magically, and requires extra support from the +underlying RandomGenerator class. Specifically, it requires +that the underlying RandomGenerator defines its attributes +in its \ref ns3::TypeId "TypeId" in a new public static method: + +\code +class RandomGenerator +{ +public: + static TypeId GetTypeId (void); +}; +\endcode + +The corresponding implementation is shown below: + +\code +TypeId +RandomGenerator::GetTypeId (void) +{ + static TypeId tid = TypeId ("RandomGenerator") + .SetParent () + .AddConstructor () + .AddAttribute ("Delay", "The delay between two packets (s)", + RandomVariableValue (ConstantVariable (1.0)), + MakeRandomVariableAccessor (&RandomGenerator::m_delay), + MakeRandomVariableChecker ()) + .AddAttribute ("PacketSize", "The size of each packet (bytes)", + RandomVariableValue (ConstantVariable (2000)), + MakeRandomVariableAccessor (&RandomGenerator::m_size), + MakeRandomVariableChecker ()) + ; + return tid; +} +\endcode + +*/ diff --git a/doc/howtos/howtos-net-device.h b/doc/howtos/howtos-net-device.h new file mode 100644 index 000000000..00bb016e1 --- /dev/null +++ b/doc/howtos/howtos-net-device.h @@ -0,0 +1,162 @@ +/*! + \page net-device How to create a new OSI layer 1 + 2 implementation ? + \anchor howtos-net-device + + Question: How do I integrate a new OSI layer 1 + 2 implementation ? + + Answer: The OSI layers 1 and 2 are represented by the ns3::NetDevice + and ns3::Channel classes. To plug transparently in ns-3, a new layer 1+2 model + thus simply needs to provide two new subclasses of these two base classes. + + To make that subclassing process easy, two skeleton classes are provided in + the src/node directory: simple-net-device.h (ns3::SimpleNetDevice) and + simple-channel.h (ns3::SimpleChannel) implement a broadcast passthru medium + using 48bit MAC addresses without any kind of MAC access algorithm or PHY + layer modeling. + + The ns3::SimpleChannel class is really very simple: it provides + an implementation for the ns3::Channel::GetNDevices and ns3::Channel::GetDevice + methods defined in the Channel base class and, then defines the channel-specific + send and add methods: +- The Add method is used by SimpleNetDevice::SetChannel to register a new + SimpleNetDevice with its associated channel. +- The Send method is used by SimpleNetDevice::Send to send a packet over the + broadcast medium and ensure that it gets delivered to all associated devices + (except the sender). + +\code +class SimpleChannel : public Channel +{ +public: + static TypeId GetTypeId (void); + SimpleChannel (); + + void Send (Ptr p, uint16_t protocol, Mac48Address to, Mac48Address from, + Ptr sender); + + void Add (Ptr device); + + // inherited from ns3::Channel + virtual uint32_t GetNDevices (void) const; + virtual Ptr GetDevice (uint32_t i) const; + +private: + std::vector > m_devices; +}; +\endcode + +The SimpleNetDevice class is also trivial since it implements no special +MAC-layer processing: +\code +class SimpleNetDevice : public NetDevice +{ +public: + static TypeId GetTypeId (void); + SimpleNetDevice (); + + void Receive (Ptr packet, uint16_t protocol, Mac48Address to, Mac48Address from); + void SetChannel (Ptr channel); + void SetAddress (Mac48Address address); + + // inherited from NetDevice base class. + virtual void SetName(const std::string name); + ... +}; +\endcode + +The code below illustrates how the three model-specific methods defined above are +implemented: + +\code +void +SimpleNetDevice::Receive (Ptr packet, uint16_t protocol, + Mac48Address to, Mac48Address from) +{ + if (to == m_address || to == Mac48Address::GetBroadcast ()) + { + m_rxCallback (this, packet, protocol, from); + } +} +void +SimpleNetDevice::SetChannel (Ptr channel) +{ + m_channel = channel; + m_channel->Add (this); +} +void +SimpleNetDevice::SetAddress (Mac48Address address) +{ + m_address = address; +} +\endcode + +Building a topology with such a device is then a matter of +instanciating a set of SimpleNetDevice objects connected on a shared +SimpleChannel: +\code +NodeContainer nodes; +nodes.Create (10); +Ptr channel = CreateObject (); +for (uint32_t i = 0; i < nodes.GetN (); ++i) + { + CreateSimpleDevice (nodes.Get (i), channel); + } +\endcode + +With the following CreateSimpleDevice function: +\code +static Ptr +CreateSimpleDevice (Ptr node, Ptr channel) +{ + Ptr device = CreateObject (); + device->SetAddress (Mac48Address:Allocate ()); + device->SetChannel (channel); + node->AddDevice (device); + return device; +} +\endcode + +Of course, ultimately, you need to provide a helper class for this new device and channel +to save each user from having to re-implement their own CreateSimpleDevice helper +function: + +\code +class SimpleHelper +{ +public: + NetDeviceContainer Install (NodeContainer nodes, Ptr channel); + NetDeviceContainer Install (NodeContainer nodes); +}; +\endcode + +with the following straightforward implementation, inspired by the CreateSimpleDevice +function defined above: + +\code +NetDeviceContainer +SimpleHelper::Install (NodeContainer nodes, Ptr channel) +{ + NetDeviceContainer devices; + for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i) + { + Ptr dev = CreateObject (); + dev->SetAddress (Mac48Address::Allocate ()); + dev->SetChannel (channel); + (*i)->AddDevice (dev); + devices.Add (dev); + } + return devices; +} +NetDeviceContainer +SimpleHelper::Install (NodeContainer nodes) +{ + return Install (nodes, CreateObject ()); +} +\endcode + +Of course, at some point, this device helper class should also contain a couple of +ascii and pcap tracing helper functions but, since the default SimpleNetDevice +class we used as an example here does not report any trace event, it would +be of little use. + +*/ diff --git a/doc/howtos/howtos-packet-header.h b/doc/howtos/howtos-packet-header.h new file mode 100644 index 000000000..cf442167e --- /dev/null +++ b/doc/howtos/howtos-packet-header.h @@ -0,0 +1,119 @@ +/*! +\page packet-header-trailer How to create a new type of protocol header or trailer +\anchor howtos-packet-header-trailer + +Question: I want to implement a new protocol X which uses a new +type of header Y. How do I implement and use this new header Y in ns-3 ? + +Answer: The key is to implement a new subclass of the ns3::Header +base class to represent your protocol header: +\code +class YHeader : public Header +{ +public: + // must be implemented to become a valid new header. + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + virtual void Print (std::ostream &os) const; + + // allow protocol-specific access to the header data. + void SetData (uint32_t data); + uint32_t GetData (void) const; +private: + uint32_t m_data; +}; +\endcode + +Once this class is implemented, you can easily store your protocol +header into a packet: +\code +Ptr p = ...; +YHeader yHeader; +yHeader.SetData (0xdeadbeaf); +// copy the header into the packet +p->AddHeader (yHeader); +\endcode +and get it out of a packet: +\code +Ptr p = ...; +YHeader yHeader; +// copy the header from the packet +p->RemoveHeader (yHeader); +uint32_t data = yHeader.GetData (); +\endcode + +The implementation of the new header is very simple. First, you need +to give a TypeId to your YHeader class: +\code +TypeId +YHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("YHeader") + .SetParent
() + .AddConstructor () + ; + return tid; +} +TypeId +YHeader::GetInstanceTypeId (void) +{ + return GetTypeId (); +} +\endcode + +Then, you need to allow your header to serialize and deserialize itself +to a byte buffer in its network representation. Here, our new protocol +header contains first a 2-byte constant, and, then, the data field so, +the total size of the header is 2+4=6 bytes. +\code +uint32_t +YHeader::GetSerializedSize (void) const +{ + return 6; +} +void +YHeader::Serialize (Buffer::Iterator start) const +{ + // The 2 byte-constant + start.WriteU8 (0xfe); + start.WriteU8 (0xef); + // The data. + start.WriteHtonU32 (m_data); +} +uint32_t +YHeader::Deserialize (Buffer::Iterator start) +{ + uint8_t tmp; + tmp = start.ReadU8 (); + NS_ASSERT (tmp == 0xfe); + tmp = start.ReadU8 (); + NS_ASSERT (tmp == 0xef); + m_data = start.ReadNtohU32 (); + return 6; // the number of bytes consumed. +} +\endcode + +Finally, to make sure that Packet::Print also prints the content +of your header, just as it prints the content of the other +headers of the system, you need to provide a Print method: +\code +void +YHeader::Print (std::ostream &os) const +{ + os << "data=" << m_data; +} +\endcode + +The code will look the same if you want to implement a trailer, +that is, a protocol data structure which will be appended to the +end of the packet, not its start: you need to make sure that +you derive from the ns3::Trailer base class and that you call +Packet::AddTrailer and Packet::RemoveTrailer. Another important +detail is that you must make sure to rewind the iterator in your +Serialize and Deserialize methods writing to or reading from +the underlying buffer. + +*/ diff --git a/doc/howtos/howtos.h b/doc/howtos/howtos.h index e37546914..199b0d1b9 100644 --- a/doc/howtos/howtos.h +++ b/doc/howtos/howtos.h @@ -12,6 +12,9 @@ Please consider contributing tips to either the wiki (yourself) or by submitting a patch to this maintained documentation. - \subpage callbacks +- \subpage packet-header-trailer +- \subpage net-device +- \subpage application */ diff --git a/doc/manual/Makefile b/doc/manual/Makefile new file mode 100644 index 000000000..0711f1ebd --- /dev/null +++ b/doc/manual/Makefile @@ -0,0 +1,34 @@ +TEXI2HTML = texi2html +TEXI2PDF = texi2dvi --pdf +EPSTOPDF = epstopdf +DIA = dia +CONVERT = convert +CSS = --css-include=manual.css +SPLIT = --split section + +DIA_SOURCES = internet-node-send.dia internet-node-recv.dia packet.dia node.dia buffer.dia sockets-overview.dia +DIA_EPS = ${DIA_SOURCES:.dia=.eps} +DIA_PNG = ${DIA_SOURCES:.dia=.png} +DIA_PDF = ${DIA_SOURCES:.dia=.pdf} + +all: images html split-html pdf + +images: + cd figures/; $(DIA) -t png $(DIA_SOURCES) + cd figures/; $(DIA) -t eps $(DIA_SOURCES) + cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);) + +html: images + $(TEXI2HTML) ${CSS} manual.texi + +split-html: images + $(TEXI2HTML) ${CSS} ${SPLIT} manual.texi + +pdf: images + $(TEXI2PDF) manual.texi + +figures-clean: + cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF) + +clean: figures-clean + rm -rf manual.aux manual.cp manual.cps manual.fn manual.ky manual.pg manual.tp manual.vr manual.toc manual.log manual.pdf manual.html manual/ diff --git a/doc/manual/attributes.texi b/doc/manual/attributes.texi new file mode 100644 index 000000000..5ae1a1915 --- /dev/null +++ b/doc/manual/attributes.texi @@ -0,0 +1,723 @@ +@node Attributes +@chapter Attributes +@anchor{chap:Attributes} + +@menu +* Object Overview:: +* Attribute Overview:: +* Extending attributes:: +* Adding new class type:: +* ConfigStore:: +@end menu + + +In ns-3 simulations, there are two main aspects to configuration: +@itemize @bullet +@item the simulation topology and how objects are connected +@item the values used by the models instantiated in the topology +@end itemize + +This chapter focuses on the second item above: how the many values +in use in ns-3 are organized, documented, and modifiable by ns-3 users. +The ns-3 attribute system is also the underpinning of how traces +and statistics are gathered in the simulator. + +Before delving into details of the attribute value system, +it will help to review some basic properties of @code{class ns3::Object}. + +@node Object Overview +@section Object Overview + +ns-3 is fundamentally a C++ object-based system. By this we mean that +new C++ classes (types) can be declared, defined, and subclassed +as usual. + +Many ns-3 objects inherit from the @code{ns3::Object} base class. These +objects have some additional properties that we exploit for +organizing the system and improving the memory management +of our objects: + +@itemize @bullet +@item a "metadata" system that links the class name to a lot of +meta-information about the object, including the base class of the subclass, +the set of accessible constructors in the subclass, and the set of +"attributes" of the subclass +@item a reference counting smart pointer implementation, for memory +management. +@end itemize + +ns-3 objects that use the attribute system derive from either +@code{ns3::Object} or @code{ns3::ObjectBase}. Most ns-3 objects +we will discuss derive from @code{ns3::Object}, but a few that +are outside the smart pointer memory management framework derive +from @code{ns3::ObjectBase}. + +Let's review a couple of properties of these objects. + +@node Smart pointers +@subsection Smart pointers + +As introduced in the ns-3 tutorial, ns-3 objects are memory managed by a +@uref{http://en.wikipedia.org/wiki/Smart_pointer,,reference counting smart pointer implementation}, @code{class ns3::Ptr}. + +Smart pointers are used extensively in the ns-3 APIs, to avoid passing +references to heap-allocated objects that may cause memory leaks. +For most basic usage (syntax), treat a smart pointer like a regular pointer: +@verbatim + Ptr nd = ...; + nd->CallSomeFunction (); + // etc. +@end verbatim + +@node CreateObject +@subsection CreateObject + +As we discussed above in @ref{Object Creation}, +at the lowest-level API, objects of type @code{ns3::Object} are +not instantiated using @code{operator new} as usual but instead by +a templated function called @code{CreateObject()}. + +A typical way to create such an object is as follows: +@verbatim + Ptr nd = CreateObject (); +@end verbatim + +You can think of this as being functionally equivalent to: +@verbatim + WifiNetDevice* nd = new WifiNetDevice (); +@end verbatim + +Objects that derive from @code{ns3::Object} must be allocated +on the heap using CreateObject(). Those deriving from +@code{ns3::ObjectBase}, such as ns-3 helper functions and packet +headers and trailers, can be allocated on the stack. + +In some scripts, you may not see a lot of CreateObject() calls +in the code; +this is because there are some helper objects in effect that +are doing the CreateObject()s for you. + +@node TypeId +@subsection TypeId + +ns-3 classes that derive from class ns3::Object can include +a metadata class called @code{TypeId} that records meta-information +about the class, for use in the object aggregation and component +manager systems: +@itemize @bullet + @item a unique string identifying the class + @item the base class of the subclass, within the metadata system + @item the set of accessible constructors in the subclass +@end itemize + +@node Object Summary +@subsection Object Summary + +Putting all of these concepts together, let's look at a specific +example: @code{class ns3::Node}. + +The public header file node.h has a declaration that includes +a static GetTypeId function call: +@verbatim +class Node : public Object +{ +public: + static TypeId GetTypeId (void); + ... +@end verbatim + +This is defined in the node.cc file as follows: +@verbatim +TypeId +Node::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Node") + .SetParent () + ; + return tid; +} +@end verbatim +Finally, when users want to create Nodes, they call: +@verbatim + Ptr n = CreateObject (); +@end verbatim + +We next discuss how attributes (values associated with member variables +or functions of the class) are plumbed into the above TypeId. + +@node Attribute Overview +@section Attribute Overview + +The goal of the attribute system is to organize the access of +internal member objects of a simulation. This goal arises because, +typically in simulation, users will cut and paste/modify existing +simulation scripts, or will use higher-level simulation constructs, +but often will be interested in studying or tracing particular +internal variables. For instance, use cases such as: +@itemize @bullet +@item "I want to trace the packets on the wireless interface only on +the first access point" +@item "I want to trace the value of the TCP congestion window (every +time it changes) on a particular TCP socket" +@item "I want a dump of all values that were used in my simulation." +@end itemize + +Similarly, users may want fine-grained access to internal +variables in the simulation, or may want to broadly change the +initial value used for a particular parameter in all subsequently +created objects. Finally, users may wish to know what variables +are settable and retrievable in a simulation configuration. This +is not just for direct simulation interaction on the command line; +consider also a (future) graphical user interface +that would like to be able to provide a feature whereby a user +might right-click on an node on the canvas and see a hierarchical, +organized list of parameters that are settable on the node and its +constituent member objects, and help text and default values for +each parameter. + +@node Functional overview +@subsection Functional overview + +We provide a way for users to access values deep in the system, without +having to plumb accessors (pointers) through the system and walk +pointer chains to get to them. Consider a class DropTailQueue that +has a member variable that is an unsigned integer @code{m_maxPackets}; +this member variable controls the depth of the queue. + +If we look at the declaration of DropTailQueue, we see the following: +@verbatim +class DropTailQueue : public Queue { +public: + static TypeId GetTypeId (void); + ... + +private: + std::queue > m_packets; + uint32_t m_maxPackets; +}; +@end verbatim + +Let's consider things that a user may want to do with the value of +m_maxPackets: + +@itemize @bullet +@item Set a default value for the system, such that whenever a new +DropTailQueue is created, this member is initialized to that default. +@item Set or get the value on an already instantiated queue. +@end itemize + +The above things typically require providing Set() and Get() functions, +and some type of global default value. + +In the ns-3 attribute system, these value definitions and accessor +functions are moved into the TypeId class; e.g.: +@verbatim +TypeId DropTailQueue::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::DropTailQueue") + .SetParent () + .AddConstructor () + .AddAttribute ("MaxPackets", + "The maximum number of packets accepted by this DropTailQueue.", + UintegerValue (100), + MakeUintegerAccessor (&DropTailQueue::m_maxPackets), + MakeUintegerChecker ()) + ; + + return tid; +} +@end verbatim + +The AddAttribute() method is performing a number of things with this +value: +@itemize @bullet +@item Binding the variable m_maxPackets to a string "MaxPackets" +@item Providing a default value (100 packets) +@item Providing some help text defining the value +@item Providing a "checker" (not used in this example) that can be used to set +bounds on the allowable range of values +@end itemize + +The key point is that now the value of this variable and its default +value are accessible in the attribute namespace, which is based on +strings such as "MaxPackets" and TypeId strings. In the next +section, we will provide an example script that shows how users +may manipulate these values. + +@node Basic usage +@subsection Basic usage + +Let's look at how a user script might access these values. +This is based on the script found at @code{samples/main-attribute-value.cc}, +with some details stripped out. +@verbatim +// +// This is a basic example of how to use the attribute system to +// set and get a value in the underlying system; namely, an unsigned +// integer of the maximum number of packets in a queue +// + +int +main (int argc, char *argv[]) +{ + + // By default, the MaxPackets attribute has a value of 100 packets + // (this default can be observed in the function DropTailQueue::GetTypeId) + // + // Here, we set it to 80 packets. We could use one of two value types: + // a string-based value or a Uinteger value + Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("80")); + // The below function call is redundant + Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (80)); + + // Allow the user to override any of the defaults and the above + // SetDefaults() at run-time, via command-line arguments + CommandLine cmd; + cmd.Parse (argc, argv); +@end verbatim + +The main thing to notice in the above are the two calls to +@code{Config::SetDefault}. This is how we set the default value +for all subsequently instantiated DropTailQueues. We illustrate +that two types of Value classes, a StringValue and a UintegerValue class, +can be used to assign the value to the attribute named by +"ns3::DropTailQueue::MaxPackets". + +Now, we will create a few objects using the low-level API; here, +our newly created queues will not have a m_maxPackets initialized to +100 packets but to 80 packets, because of what we did above with +default values. +@verbatim + Ptr n0 = CreateObject (); + + Ptr net0 = CreateObject (); + n0->AddDevice (net0); + + Ptr q = CreateObject (); + net0->AddQueue(q); +@end verbatim + +At this point, we have created a single node (Node 0) and a +single PointToPointNetDevice (NetDevice 0) and added a +DropTailQueue to it. + +Now, we can manipulate the MaxPackets value of the already +instantiated DropTailQueue. Here are various ways to do that. + +@subsubsection Pointer-based access + +We assume that a smart pointer (Ptr) to a relevant network device is +in hand; here, it is the net0 pointer. + +One way to change the value is to access a pointer to the +underlying queue and modify its attribute. + +First, we observe that we can get a pointer to the (base class) +queue via the PointToPointNetDevice attributes, where it is called +TxQueue +@verbatim + PointerValue tmp; + net0->GetAttribute ("TxQueue", tmp); + Ptr txQueue = tmp.GetObject (); +@end verbatim + +Using the GetObject function, we can perform a safe downcast +to a DropTailQueue, where MaxPackets is a member +@verbatim + Ptr dtq = txQueue->GetObject (); + NS_ASSERT (dtq != 0); +@end verbatim + +Next, we can get the value of an attribute on this queue. +We have introduced wrapper "Value" classes for the underlying +data types, similar to Java wrappers around these types, since +the attribute system stores values and not disparate types. +Here, the attribute value is assigned to a UintegerValue, and +the Get() method on this value produces the (unwrapped) uint32_t. +@verbatim + UintegerValue limit; + dtq->GetAttribute ("MaxPackets", limit); + NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets"); +@end verbatim + +Note that the above downcast is not really needed; we could have +done the same using the Ptr even though the attribute +is a member of the subclass +@verbatim + txQueue->GetAttribute ("MaxPackets", limit); + NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets"); +@end verbatim + +Now, let's set it to another value (60 packets) +@verbatim + txQueue->SetAttribute("MaxPackets", UintegerValue (60)); + txQueue->GetAttribute ("MaxPackets", limit); + NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets"); +@end verbatim + +@subsubsection Namespace-based access + +An alternative way to get at the attribute is to use the configuration +namespace. Here, this attribute resides on a known path in this +namespace; this approach is useful if one doesn't have access to +the underlying pointers and would like to configure a specific +attribute with a single statement. +@verbatim + Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25)); + txQueue->GetAttribute ("MaxPackets", limit); + NS_LOG_INFO ("4. txQueue limit changed through namespace: " << + limit.Get () << " packets"); +@end verbatim + +We could have also used wildcards to set this value for all nodes +and all net devices (which in this simple example has the same +effect as the previous Set()) +@verbatim + Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15)); + txQueue->GetAttribute ("MaxPackets", limit); + NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " << + limit.Get () << " packets"); +@end verbatim + +@node Setting through constructors and helper classes +@subsection Setting through constructors helper classes + +Arbitrary combinations of attributes can be set and fetched from +the helper and low-level APIs; either from the constructors themselves: +@verbatim +Ptr p = CreateObject ("n1", v1, "n2", v2, ...); +@end verbatim +or from the higher-level helper APIs, such as: +@verbatim + mobility.SetPositionAllocator ("GridPositionAllocator", + "MinX", DoubleValue (-100.0), + "MinY", DoubleValue (-100.0), + "DeltaX", DoubleValue (5.0), + "DeltaY", DoubleValue (20.0), + "GridWidth", UintegerValue (20), + "LayoutType", StringValue ("RowFirst")); +@end verbatim + +@node Value classes +@subsection Value classes +Readers will note the new FooValue classes which are subclasses of the +AttributeValue base class. These can be thought of as +an intermediate class that can be used to convert from raw types to the +Values that are used by the attribute system. Recall that this database is holding +objects of many types with a single generic type. Conversions to this +type can either be done using an intermediate class (IntegerValue, DoubleValue for +"floating point") or via strings. Direct implicit conversion of types +to Value is not really practical. So in the above, users have a choice +of using strings or values: +@verbatim +p->Set ("cwnd", StringValue ("100")); // string-based setter +p->Set ("cwnd", IntegerValue (100)); // integer-based setter +@end verbatim + +The system provides some macros that help users declare and define +new AttributeValue subclasses for new types that they want to introduce into +the attribute system: +@itemize @bullet +@item ATTRIBUTE_HELPER_HEADER +@item ATTRIBUTE_HELPER_CPP +@end itemize + +@node Extending attributes +@section Extending attributes + +The ns-3 system will place a number of internal values under the +attribute system, but undoubtedly users will want to extend this +to pick up ones we have missed, or to add their own classes to this. + +@subsection Adding an existing internal variable to the metadata system + +Consider this variable in class TcpSocket: +@verbatim + uint32_t m_cWnd; // Congestion window +@end verbatim + +Suppose that someone working with Tcp wanted to get or set the +value of that variable using the metadata system. If it were not +already provided by ns-3, the user could declare the following addition +in the metadata system (to the TypeId declaration for TcpSocket): +@verbatim + .AddParameter ("Congestion window", + "Tcp congestion window (bytes)", + Uinteger (1), + MakeUintegerAccessor (&TcpSocket::m_cWnd), + MakeUintegerChecker ()); + +@end verbatim + +Now, the user with a pointer to the TcpSocket can perform operations +such as setting and getting the value, without having to add these +functions explicitly. Furthermore, access controls can be applied, such +as allowing the parameter to be read and not written, or bounds +checking on the permissible values can be applied. + +@subsection Adding a new TypeId + +Here, we discuss the impact on a user who wants to add a new class to +ns-3; what additional things must be done to hook it into this system. + +We've already introduced what a TypeId definition looks like: +@verbatim +TypeId +RandomWalk2dMobilityModel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::RandomWalk2dMobilityModel") + .SetParent () + .SetGroupName ("Mobility") + .AddConstructor () + .AddAttribute ("Bounds", + "Bounds of the area to cruise.", + RectangleValue (Rectangle (0.0, 0.0, 100.0, 100.0)), + MakeRectangleAccessor (&RandomWalk2dMobilityModel::m_bounds), + MakeRectangleChecker ()) + .AddAttribute ("Time", + "Change current direction and speed after moving for this delay.", + TimeValue (Seconds (1.0)), + MakeTimeAccessor (&RandomWalk2dMobilityModel::m_modeTime), + MakeTimeChecker ()) + // etc (more parameters). + ; + return tid; +} +@end verbatim + +The declaration for this in the class declaration is one-line public +member method: +@verbatim + public: + static TypeId GetTypeId (void); +@end verbatim + +Typical mistakes here involve: +@itemize @bullet +@item Not calling the SetParent method or calling it with the wrong type +@item Not calling the AddConstructor method of calling it with the wrong type +@item Introducing a typographical error in the name of the TypeId in its constructor +@item Not using the fully-qualified c++ typename of the enclosing c++ class as the +name of the TypeId +@end itemize +None of these mistakes can be detected by the ns-3 codebase so, users +are advised to check carefully multiple times that they got these right. + + +@node Adding new class type +@section Adding new class type to the attribute system + +From the perspective of the user who writes a new class in the system and +wants to hook it in to the attribute system, there is mainly the matter +of writing +the conversions to/from strings and attribute values. Most of this can be +copy/pasted with macro-ized code. For instance, consider class +Rectangle in the @code{src/mobility/} directory: + +One line is added to the class declaration: +@verbatim +/** + * \brief a 2d rectangle + */ +class Rectangle +{ +... + +}; +@end verbatim + +One macro call and two operators, are added below the class declaration: + +@verbatim +std::ostream &operator << (std::ostream &os, const Rectangle &rectangle); +std::istream &operator >> (std::istream &is, Rectangle &rectangle); + +ATTRIBUTE_HELPER_HEADER (Rectangle); +@end verbatim + +In the class definition, the code looks like this: + +@verbatim +ATTRIBUTE_HELPER_CPP (Rectangle); + +std::ostream & +operator << (std::ostream &os, const Rectangle &rectangle) +{ + os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax; + return os; +} +std::istream & +operator >> (std::istream &is, Rectangle &rectangle) + { + char c1, c2, c3; + is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax; + if (c1 != '|' || + c2 != '|' || + c3 != '|') + { + is.setstate (std::ios_base::failbit); + } + return is; +} +@end verbatim + +These stream operators simply convert from a string representation of the +Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the +modeler must specify these operators and the string syntactical representation +of an instance of the new class. + +@node ConfigStore +@section ConfigStore + +@strong{Feedback requested:} This is an experimental feature of ns-3. +It is not in the main tree. If you like this feature and would like +to provide feedback on it, please email us. + +Values for ns-3 attributes can be stored in an ascii text file and +loaded into a future simulation. This feature is known as the +ns-3 ConfigStore. +The ConfigStore code is in @code{src/contrib/}. It is not yet main-tree +code, because we are seeking some user feedback. + +We can explore this system by using an example. Copy the @code{csma-bridge.cc} +file to the scratch directory: +@verbatim + cp examples/csma-bridge.cc scratch/ + ./waf +@end verbatim + +Let's edit it to add the ConfigStore feature. First, add an include statement, +and then add these lines: + +@verbatim +#include "contrib-module.h" +... +int main (...) +{ + // setup topology + + // Invoke just before entering Simulator::Run () + ConfigStore config; + config.Configure (); + + Simulator::Run (); +} +@end verbatim + +There is an attribute that governs whether the Configure() call either +stores a simulation configuration in a file and exits, or whether +it loads a simulation configuration file annd proceeds. First, +the @code{LoadFilename} attribute is checked, and if non-empty, +the program loads the configuration from the filename provided. +If LoadFilename is empty, and if the @code{StoreFilename} attribute is +populated, the configuration will be written to the output filename +specified. + +While it is possible to generate a sample config file and lightly +edit it to change a couple of values, there are cases where this +process will not work because the same value on the same object +can appear multiple times in the same automatically-generated +configuration file under different configuration paths. + +As such, the best way to use this class is to use it to generate +an initial configuration file, extract from that configuration +file only the strictly necessary elements, and move these minimal +elements to a new configuration file which can then safely +be edited and loaded in a subsequent simulation run. + +So, let's do that as an example. We'lll run the program once +to create a configure file, and look at it. +If you are running bash shell, the below command should work (which illustrates +how to set an attribute from the command line): +@verbatim +./build/debug/scratch/csma-bridge --ns3::ConfigStore::StoreFilename=test.config +@end verbatim +or, if the above does not work (the above requires rpath support), try this: +@verbatim +./waf --command-template="%s --ns3::ConfigStore::StoreFilename=test.config" --run scratch/csma-bridge +@end verbatim + +Running the program should yield a "test.config" output configuration file +that looks like this: +@verbatim +/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Addre +ss 00:00:00:00:00:01 +/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Frame +Size 1518 +/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/SendE +nable true +/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Recei +veEnable true +/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/TxQue +ue/$ns3::DropTailQueue/MaxPackets 100 +/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Mtu 1 +500 +... +@end verbatim + +The above lists, for each object in the script topology, the value of each +registered attribute. The syntax of this file is that the unique name +of the attribute (in the attribute namespace) is specified on each line, +followed by a value. + +This file is intended to be a convenient record of the parameters that were +used in a given simulation run, and can be stored with simulation +output files. Additionally, +this file can also be used to parameterize a simulation, instead of +editing the script or passing in command line arguments. For instance, +a person wanting to run the simulation can examine and tweak the values +in a pre-existing configuration file, and pass the file to the +program. In this case, the relevant commands are: +@verbatim +./build/debug/scratch/csma-bridge --ns3::ConfigStore::LoadFilename=test.config +@end verbatim +or, if the above does not work (the above requires rpath support), try this: +@verbatim +./waf --command-template="%s --ns3::ConfigStore::LoadFilename=test.config" --run scratch/csma-bridge +@end verbatim + +@subsection GTK-based ConfigStore + +There is a GTK-based front end for the ConfigStore. This allows users +to use a GUI to access and change variables. Screenshots of this +feature are available in the +@uref{http://www.nsnam.org/docs/ns-3-overview.pdf,,ns-3 Overview} presentation. + +To use this feature, one must install libgtk and libgtk-dev; an example +Ubuntu installation command is: +@verbatim +sudo apt-get install libgtk2.0-0 libgtk2.0-dev +@end verbatim +To check whether it is configured or not, check the output of the +./waf configure step: +@verbatim +---- Summary of optional NS-3 features: +Threading Primitives : enabled +Real Time Simulator : enabled +GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found) +@end verbatim + +In the above example, it was not enabled, so it cannot be used until a +suitable version is installed and ./waf configure; ./waf is rerun. + +Usage is almost the same as the non-GTK-based version: +@verbatim + // Invoke just before entering Simulator::Run () + GtkConfigStore config; + config.Configure (); +@end verbatim + +Now, when you run the script, a GUI should pop up, allowing you to open +menus of attributes on different nodes/objects, and then launch the +simulation execution when you are done. + +@subsection Future work +There are a couple of possible improvements: +@itemize bullet +@item save a unique version number with date and time at start of file +@item save rng initial seed somewhere. +@item make each RandomVariable serialize its own initial seed and re-read +it later +@item add the default values +@end itemize + diff --git a/doc/tutorial/callbacks.texi b/doc/manual/callbacks.texi similarity index 99% rename from doc/tutorial/callbacks.texi rename to doc/manual/callbacks.texi index 377689975..38a4f07a6 100644 --- a/doc/tutorial/callbacks.texi +++ b/doc/manual/callbacks.texi @@ -1,5 +1,5 @@ -@node ns-3 Callbacks -@chapter ns-3 Callbacks +@node Callbacks +@chapter Callbacks Some new users to @command{ns-3} are unfamiliar with an extensively used programming idiom used throughout the code: the ``ns-3 callback''. This diff --git a/doc/manual/figures/README b/doc/manual/figures/README new file mode 100644 index 000000000..0b9965deb --- /dev/null +++ b/doc/manual/figures/README @@ -0,0 +1,18 @@ +Please write image files in a vector graphics format, when possible, and +generate the .png and .pdf versions on the fly (see ../Makefile). + +The currently supported tool is dia. xfig could be added similarly +if someone wants to add it. The main requirement for adding another format +is that the tool to edit it is freely available and that a cron script can +autogenerate the pdf and png from the figure source. Tgif (.obj) files +were once used but the file conversions require a valid X display to +be running, and are therefore to be avoided since our code server +does not run such a server. Tgif pdf conversions were also cumbersome. + +Store the .dia versions in mercurial, but not the .png or .pdfs. +If the figure is not available in a vector graphics format, store both +a .png and a .pdf version in this directory. + +If you add a source (.dia) file here, remember to add it to +the list of figure sources in the Makefile in the directory above + diff --git a/doc/tutorial/figures/buffer.dia b/doc/manual/figures/buffer.dia similarity index 100% rename from doc/tutorial/figures/buffer.dia rename to doc/manual/figures/buffer.dia diff --git a/doc/manual/figures/internet-node-recv.dia b/doc/manual/figures/internet-node-recv.dia new file mode 100644 index 000000000..934347617 Binary files /dev/null and b/doc/manual/figures/internet-node-recv.dia differ diff --git a/doc/manual/figures/internet-node-send.dia b/doc/manual/figures/internet-node-send.dia new file mode 100644 index 000000000..602a4bf31 Binary files /dev/null and b/doc/manual/figures/internet-node-send.dia differ diff --git a/doc/manual/figures/node.dia b/doc/manual/figures/node.dia new file mode 100644 index 000000000..34d7c40a1 Binary files /dev/null and b/doc/manual/figures/node.dia differ diff --git a/doc/manual/figures/packet.dia b/doc/manual/figures/packet.dia new file mode 100644 index 000000000..a6f252e51 Binary files /dev/null and b/doc/manual/figures/packet.dia differ diff --git a/doc/tutorial/figures/sockets-overview.dia b/doc/manual/figures/sockets-overview.dia similarity index 100% rename from doc/tutorial/figures/sockets-overview.dia rename to doc/manual/figures/sockets-overview.dia diff --git a/doc/tutorial/log.texi b/doc/manual/log.texi similarity index 100% rename from doc/tutorial/log.texi rename to doc/manual/log.texi diff --git a/doc/manual/manual.css b/doc/manual/manual.css new file mode 100644 index 000000000..a7586ac83 --- /dev/null +++ b/doc/manual/manual.css @@ -0,0 +1,156 @@ +body { + font-family: "Trebuchet MS", "Bitstream Vera Sans", verdana, lucida, arial, helvetica, sans-serif; + background: white; + color: black; + font-size: 11pt; +} + +h1, h2, h3, h4, h5, h6 { +# color: #990000; + color: #009999; +} + +pre { + font-size: 10pt; + background: #e0e0e0; + color: black; +} + +a:link, a:visited { + font-weight: normal; + text-decoration: none; + color: #0047b9; +} + +a:hover { + font-weight: normal; + text-decoration: underline; + color: #0047b9; +} + +img { + border: 0px; +} + +#main th { + font-size: 12pt; + background: #b0b0b0; +} + +.odd { + font-size: 12pt; + background: white; +} + +.even { + font-size: 12pt; + background: #e0e0e0; +} + +.answer { + font-size: large; + font-weight: bold; +} + +.answer p { + font-size: 12pt; + font-weight: normal; +} + +.answer ul { + font-size: 12pt; + font-weight: normal; +} + +#container { + position: absolute; + width: 100%; + height: 100%; + top: 0px; +} + +#feedback { + color: #b0b0b0; + font-size: 9pt; + font-style: italic; +} + +#header { + position: absolute; + margin: 0px; + top: 10px; + height:96px; + left: 175px; + right: 10em; + bottom: auto; + background: white; + clear: both; +} + +#middle { + position: absolute; + left: 0; + height: auto; + width: 100%; +} + +#main { + position: absolute; + top: 50px; + left: 175px; + right: 100px; + background: white; + padding: 0em 0em 0em 0em; +} + +#navbar { + position: absolute; + top: 75px; + left: 0em; + width: 146px; + padding: 0px; + margin: 0px; + font-size: 10pt; +} + +#navbar a:link, #navbar a:visited { + font-weight: normal; + text-decoration: none; + color: #0047b9; +} + +#navbar a:hover { + font-weight: normal; + text-decoration: underline; + color: #0047b9; +} + +#navbar dl { + width: 146px; + padding: 0; + margin: 0 0 10px 0px; + background: #99ffff url(images/box_bottom2.gif) no-repeat bottom left; +} + +#navbar dt { + padding: 6px 10px; + font-size: 100%; + font-weight: bold; + background: #009999; + margin: 0px; + border-bottom: 1px solid #fff; + color: white; + background: #009999 url(images/box_top2.gif) no-repeat top left; +} + +#navbar dd { + font-size: 100%; + margin: 0 0 0 0px; + padding: 6px 10px; + color: #0047b9; +} + +dd#selected { + background: #99ffff url(images/arrow.gif) no-repeat; + background-position: 4px 10px; +} diff --git a/doc/manual/manual.texi b/doc/manual/manual.texi new file mode 100644 index 000000000..6bb998093 --- /dev/null +++ b/doc/manual/manual.texi @@ -0,0 +1,108 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename ns-3.info +@settitle ns-3 manual +@c @setchapternewpage odd +@c %**end of header + +@ifinfo +Primary documentation for the @command{ns-3} project is available in +four forms: +@itemize @bullet +@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator +@item @uref{http://www.nsnam.org/tutorial/index.html,,ns-3 Tutorial} +@item Reference Manual (this document) +@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} +@end itemize + +This document is written in GNU Texinfo and is to be maintained in +revision control on the @command{ns-3} code server. Both PDF and HTML versions +should be available on the server. Changes to +the document should be discussed on the ns-developers@@isi.edu mailing list. +@end ifinfo + +@copying + +This is an @command{ns-3} reference manual. +Primary documentation for the @command{ns-3} project is available in +four forms: +@itemize @bullet +@item @uref{http://www.nsnam.org/tutorial/index.html,,ns-3 Tutorial} +@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen}: Documentation of the public APIs of the simulator +@item Reference Manual (this document) +@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} +@end itemize + +This document is written in GNU Texinfo and is to be maintained in +revision control on the @command{ns-3} code server. Both PDF and HTML +versions should be available on the server. Changes to +the document should be discussed on the ns-developers@@isi.edu mailing list. + +This software is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This software 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, see @uref{http://www.gnu.org/licenses/}. +@end copying + +@titlepage +@title ns-3 Reference Manual +@author ns-3 project +@author feedback: ns-developers@@isi.edu +@today{} + +@c @page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + +@c So the toc is printed at the start. +@anchor{Full Table of Contents} +@contents + +@ifnottex +@node Top, Overview, Full Table of Contents +@top ns-3 Manual (html version) + +For a pdf version of this manual, +see @uref{http://www.nsnam.org/docs/manual.pdf}. + +@insertcopying +@end ifnottex + +@menu +* Random variables:: +* Callbacks:: +* Attributes:: +* RealTime:: +* Packets:: +* Sockets APIs:: +* Node and Internet Stack:: +* TCP:: +* Routing overview:: +* Troubleshooting +@end menu + +@include random.texi +@include callbacks.texi +@include attributes.texi +@include realtime.texi +@include packets.texi +@include sockets.texi +@include node.texi +@c @include output.texi +@include tcp.texi +@include routing.texi +@c @include other.texi +@include troubleshoot.texi + +@printindex cp + +@bye diff --git a/doc/manual/node.texi b/doc/manual/node.texi new file mode 100644 index 000000000..31d8b8561 --- /dev/null +++ b/doc/manual/node.texi @@ -0,0 +1,358 @@ +@node Node and Internet Stack +@chapter Node and Internet Stack +@anchor{chap:Node} + +This chapter describes how ns-3 nodes are put together, and provides +a walk-through of how packets traverse an internet-based Node. + +@float Figure,fig:node +@caption{High-level node architecture.} +@image{figures/node,5in} +@end float + +In ns-3, nodes are instances of @code{class Node}. This class +may be subclassed, but instead, the conceptual model is that +we @emph{aggregate} or insert objects to it rather than define +subclasses. + +One might think of a bare ns-3 node as a shell of a computer, +to which one may add NetDevices (cards) and other innards including +the protocols and applications. @ref{fig:node} illustrates +that Node objects contain a list of Applications (initially, +the list is empty), a list of NetDevices (initially, the list +is empty), a unique integer ID, and a system ID (for +distributed simulation). + +The design tries to avoid putting too many dependencies on the +base class Node, Application, or NetDevice for the following: +@itemize @bullet +@item IP version, or whether IP is at all even used in the Node. +@item implementation details of the IP stack +@end itemize + +From a software perspective, the lower interface of applications +corresponds to the C-based sockets API. The upper interface +of NetDevice objects corresponds to the device independent +sublayer of the Linux stack. Everything in between can be +aggregated and plumbed together as needed. + +Let's look more closely at the protocol demultiplexer. We want +incoming frames at layer-2 to be delivered to the right layer-3 +protocol such as Ipv4. The +function of this demultiplexer is to register callbacks for +receiving packets. The callbacks are indexed based on the +@uref{http://en.wikipedia.org/wiki/EtherType,,EtherType} +in the layer-2 frame. + +Many different types of higher-layer protocols may be +connected to the NetDevice, such as IPv4, IPv6, ARP, +MPLS, IEEE 802.1x, and packet sockets. Therefore, the +use of a callback-based demultiplexer avoids the need to +use a common base class for all of these protocols, which +is problematic because of the different types of objects +(including packet sockets) expected to be registered there. + +Each NetDevice delivers packets to a callback with the following +signature: +@verbatim + /** + * \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, Ptr, uint16_t, + const Address &> ReceiveCallback; +@end verbatim + +There is a function in class Node that matches that signature: +@verbatim +private: + bool ReceiveFromDevice (Ptr device, Ptr, + uint16_t protocol, const Address &from); +@end verbatim + +However, users do not need to access this function directly. Instead, +when users call @code{uint32_t AddDevice (Ptr device)}, +the implementation of this function sets the callback (and the +function returns the ifIndex of the NetDevice on that Node). + +But what does the ReceiveFromDevice function do? Here, it looks +up another callback, in its list of callbacks, corresponding to the +matching EtherType. This callback is called a ProtocolHandler, and +is specified as follows: +@verbatim + typedef Callback, Ptr, uint16_t, + const Address &> ProtocolHandler; +@end verbatim + +Upper-layer protocols or objects are expected to provide such a function. +and register it with the list of ProtocolHandlers by calling +@code{Node::RegisterProtocolHandler ();} +For instance, if Ipv4 is aggregated to a Node, then the Ipv4 receive +function can be registered with the protocol handler by calling: +@verbatim + RegisterProtocolHandler ( + MakeCallback (&Ipv4L3Protocol::Receive, ipv4), + Ipv4L3Protocol::PROT_NUMBER, 0); +@end verbatim +and likewise for Ipv6, Arp, etc. + +@section NodeList + +Every Node created is automatically added to the ns-3 @code{NodeList}. +The NodeList class provides an @code{Add()} method and C++ iterators +to allow one to walk the node list or fetch a Node pointer by +its integer identifier. + +@section Internet stack aggregation + +The above @code{class Node} is not very useful as-is; other objects +must be aggregated to it to provide useful node functionality. + +The ns-3 source code directory @code{src/internet-stack} provides +implmentation of TCP/IPv4-related components. These include IPv4, +ARP, UDP, TCP, and other related protocols. + +Internet Nodes are not subclasses of class Node; they are simply Nodes +that have had a bunch of IPv4-related +objects aggregated to them. They can be put together by hand, or +via a helper function @code{AddInternetStack ()} which does the +following: +@verbatim +void AddInternetStack (Ptr node) +{ + // Create layer-3 protocols + Ptr ipv4 = CreateObject (); + Ptr arp = CreateObject (); + ipv4->SetNode (node); + arp->SetNode (node); + + // Create an L4 demux + Ptr ipv4L4Demux = CreateObject (); + + // Create transport protocols and insert them into the demux + Ptr udp = CreateObject (); + Ptr tcp = CreateObject (); + + ipv4L4Demux->SetNode (node); + udp->SetNode (node); + tcp->SetNode (node); + + ipv4L4Demux->Insert (udp); + ipv4L4Demux->Insert (tcp); + + // Add factories for instantiating transport protocol sockets + Ptr udpFactory = CreateObject (); + Ptr tcpFactory = CreateObject (); + Ptr ipv4Impl = CreateObject (); + + udpFactory->SetUdp (udp); + tcpFactory->SetTcp (tcp); + ipv4Impl->SetIpv4 (ipv4); + + // Aggregate all of these new objects to the node + node->AggregateObject (ipv4); + node->AggregateObject (arp); + node->AggregateObject (ipv4Impl); + node->AggregateObject (udpFactory); + node->AggregateObject (tcpFactory); + node->AggregateObject (ipv4L4Demux); +} +@end verbatim + +@subsection Internet Node structure + +The Internet Node (an ns-3 Node augmented by aggregation to have one or more +IP stacks) has the following internal structure. + +@subsubsection Layer-3 protocols +At the lowest layer, sitting above the NetDevices, are the "layer 3" +protocols, including IPv4, IPv6, and ARP. These protocols provide +the following key methods and data members: + +@verbatim +class Ipv4L3Protocol : public Object +{ +public: + // Add an Ipv4 interface corresponding to the provided NetDevice + uint32_t AddInterface (Ptr device); + + // Receive function that can be bound to a callback, for receiving + // packets up the stack + void Receive( Ptr device, Ptr p, uint16_t protocol, + const Address &from); + + // Higher-level layers call this method to send a packet + // down the stack to the MAC and PHY layers + // + void Send (Ptr packet, Ipv4Address source, + Ipv4Address destination, uint8_t protocol); + +private: + Ipv4InterfaceList m_interfaces; + + // Protocol handlers +} +@end verbatim +There are many more functions (such as @code{Forward ()}) but we will +focus on the above four items from an architectural perspective. + +First, note that the @code{Receive ()} function has a matching signature +to the ReceiveCallback in the @code{class Node}. This function pointer +is inserted into the the Node's protocol handler when +@code{AddInterface ()} is called. The actual registration is done +with a statement such as: +follows: +@verbatim + RegisterProtocolHandler ( MakeCallback (&Ipv4Protocol::Receive, ipv4), + Ipv4L3Protocol::PROT_NUMBER, 0); +@end verbatim + +The Ipv4L3Protocol object is aggregated to the Node; there is only one +such Ipv4L3Protocol object. Higher-layer protocols that have a packet +to send down to the Ipv4L3Protocol object can call +@code{GetObject ()} to obtain a pointer, as follows: +@verbatim + Ptr ipv4 = m_node->GetObject (); + if (ipv4 != 0) + { + ipv4->Send (packet, saddr, daddr, PROT_NUMBER); + } +@end verbatim + +This class nicely demonstrates two techniques we exploit in +ns-3 to bind objects together: callbacks, and object aggregation. + +Once IPv4 has determined that a packet is for the local node, it +forwards it up the stack. This is done with the following function: + +@verbatim +void +Ipv4L3Protocol::ForwardUp (Ptr p, Ipv4Header const&ip, + Ptr incomingInterface) +{ + NS_LOG_FUNCTION (this << p << &ip); + + Ptr demux = m_node->GetObject (); + Ptr protocol = demux->GetProtocol (ip.GetProtocol ()); + protocol->Receive (p, ip.GetSource (), ip.GetDestination (), incomingInterface); +} +@end verbatim + +The first step is to find the aggregated Ipv4L4Demux object. Then, this +object is consulted to look up the right Ipv4L4Protocol, based on IP protocol +number. For instance, TCP is registered in the demux as protocol number 6. +Finally, the @code{Receive()} function on the Ipv4L4Protocol (such as +@code{TcpL4Protocol::Receive} is called. + +We have not yet introduced the class Ipv4Interface. Basically, +each NetDevice is paired with an IPv4 representation of such device. +In Linux, this @code{class Ipv4Interface} roughly corresponds to +the @code{struct in_device}; the main purpose is to provide +address-family specific information (addresses) about an interface. + +@subsubsection Layer-4 protocols and sockets + +We next describe how the transport protocols, sockets, and applications +tie together. In summary, each transport protocol implementation is +a socket factory. An application that needs a new socket + +For instance, to create a UDP socket, an application would use a code +snippet such as the following: +@verbatim + Ptr udpSocketFactory = GetNode ()->GetObject (); + Ptr m_socket = socketFactory->CreateSocket (); + m_socket->Bind (m_local_address); + ... +@end verbatim +The above will query the node to get a pointer to its UDP socket +factory, will create one such socket, and will use the socket with +an API similar to the C-based sockets API, such as @code{Connect ()} +and @code{Send ()}. See the chapter on ns-3 sockets for more information. + +We have described so far a socket factory (e.g. @code{class Udp}) and +a socket, which may be specialized (e.g., @code{class UdpSocket}). +There are a few more key objects that relate to the specialized +task of demultiplexing a packet to one or more receiving sockets. +The key object in this task is @code{class Ipv4EndPointDemux}. +This demultiplexer stores objects of @code{class Ipv4EndPoint}. +This class holds the addressing/port tuple (local port, local address, +destination port, destination address) associated with the socket, +and a receive callback. This receive callback has a receive +function registered by the socket. The @code{Lookup ()} function to +Ipv4EndPointDemux returns a list of Ipv4EndPoint objects (there may +be a list since more than one socket may match the packet). The +layer-4 protocol copies the packet to each Ipv4EndPoint and calls +its @code{ForwardUp ()} method, which then calls the @code{Receive ()} +function registered by the socket. + +An issue that arises when working with the sockets API on real +systems is the need to manage the reading from a socket, using +some type of I/O (e.g., blocking, non-blocking, asynchronous, ...). +ns-3 implements an asynchronous model for socket I/O; the application +sets a callback to be notified of received data ready to be read, and the +callback is invoked by the transport protocol when data is available. +This callback is specified as follows: +@verbatim + void Socket::SetRecvCallback (Callback, + Ptr, const Address&> receivedData); +@end verbatim +The data being received is conveyed in the Packet data buffer. An example +usage is in @code{class PacketSink}: +@verbatim + m_socket->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this)); +@end verbatim + +To summarize, internally, the UDP implementation is organized as follows: +@itemize @bullet +@item a @code{UdpImpl} class that implements the Udp socket factory +functionality +@item a @code{UdpL4Protocol} class that implements the protocol logic +that is socket-independent +@item a @code{UdpSocketImpl} class that implements socket-specific aspects +of UDP +@item a class called @code{Ipv4EndPoint} that stores the +addressing tuple (local port, local address, destination port, destination +address) associated with the socket, and a receive callback for the socket. +@end itemize + +@subsection Internet Node interfaces + +Many of the implementation details, or internal objects themselves, +of Internet Node objects are not exposed at the simulator public +API. This allows for different implementations; for instance, +replacing the native ns-3 models with ported TCP/IP stack code. + +The C++ public APIs of all of these objects is found in the +@code{src/node} directory, including principally: +@itemize @bullet +@item @code{socket.h} +@item @code{tcp.h} +@item @code{udp.h} +@item @code{ipv4.h} +@end itemize +These are typically base class objects that implement the default +values used in the implementation, implement access methods to get/set +state variables, host attributes, and implement publicly-available methods +exposed to clients such as @code{CreateSocket}. + +@subsection Example path of a packet + +These two figures show an example stack trace of how packets flow +through the Internet Node objects. + +@float Figure,fig:internet-node-send +@caption{Send path of a packet.} +@image{figures/internet-node-send,5in} +@end float + +@float Figure,fig:internet-node-recv +@caption{Receive path of a packet.} +@image{figures/internet-node-recv,5in} +@end float + diff --git a/doc/tutorial/other.texi b/doc/manual/other.texi similarity index 100% rename from doc/tutorial/other.texi rename to doc/manual/other.texi diff --git a/doc/tutorial/output.texi b/doc/manual/output.texi similarity index 100% rename from doc/tutorial/output.texi rename to doc/manual/output.texi diff --git a/doc/tutorial/packets.texi b/doc/manual/packets.texi similarity index 99% rename from doc/tutorial/packets.texi rename to doc/manual/packets.texi index cc00e0094..b4cc4e3b8 100644 --- a/doc/tutorial/packets.texi +++ b/doc/manual/packets.texi @@ -1,5 +1,5 @@ -@node ns-3 Packets -@chapter ns-3 Packets +@node Packets +@chapter Packets The design of the Packet framework of @emph{ns} was heavily guided by a few important use-cases: diff --git a/doc/manual/random.texi b/doc/manual/random.texi new file mode 100644 index 000000000..c350bdaf8 --- /dev/null +++ b/doc/manual/random.texi @@ -0,0 +1,304 @@ +@anchor{chap:rv} +@node Random variables +@chapter Random variables + +ns-3 contains a built-in pseudo-random number generator (PRNG). +It is important for serious users of the simulator to understand +the functionality, configuration, and usage of this PRNG, and +to decide whether it is sufficient for his or her research use. + +@node Quick Overview +@section Quick Overview + +ns-3 random numbers are provided via instances of @code{class RandomVariable}. +@itemize @bullet +@item @strong{by default, ns-3 simulations use a random seed}; if there is any +randomness in the simulation, each run of the program will yield different results. To use a fixed seed, users must call +@code{RandomVariable::UseGlobalSeed ()} at the beginning of the program; +see section @xref{Seeding and independent replications} +@item each RandomVariable used in ns-3 has a virtual random number +generator associated with it; all random variables use either a fixed +or random seed based on the use of the global seed (previous bullet); +@item if you intend to perform multiple runs of the same scenario, with +different random numbers, please be sure to read the section on how to +perform independent replications: @xref{Seeding and independent replications}. +@end itemize + +Read further for more explanation about the random number facility for +ns-3. + +@node Background +@section Background + +Simulations use a lot of random numbers; the study in [cite] +found that most network simulations spend as much as 50% +of the CPU generating random numbers. Simulation users need +to be concerned with the quality of the (pseudo) random numbers and +the independence between different streams of random numbers. + +Users need to be concerned with a few issues, such as: +@itemize @bullet +@item the seeding of the random number generator and whether a +simulation run is deterministic or not, +@item how to acquire different streams of random numbers that are +independent from one another, and +@item how long it takes for streams to cycle +@end itemize + +We will introduce a few terms here: a RNG provides a long sequence +of (pseudo) random numbers. +The length of this sequence is called the @emph{cycle length} +or @emph{period}, after which the RNG will repeat itself. +This sequence can +be partitioned into disjoint @emph{streams}. A stream of a +RNG is a contiguous subset or block of the RNG sequence. +For instance, if the +RNG period is of length N, and two streams are provided from this +RNG, then +the first stream might use the first N/2 values and the second +stream might produce the second N/2 values. An important property +here is that the two streams are uncorrelated. Likewise, each +stream can be partitioned disjointly to a number of +uncorrelated @emph{substreams}. The underlying RNG hopefully +produces a pseudo-random sequence of numbers with a very long +cycle length, and partitions this into streams and substreams in an +efficient manner. + +ns-3 uses the same underlying random number generator as does +ns-2: the MRG32k3a generator from Pierre L'Ecuyer. A +detailed description can be found in +@uref{http://www.iro.umontreal.ca/~lecuyer/myftp/papers/streams00.pdf,,}. +The MRG32k3a generator provides 1.8x10^19 independent +streams of random numbers, each of which consists of +2.3x10^15 substreams. Each substream has a period +(@emph{i.e.}, the number of random numbers before overlap) of +7.6x10^22. The period of the entire generator is +3.1x10^57. Figure ref-streams provides a graphical idea of +how the streams and substreams fit together. + +Class @code{ns3::RandomVariable} is the public interface to this +underlying random number generator. When users create new +RandomVariables (such as UniformVariable, ExponentialVariable, +etc.), they create an object that uses one of the distinct, independent +streams of the random number generator. Therefore, each +object of type RandomVariable has, conceptually, its own "virtual" RNG. +Furthermore, each RandomVariable can be configured to use +one of the set of substreams drawn from the main stream. + +An alternate implementation would be to allow each RandomVariable +to have its own (differently seeded) RNG. However, we cannot +guarantee as strongly that the different sequences would be +uncorrelated in such a case; hence, we prefer to use a single RNG +and streams and substreams from it. + +@anchor{chap:rv:indeprep} +@node Seeding and independent replications +@section Seeding and independent replications + +ns-3 simulations can be configured to produce deterministic or +random results. If the ns-3 simulation is configured to use +a fixed, deterministic seed with the same run number, it should give +the same output each time it is run. + +By default, ns-3 simulations use random seeds where the seeding +is drawn from @code{/dev/random} (if it is available) or else from +the time of day. A user who wants to fix the initial seeding +of the PRNG must call the following static method during simulation +configuration: +@verbatim +RandomVariable::UseGlobalSeed (uint32_t s0, s1, s2, s3, s4, s5); +@end verbatim +where the six parameters are each of type uint32_t. + +A typical use case is to run a simulation as a sequence of independent +trials, so as to compute statistics on a large number of independent +runs. The user can either change the global seed and rerun the +simulation, or can advance the substream state of the RNG. +This seeding and substream state setting must be called before any +random variables are created; e.g. + +@verbatim + RandomVariable::UseGlobalSeed(1,2,3,4,5,6); + int N = atol(argv[1]); //read in run number from command line + RandomVariable::SetRunNumber(N); + // Now, create random variables + UniformVariable x(0,10); + ExponentialVariable y(2902); + ... +@end verbatim + +Which is better, setting a new seed or advancing the substream state? +There is no guarantee that the streams +produced by two random seeds will not overlap. The only way to +guarantee that two streams do not overlap is to use the substream +capability provided by the RNG implementation. +@strong{Therefore, use the substream capability to produce +multiple independent runs of the same simulation.} +In other words, the more statistically rigorous way to configure +multiple independent replications is not to simply ignore the +seeding (and use /dev/random to seed the generator each time) but +instead to use a fixed seed and to iterate the run number. +This implementation allows for a maximum of +2.3x10^15 independent replications using the substreams. + +@node class RandomVariable +@section class RandomVariable + +All random variables should derive from @code{class RandomVariable}. +This base class provides a few static methods for globally configuring +the behavior of the random number generator. Derived classes +provide API for drawing random variates from the particular +distribution being supported. + +Each RandomVariable created in the simulation is given a generator +that is a new RNGStream from the underlying PRNG. +Used in this manner, the L'Ecuyer implementation allows for a maximum of +1.8x10^19 random variables. Each random variable in +a single replication can produce up to 7.6x10^22 random +numbers before overlapping. + +@node Base class public API +@section Base class public API + +Below are excerpted a few public methods of @code{class RandomVariable} +that deal with the global configuration and state of the RNG. +@verbatim + /** + * \brief Set seeding behavior + * + * Specify whether the POSIX device /dev/random is to + * be used for seeding. When this is used, the underlying + * generator is seeded with data from /dev/random instead of + * being seeded based upon the time of day. Defaults to true. + */ + static void UseDevRandom(bool udr = true); + + /** + * \brief Use the global seed to force precisely reproducible results. + */ + static void UseGlobalSeed(uint32_t s0, uint32_t s1, uint32_t s2, + uint32_t s3, uint32_t s4, uint32_t s5); + + /** + * \brief Set the run number of this simulation + */ + static void SetRunNumber(uint32_t n); + + /** + * \brief Get the internal state of the RNG + * + * This function is for power users who understand the inner workings + * of the underlying RngStream method used. It returns the internal + * state of the RNG via the input parameter. + * \param seed Output parameter; gets overwritten with the internal state + * of the RNG. + */ + void GetSeed(uint32_t seed[6]) const; +@end verbatim + +We have already described the seeding configuration above. + +@node Types of RandomVariables +@section Types of RandomVariables + +The following types of random variables are provided, and are documented +in the ns-3 Doxygen or by reading @code{src/core/random-variable.h}. Users +can also create their own custom random variables by deriving from +class RandomVariable. +@itemize @bullet +@item @code{class UniformVariable } +@item @code{class ConstantVariable } +@item @code{class SequentialVariable } +@item @code{class ExponentialVariable } +@item @code{class ParetoVariable } +@item @code{class WeibullVariable } +@item @code{class NormalVariable } +@item @code{class EmpiricalVariable } +@item @code{class IntEmpiricalVariable } +@item @code{class DeterministicVariable } +@item @code{class LogNormalVariable } +@item @code{class TriangularVariable } +@end itemize + +@node Semantics of RandomVariable objects +@section Semantics of RandomVariable objects + +RandomVariable objects have value semantics. This means that they +can be passed by value to functions. The can also be passed by +reference to const. RandomVariables do not derive from +@code{ns3::Object} and we do not use smart pointers to manage them; +they are either allocated on the stack or else users explicitly manage +any heap-allocated RandomVariables. + +RandomVariable objects can also be used in ns-3 attributes, which means +that values can be set for them through the ns-3 attribute system. +An example is in the propagation models for WifiNetDevice: +@verbatim +TypeId +RandomPropagationDelayModel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::RandomPropagationDelayModel") + .SetParent () + .AddConstructor () + .AddAttribute ("Variable", + "The random variable which generates random delays (s).", + RandomVariableValue (UniformVariable (0.0, 1.0)), + MakeRandomVariableAccessor (&RandomPropagationDelayModel::m_variable), + MakeRandomVariableChecker ()) + ; + return tid; +} +@end verbatim +Here, the ns-3 user can change the default random variable for this +delay model (which is a UniformVariable ranging from 0 to 1) through +the attribute system. + +@node Using other PRNG +@section Using other PRNG + +There is presently no support for substituting a different underlying +random number generator (e.g., the GNU Scientific Library or the Akaroa +package). Patches are welcome. + +@node More advanced usage +@section More advanced usage + +@emph{To be completed} + +@node Publishing your results +@section Publishing your results + +When you publish simulation results, a key piece of configuration +information that you should always state is how you used the +the random number generator. +@itemize @bullet +@item what seeds you used, +@item what RNG you used if not the default, +@item how were independent runs performed, +@item for large simulations, how did you check that you did not cycle. +@end itemize + +It is incumbent on the researcher publishing results to include enough +information to allow others to reproduce his or her results. It is +also incumbent on the researcher to convince oneself that the random +numbers used were statistically valid, and to state in the paper why +such confidence is assumed. + +@node Summary +@section Summary + +Let's review what things you should do when creating a simulation. + +@itemize @bullet +@item Decide whether you are running with a fixed seed or random seed; +a random seed is the default, +@item Decide how you are going to manage independent replications, if +applicable, +@item Convince yourself that you are not drawing more random values +than the cycle length, if you are running a long simulation, and +@item When you publish, follow the guidelines above about documenting your +use of the random number generator. +@end itemize + +The program @emph{samples/main-random.cc} has some examples of usage. + diff --git a/doc/manual/realtime.texi b/doc/manual/realtime.texi new file mode 100644 index 000000000..e5d3c7d4b --- /dev/null +++ b/doc/manual/realtime.texi @@ -0,0 +1,100 @@ +@node RealTime +@chapter Real-Time Scheduler +@anchor{chap:RealTime} + +ns-3 has been designed for integration into testbed and virtual machine +environments. To integrate with real network stacks and emit/consume +packets, a real-time scheduler is needed to try to lock the simulation +clock with the hardware clock. We describe here a component of this: +the RealTime scheduler. + +The purpose of the realtime scheduler is to cause the progression of +the simulation clock to occur synchronously with respect to some +external time base. Without the presence of an external time base +(wall clock), simulation time jumps instantly from one simulated time to +the next. + +@section Behavior + +When using a non-realtime scheduler (the default in ns-3), the simulator +advances the simulation time to the next scheduled event. During event +execution, simulation time is frozen. With the realtime scheduler, the +behavior is similar from the perspective of simulation models (i.e., +simulation time is frozen during event execution), but between events, +the simulator will attempt to keep the simulation clock aligned with +the machine clock. + +When an event is finished executing, and the scheduler moves to the next +event, the scheduler compares the next event execution time with the +machine clock. If the next event is scheduled for a future time, +the simulator sleeps until that realtime is reached and then executes +the next event. + +It may happen that, due to the processing inherent in the execution +of simulation events, that the simulator cannot keep up with realtime. +In such a case, it is up to the user configuration what to do. There +are two ns-3 attributes that govern the behavior. The first is +@code{ns3::RealTimeSimulatorImpl::SynchronizationMode}. The two +entries possible for this attribute are @code{BestEffort} (the default) +or @code{HardLimit}. In "BestEffort" mode, the simulator will just +try to catch up to realtime by executing events until it reaches +a point where the next event is in the (realtime) future, or else +the simulation ends. In BestEffort mode, then, it is possible for +the simulation to consume more time than the wall clock time. The +other option "HardLimit" will cause the simulation to abort if the tolerance +threshold is exceeded. This attribute is +@code{ns3::RealTimeSimulatorImpl::HardLimit} and the default is 0.1 seconds. + +A different mode of operation is one in which simulated time is @strong{not} +frozen during an event execution. This mode of realtime simulation was +implemented but removed from the ns-3 tree because of questions of whether +it would be useful. If users are interested in a realtime simulator +for which simulation time does not freeze during event execution (i.e., +every call to @code{Simulator::Now()} returns the current wall clock time, +not the time at which the event started executing), please contact the +ns-developers mailing list. + +@section Usage + +The usage of the realtime simulator is straightforward, from a scripting +perspective. Users just need to set the attribute +@code{SimulatorImplementationType} to the Realtime simulator, such as follows: +@verbatim + GlobalValue::Bind ("SimulatorImplementationType", + StringValue ("ns3::RealtimeSimulatorImpl")); +@end verbatim + +There is a script in @code{examples/realtime-udp-echo.cc} that has an +example of how to configure the realtime behavior. Try: +@verbatim +./waf --run realtime-udp-echo +@end verbatim + +Whether the simulator will work in a best effort or hard limit policy +fashion is governed by the attributes explained in the previous section. + +@section Implementation + +The implementation is contained in the following files: +@itemize @bullet +@item @code{src/simulator/realtime-simulator-impl.{cc,h}} +@item @code{src/simulator/wall-clock-synchronizer.{cc,h}} +@end itemize + +In order to create a realtime scheduler, to a first approximation you +just want to cause simulation time jumps to consume real time. We propose +doing this using a combination of sleep- and busy- waits. Sleep-waits cause +the calling process (thread) to yield the processor for some amount of time. +Even though this specified amount of time can be passed to nanosecond +resolution, it is actually converted to an OS-specific granularity. +In Linux, the granularity is called a Jiffy. Typically this resolution is +insufficient for our needs (on the order of a ten milliseconds), so we +round down and sleep for some smaller number of Jiffies. The process is +then awakened after the specified number of Jiffies has passed. At this +time, we have some residual time to wait. This time is generally smaller +than the minimum sleep time, so we busy-wait for the remainder of the time. +This means that the thread just sits in a for loop consuming cycles until +the desired time arrives. After the combination of sleep- and busy-waits, +the elapsed realtime (wall) clock should agree with the simulation time +of the next event and the simulation proceeds. + diff --git a/doc/tutorial/routing.texi b/doc/manual/routing.texi similarity index 99% rename from doc/tutorial/routing.texi rename to doc/manual/routing.texi index d8250ee24..dbd054f7a 100644 --- a/doc/tutorial/routing.texi +++ b/doc/manual/routing.texi @@ -1,5 +1,5 @@ -@node ns-3 routing overview -@chapter ns-3 routing overview +@node Routing overview +@chapter Routing overview This chapter describes the overall design of routing in the @code{src/internet-stack} diff --git a/doc/tutorial/sockets.texi b/doc/manual/sockets.texi similarity index 100% rename from doc/tutorial/sockets.texi rename to doc/manual/sockets.texi diff --git a/doc/tutorial/statistics.texi b/doc/manual/statistics.texi similarity index 100% rename from doc/tutorial/statistics.texi rename to doc/manual/statistics.texi diff --git a/doc/manual/tcp.texi b/doc/manual/tcp.texi new file mode 100644 index 000000000..f21315837 --- /dev/null +++ b/doc/manual/tcp.texi @@ -0,0 +1,342 @@ +@node TCP +@chapter TCP models in ns-3 +@anchor{chap:TCP} + +This chapter describes the TCP models available in ns-3. + +@section Generic support for TCP + +ns-3 was written to support multiple TCP implementations. The +implementations inherit from a few common header classes in the +@code{src/node} directory, so that user code can swap out implementations +with minimal changes to the scripts. + +There are two important abstract base classes: +@itemize @bullet +@item @code{class TcpSocket}: This is defined in @code{src/node/tcp-socket.{cc,h}}. This class exists for hosting TcpSocket attributes that can be +reused across different implementations. For instance, +@code{TcpSocket::SetInitialCwnd()} can be used for any of the implementations +that derive from @code{class TcpSocket}. +@item @code{class TcpSocketFactory}: This is used by applications to +create TCP sockets. A typical usage can be seen in this snippet: +@verbatim + // Create the socket if not already created + if (!m_socket) + { + m_socket = Socket::CreateSocket (GetNode(), m_tid); + m_socket->Bind (m_local); + ... + } +@end verbatim +The parameter @code{m_tid} controls the TypeId of the actual Tcp Socket +implementation that is instantiated. This way, the application can be +written generically and different socket implementations can be swapped out +by specifying the TypeId. +@end itemize + +@section ns-3 TCP + +ns-3 contains a port of the TCP model from +@uref{http://www.ece.gatech.edu/research/labs/MANIACS/GTNetS/index.html,,GTNetS}. This model is a full TCP, in that it is +bidirectional and attempts to model the connection setup and +close logic. In fact, it is a more complete implementation of the TCP +state machine than ns-2's "FullTcp" model. This TCP model was originally +written by George Riley +as part of GTNetS and ported to ns-3 by Raj Bhattacharjea. + +The implementation of TCP is contained in the following files: +@verbatim +src/internet-stack/tcp-header.{cc,h} +src/internet-stack/tcp-l4-protocol.{cc,h} +src/internet-stack/tcp-socket-factory-impl.{cc,h} +src/internet-stack/tcp-socket-impl.{cc,h} +src/internet-stack/tcp-typedefs.h +src/internet-stack/rtt-estimator.{cc,h} +src/internet-stack/sequence-number.{cc,h} +@end verbatim + +@subsection Usage + +The file @code{examples/tcp-star-server.cc} contains an example that +makes use of @code{ns3::OnOffApplication} and @code{ns3::PacketSink} +applications. + +Using the helper functions defined in @code{src/helper}, here is how +one would create a TCP receiver: +@verbatim + // Create a packet sink on the star "hub" to receive these packets + uint16_t port = 50000; + Address sinkLocalAddress(InetSocketAddress (Ipv4Address::GetAny (), port)); + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress); + ApplicationContainer sinkApp = sinkHelper.Install (serverNode); + sinkApp.Start (Seconds (1.0)); + sinkApp.Stop (Seconds (10.0)); +@end verbatim + +Similarly, the below snippet configures OnOffApplication traffic +source to use +TCP: +@verbatim + // Create the OnOff applications to send TCP to the server + OnOffHelper clientHelper ("ns3::TcpSocketFactory", Address ()); +@end verbatim + +The careful reader will note above that we have specified the TypeId +of an abstract base class @code{TcpSocketFactory}. How does the +script tell ns-3 that it wants the native ns-3 TCP vs. some other one? +Well, when internet stacks are added to the node, the default +TCP implementation that is aggregated to the node is the ns-3 TCP. +This can be overridden as we show below when using Network +Simulation Cradle. So, by default, when using the ns-3 helper API, +the TCP that is aggregated to nodes with an Internet stack is the +native ns-3 TCP. + +Once a TCP socket is created, you will want to follow conventional +socket logic and either connect() and send() (for a TCP client) +or bind(), listen(), and accept() (for a TCP server). +@xref{Sockets APIs,,Sockets API} for a review of how sockets are used +in ns-3. + +To configure behavior of TCP, a number of parameters are exported through +the @ref{Attributes,,ns-3 attribute system}. These are documented in the +@uref{http://www.nsnam.org/doxygen/classns3_1_1_tcp_socket.html,,Doxygen} +for @code{class TcpSocket}. + +@subsection Current limitations +@itemize @bullet +@item Only Tahoe congestion control is presently supported. +@item Only IPv4 is supported (IPv6 support will start to be added in ns-3.3). +@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=198,,Bug 198}: TcpSocketImpl doesn't send acks with data packets in two-way transfers +@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=250,,Bug 250}: Tcp breaks if you set the DelAckCount parameter to be greater than 2 +@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=311,,Bug 311}: Tcp socket close returns -1 but does not set errno. +@end itemize + +@section Network Simulation Cradle + +The @uref{http://www.wand.net.nz/~stj2/nsc/,,Network Simulation Cradle (NSC)} +is a framework for wrapping real-world network +code into simulators, allowing simulation of real-world behavior at little +extra cost. This work has been validated by comparing situations using +a test network with the same situations in the simulator. To date, it has +been shown that the NSC is able to produce extremely accurate results. +NSC supports four real world stacks: FreeBSD, OpenBSD, lwIP and Linux. +Emphasis has been placed on not changing any of the network stacks by hand. +Not a single line of code has been changed in the network protocol +implementations of any of the above four stacks. However, a custom C +parser was built to programmatically change source code. + +NSC has previously been ported to ns-2 and OMNeT++, and recently +was added to ns-3. This section describes the ns-3 port of NSC and +how to use it. + +@subsection Prerequisites + +Presently, NSC has been tested and shown to work on these platforms: +Linux i386 and Linux x86-64. NSC does not support powerpc at the moment. + +NSC requires the packages mercurial, flex, and bison. + +@subsection Configuring and Downloading + +NSC is disbled by default and must be explicitly configured in. To try +this, type +@verbatim +./waf configure --enable-nsc +@end verbatim +the output of the configuration will show something like: +@verbatim +Checking for NSC supported architecture x86_64 : ok +Pulling nsc updates from https://secure.wand.net.nz/mercurial/nsc +pulling from https://secure.wand.net.nz/mercurial/nsc +searching for changes +no changes found +---- Summary of optional NS-3 features: +... +Network Simulation Cradle : enabled +... +@end verbatim +if successful. Note that the configure script pulls a recent copy of +NSC from a mercurial repository. This download will not work if you are not +online. + +If everything went OK, you will see a directory called "nsc" in the top-level +directory, with contents like this: +@verbatim +audit.sh linux-2.6/ openbsd3/ scons-time.py* +ChangeLog linux-2.6.18/ README SConstruct +config.log linux-2.6.26/ sconsign.py* sim/ +freebsd5/ lwip-1.3.0/ scons-LICENSE test/ +globaliser/ lwip-HEAD/ scons-local-1.0.1/ +INSTALL ns/ scons.py* +LICENSE omnetpp/ scons-README +@end verbatim + +@subsection Building and validating + +Building ns-3 with nsc support is the same as building it without; no +additional arguments are needed for waf. Building nsc may take some time +compared to ns-3; it is interleaved in the ns-3 building process. + +Try running the regression tests: @code{./waf --regression}. If NSC has +been successfully built, the following test should show up in the results: +@verbatim +PASS test-tcp-nsc-lfn +@end verbatim + +This confirms that NSC is ready to use. + +@subsection Usage +There are a few example files. Try +@verbatim +./waf --run tcp-nsc-zoo +./waf --run tcp-nsc-lfn +@end verbatim +These examples will deposit some @code{.pcap} files in your directory, +which can be examined by tcpdump or wireshark. + +Let's look at the @code{examples/tcp-nsc-zoo.cc} file for some typical +usage. How does it differ from using native ns-3 TCP? There is one +main configuration line, when using NSC and the ns-3 helper API, that needs +to be set: +@verbatim + InternetStackHelper internetStack; + + internetStack.SetNscStack ("liblinux2.6.26.so"); + // this switches nodes 0 and 1 to NSCs Linux 2.6.26 stack. + internetStack.Install (n.Get(0)); + internetStack.Install (n.Get(1)); +@end verbatim + +The key line is the @code{SetNscStack}. This tells the InternetStack +helper to aggregate instances of NSC TCP instead of native ns-3 TCP +to the remaining nodes. It is important that this function be called +@strong{before} callling the @code{Install()} function, as shown above. + +Which stacks are available to use? Presently, the focus has been on +Linux 2.6.18 and Linux 2.6.26 stacks for ns-3. To see which stacks +were built, one can execute the following find command at the ns-3 top level +directory: +@verbatim +~/ns-3.2> find nsc -name "*.so" -type f +nsc/linux-2.6.18/liblinux2.6.18.so +nsc/linux-2.6.26/liblinux2.6.26.so +@end verbatim +This tells us that we may either pass the library name liblinux2.6.18.so or +liblinux2.6.26.so to the above configuration step. + +@subsection Stack configuration +NSC TCP shares the same configuration attributes that are common +across TCP sockets, as described above and documented in +@uref{http://www.nsnam.org/doxygen/classns3_1_1_tcp_socket.html,,Doxygen} + +Additionally, NSC TCP exports a lot of configuration variables into the +ns-3 @ref{Attributes} system, via a @uref{http://en.wikipedia.org/wiki/Sysctl,, +sysctl}-like interface. In the @code{examples/tcp-nsc-zoo} example, you +can see the following configuration: +@verbatim + // this disables TCP SACK, wscale and timestamps on node 1 (the attributes represent sysctl-values). + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_sack", StringValue ("0")); + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_timestamps", StringValue ("0")); + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_window_scaling", StringValue ("0")); +@end verbatim +These additional configuration variables are not available to native ns-3 +TCP. + +@subsection NSC API + +This subsection describes the API that NSC presents to ns-3 or any other +simulator. NSC provides its API in the form of a number of classes that +are defined in @code{sim/sim_interface.h} in the nsc directory. + +@itemize @bullet +@item @strong{INetStack} +INetStack contains the 'low level' operations for the operating system +network stack, e.g. in and output functions from and to the network stack +(think of this as the 'network driver interface'. There are also functions +to create new TCP or UDP sockets. +@item @strong{ISendCallback} +This is called by NSC when a packet should be sent out to the network. +This simulator should use this callback to re-inject the packet into the +simulator so the actual data can be delivered/routed to its destination, +where it will eventually be handed into Receive() (and eventually back to the +receivers NSC instance via INetStack->if_receive() ). +@item @strong{INetStreamSocket} +This is the structure defining a particular connection endpoint (file +descriptor). It contains methods to operate on this endpoint, e.g. connect, +disconnect, accept, listen, send_data/read_data, ... +@item @strong{IInterruptCallback} +This contains the wakeup callback, which is called by NSC whenever +something of interest happens. Think of wakeup() as a replacement of the +operating systems wakeup function: Whenever the operating system would +wake up a process that has been waiting for an operation to complete (for +example the TCP handshake during connect()), NSC invokes the wakeup() callback +to allow the simulator to check for state changes in its connection endpoints. +@end itemize + +@subsection ns-3 implementation + +The ns-3 implementation makes use of the above NSC API, and is implemented +as follows. + +The three main parts are: +@itemize @bullet +@item @code{ns3::NscTcpL4Protocol}: a subclass of Ipv4L4Protocol (and two nsc classes: ISendCallback and IInterruptCallback) +@item @code{ns3::NscTcpSocketImpl}: a subclass of TcpSocket +@item @code{ns3::NscTcpSocketFactoryImpl}: a factory to create new NSC +sockets +@end itemize + +@code{src/internet-stack/nsc-tcp-l4-protocol} is the main class. Upon +Initialization, it loads an nsc network stack to use (via dlopen()). Each +instance of this class may use a different stack. The stack +(=shared library) to use is set using the SetNscLibrary() method (at +this time its called indirectly via the internet stack helper). The nsc +stack is then set up accordingly (timers etc). The +NscTcpL4Protocol::Receive() function hands the packet it receives (must be +a complete tcp/ip packet) to the nsc stack for further processing. +To be able to send packets, this class implements the nsc send_callback +method. This method is called by nsc whenever the nsc stack wishes to +send a packet out to the network. Its arguments are a raw buffer, +containing a complete TCP/IP packet, and a length value. This method +therefore has to convert the raw data to a Ptr usable by ns-3. +In order to avoid various ipv4 header issues, the nsc ip header is not +included. Instead, the tcp header and the actual payload are put into the +Ptr, after this the Packet is passed down to layer 3 for sending +the packet out (no further special treatment is needed in the send code +path). + +This class calls @code{ns3::NscTcpSocketImpl} both from the nsc wakeup() +callback and from the Receive path (to ensure that possibly queued data +is scheduled for sending). + + +@code{src/internet-stack/nsc-tcp-socket-impl} implements the nsc socket +interface. Each instance has its own nscTcpSocket. Data that is Send() +will be handed to the nsc stack via m_nscTcpSocket->send_data(). (and not +to nsc-tcp-l4, this is the major difference compared to ns-3 TCP). The +class also queues up data that is Send() before the underlying +descriptor has entered an ESTABLISHED state. This class is called from +the nsc-tcp-l4 class, when the nsc-tcp-l4 wakeup() callback is invoked by +nsc. nsc-tcp-socket-impl then checks the current connection state +(SYN_SENT, ESTABLISHED, LISTEN...) and schedules appropriate callbacks as +needed, e.g. a LISTEN socket will schedule Accept to see if a new +connection must be accepted, an ESTABLISHED socket schedules any pending +data for writing, schedule a read callback, etc. + +Note that @code{ns3::NscTcpSocketImpl} does not interact with nsc-tcp +directly: instead, data is redirected to nsc. nsc-tcp calls the +nsc-tcp-sockets of a node when its wakeup callback is invoked by nsc. + +@subsection Limitations +@itemize @bullet +@item NSC only works on single-interface nodes; attempting to run it on +a multi-interface node will cause a program error. This limitation should +be fixed by ns-3.3. +@item Cygwin and OS X PPC are not presently supported +@item The non-Linux stacks of NSC are not supported +@item NSC's integration into the build system presently requires on-line +access and mercurial, and is a slow download. +@end itemize + +For more information, see +@uref{http://www.nsnam.org/wiki/index.php/Network_Simulation_Cradle_Integration,, this wiki page}. diff --git a/doc/tutorial/troubleshoot.texi b/doc/manual/troubleshoot.texi similarity index 100% rename from doc/tutorial/troubleshoot.texi rename to doc/manual/troubleshoot.texi diff --git a/doc/release_steps.txt b/doc/release_steps.txt index a31da0fba..f4d666be4 100644 --- a/doc/release_steps.txt +++ b/doc/release_steps.txt @@ -1,50 +1,78 @@ Steps in doing an ns-3 release -0. check out a clean ns-3-dev somewhere -1. prepare the source files +1. check out a clean ns-3-dev somewhere +2. prepare the source files - revise and check in AUTHORS, if needed - revise and check in RELEASE_NOTES - - update and check in VERSION to the latest release number + - DO NOT change VERSION at this time - confirm that Doxygen builds cleanly and without warnings (./waf check; ./waf --doxygen), and check in any necessary changes -2. ./waf configure; ./waf dist - - this will create a ns-3.0.x.tar.bz2 tarball - - this will also create a ns-3.0.x-ref-traces.tar.bz2 tarball -3. test tarball on release platforms (waf check and maybe some other scripts) -4. once you are happy with the tarball, tag ns-3-dev with "release ns-3.0.X" - - hg tag "release ns-3.0.x" + - ensure no regressions (./waf --regression) +3. ./waf configure; ./waf dist + - this will create an ns-3-dev.tar.bz2 tarball + - this will also create a ns-3-dev-ref-traces.tar.bz2 tarball +4. test dev tarball on release platforms (waf check and maybe some other + scripts) +5. once you are happy with the tarball, tag ns-3-dev and ns-3-dev-ref-traces + - hg tag "ns-3.x" - hg push -5. clone the tagged ns-3-dev and place it on the repository + - cd into regression/ns-3-dev-ref-traces + - hg tag "ns-3.x" + - hg push +6. clone the tagged ns-3-dev and place it on the repository - ssh code.nsnam.org; sudo tcsh; 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: - "description = ns-3.0.x release - name = ns-3.0.x" -6. Run the regression tests on the new release and update the reference traces + - cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.1x + - cd /home/code/repos/ns-3.x/.hg and edit the hgrc appropriately: + "description = ns-3.x release + name = ns-3.x" + - clone the ns-3-dev-ref-traces and place it on the repository as above + but use the name ns-3.x-ref-traces and edit the hgrc appropriately +7. check out a clean version of the new release (ns-3.x) somewhere +8. Update the VERSION for this new release + - change the string 3-dev in the VERSION file to the real version + (e.g. 3.2) This must agree with the version name you chose in the clone + for the regression tests to work. + - hg commit + - hg push +9. Run the regression tests on the new release (debug and optimized) + - ./waf -d debug configure + - ./waf + - ./waf --regression + - ./waf --valgrind --regression (for valgrind version) + - ./waf -d optimized configure + - ./waf - ./waf --regression - ./waf --valgrind --regression (for valgrind version) - There should be no regression errors at this time - - tag ns-3-dev-ref-traces with "release ns-3.0.X" - hg tag "release ns-3.0.x" - hg push - - clone the ns-3-dev-ref-traces and place it on the repository as in step - 5 but use the name ns-3.0.x-ref-traces -7. Create a reference traces tarball - - again, run "./waf dist" -8. upload "ns-3.0.x.tar.bz2" to the /var/www/html/releases/ directory on +10. Create final tarballs + - ./waf configure; ./waf dist + - this will create an ns-3.x.tar.bz2 tarball + - this will also create a ns-3.x-ref-traces.tar.bz2 tarball +11. upload "ns-3.x.tar.bz2" to the /var/www/html/releases/ directory on the www.nsnam.org server - give it 644 file permissions, and user/group = apache -9. upload "ns-3.0.x-ref-traces.tar.bz2" to the /var/www/html/releases/ +12. upload "ns-3.x-ref-traces.tar.bz2" to the /var/www/html/releases/ directory on the www.nsnam.org server - give it 644 file permissions, and user/group = apache -10. update web pages on www.nsnam.org (source is in the www/ module) +13. update web pages on www.nsnam.org (source is in the www/ module) + - clone the source repo (hg clone http://code.nsnam.org/www) + - update index.html - add link to news.html - update getting_started.html - update documents.html - update roadmap on wiki - - build and update Doxygen directory on the server + - commit and push changes + - build and update HTML directory on the server -- ssh www.nsnam.org; sudo tcsh; su nsnam; + -- run ~/bin/update-html + - build and update Doxygen directory on the server -- edit ~/bin/update-doxygen-release file and change RELEASE variable to the right version number -- run ~/bin/update-doxygen-release -11. announce to ns-developers, with summary of release notes +14. Final checks + - download tarball from web, build and run regression tests for as many + targets as you can + - download release from mercurial, build and run regression tests for as + many targets as you can + - test and verify until you're confident the release is solid. +15. announce to ns-developers, with summary of release notes diff --git a/doc/tutorial/Makefile b/doc/tutorial/Makefile index f0b2f4f8f..8dc4415ce 100644 --- a/doc/tutorial/Makefile +++ b/doc/tutorial/Makefile @@ -1,24 +1,18 @@ TEXI2HTML = texi2html TEXI2PDF = texi2dvi --pdf EPSTOPDF = epstopdf -TGIF = tgif DIA = dia CONVERT = convert CSS = --css-include=tutorial.css SPLIT = --split section -DIA_SOURCES = buffer.dia pp.dia dumbbell.dia star.dia sockets-overview.dia -TGIF_SOURCES = packet.obj helpers.obj +DIA_SOURCES = pp.dia dumbbell.dia star.dia DIA_EPS = ${DIA_SOURCES:.dia=.eps} DIA_PNG = ${DIA_SOURCES:.dia=.png} DIA_PDF = ${DIA_SOURCES:.dia=.pdf} -TGIF_EPS = ${TGIF_SOURCES:.obj=.eps} -TGIF_PNG = ${TGIF_SOURCES:.obj=.png} -TGIF_PDF = ${TGIF_SOURCES:.obj=.pdf} - -all: images html split-html pdf +all: html split-html pdf # Note: tgif requires a valid x display to convert from .obj to .png. # If running this makefile on a remote console, the X virtual frame @@ -28,22 +22,18 @@ images: cd figures/; $(DIA) -t png $(DIA_SOURCES) cd figures/; $(DIA) -t eps $(DIA_SOURCES) cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);) - cd figures/; $(TGIF) -print -png $(TGIF_SOURCES) - cd figures/; $(TGIF) -print -eps $(TGIF_SOURCES) - cd figures/; $(foreach FILE,$(TGIF_EPS),$(EPSTOPDF) $(FILE);) -html: images +html: $(TEXI2HTML) ${CSS} tutorial.texi -split-html: images +split-html: $(TEXI2HTML) ${CSS} ${SPLIT} tutorial.texi -pdf: images +pdf: $(TEXI2PDF) tutorial.texi figures-clean: cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF) - cd figures/; rm -rf $(TGIF_EPS); rm -rf $(TGIF_PNG); rm -rf $(TGIF_PDF) -clean: figures-clean +clean: # figures-clean rm -rf tutorial.aux tutorial.cp tutorial.cps tutorial.fn tutorial.ky tutorial.pg tutorial.tp tutorial.vr tutorial.toc tutorial.log tutorial.pdf tutorial.html tutorial/ diff --git a/doc/tutorial/building-topologies.texi b/doc/tutorial/building-topologies.texi new file mode 100644 index 000000000..90db50d6c --- /dev/null +++ b/doc/tutorial/building-topologies.texi @@ -0,0 +1,1254 @@ + +@c ======================================================================== +@c Begin document body here +@c ======================================================================== + +@c ======================================================================== +@c PART: Building Topologies +@c ======================================================================== +@c The below chapters are under the major heading "Building Topologies" +@c This is similar to the Latex \part command +@c +@c ======================================================================== +@c Building Topologies +@c ======================================================================== +@node Building Topologies +@chapter Building Topologies + +@menu +* Building a Bus Network Topology:: +* Building a Wireless Network Topology:: +@end menu + +@c ======================================================================== +@c Building a Bus Network Topology +@c ======================================================================== +@node Building a Bus Network Topology +@section Building a Bus Network Topology + +@cindex topology +@cindex bus network topology +In this section we are going to expand our mastery of @command{ns-3} network +devices and channels to cover an example of a bus network. @command{Ns-3} +provides a net device and channel we call CSMA (Carrier Sense Multiple Access). + +The @command{ns-3} CSMA device models a simple network in the spirit of +Ethernet. A real Ethernet uses CSMA/CD (Carrier Sense Multiple Access with +Collision Detection) scheme with exponentially increasing backoff to contend +for the shared transmission medium. The @command{ns-3} CSMA device and +channel models only a subset of this. + +Just as we have seen point-to-point topology helper objects when constructing +point-to-point topologies, we will see equivalent CSMA topology helpers in +this section. The appearance and operation of these helpers should look +quite familiar to you. + +We provide an example script in our @code{examples} directory. This script +builds on the @code{first.cc} script and adds a CSMA network to the +point-to-point simulation we've already considered. Go ahead and open +@code{examples/second.cc} in your favorite editor. You will have already seen +enough @command{ns-3} code to understand most of what is going on in this +example, but we will go over the entire script and examine some of the output. + +Just as in the @code{first.cc} example (and in all ns-3 examples) the file +begins with an emacs mode line and some GPL boilerplate. + +One thing that can be surprisingly useful is a small bit of ASCII art that +shows a cartoon of the network topology constructed in the example. You will +find a similar ``drawing'' in most of our examples. + +In this case, you can see that we are going to extend our point-to-point +example (the link between the nodes n0 and n1 below) by hanging a bus network +off of the right side. Notice that this is the default network topology +since you can actually vary the number of nodes created on the LAN. If you +set nCsma to one, there will be a total of two nodes on the LAN (CSMA +channel) --- one required node and one ``extra'' node. By default there are +three ``extra'' nodes as seen below: + +@verbatim +// Default Network Topology +// +// 10.1.1.0 +// n0 -------------- n1 n2 n3 n4 +// point-to-point | | | | +// ================ +// LAN 10.1.2.0 +@end verbatim + +The actual code begins by loading module include files just as was done in the +@code{first.cc} example. Then the ns-3 namespace is @code{used} and a logging +component is defined. This is all just as it was in @code{first.cc}, so there +is nothing new yet. + +@verbatim + #include "ns3/core-module.h" + #include "ns3/simulator-module.h" + #include "ns3/node-module.h" + #include "ns3/helper-module.h" + #include "ns3/global-routing-module.h" + + using namespace ns3; + + NS_LOG_COMPONENT_DEFINE ("SecondScriptExample"); +@end verbatim + +The main program begins by enabling the @code{UdpEchoClientApplication} and +@code{UdpEchoServerApplication} logging components at @code{INFO} level so +we can see some output when we run the example. This should be entirely +familiar to you so far. + +@verbatim + int + main (int argc, char *argv[]) + { + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); +@end verbatim + +Next, you will see some familiar code that will allow you to change the number +of devices on the CSMA network via command line argument. We did something +similar when we allowed the number of packets sent to be changed in the section +on command line arguments. + +@verbatim + uint32_t nCsma = 3; + CommandLine cmd; + cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); + cmd.Parse (argc,argv); +@end verbatim + +The next step is to create two nodes that we will connect via the +point-to-point link. The @code{NodeContainer} is used to do this just as was +done in @code{first.cc}. + +@verbatim + NodeContainer p2pNodes; + p2pNodes.Create (2); +@end verbatim + +Next, we delare another @code{NodeContainer} to hold the nodes that will be +part of the bus (CSMA) network. First, we just instantiate the container +object itself. + +@verbatim + NodeContainer csmaNodes; + csmaNodes.Add (p2pNodes.Get (1)); + csmaNodes.Create (nCsma); +@end verbatim + +The next line of code @code{Gets} the first node (as in having an index of one) +from the point-to-point node container and adds it to the container of nodes +that will get CSMA devices. The node in question is going to end up with a +point-to-point device @emph{and} a CSMA device. We then create a number of +``extra'' nodes that compose the remainder of the CSMA network. + +The next bit of code should be quite familiar by now. We instantiate a +@code{PointToPointHelper} and set the associated default attributes so that +we create a five megabit per second transmitter on devices created using the +helper and a two millisecond delay on channels created by the helper. + +@verbatim + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (p2pNodes); +@end verbatim + +We then instantiate a @code{NetDeviceContainer} to keep track of the +point-to-point net devices and we @code{Install} devices on the +point-to-point nodes. + +We mentioned above that you were going to see a helper for CSMA devices and +channels, and the next lines introduce them. The @code{CsmaHelper} works just +like a @code{PointToPointHelper}, but it creates and connects CSMA devices and +channels. + +@verbatim + CsmaHelper csma; + + NetDeviceContainer csmaDevices; + csmaDevices = csma.Install (csmaNodes); +@end verbatim + +Just as we created a @code{NetDeviceContainer} to hold the devices created by +the @code{PointToPointHelper} we create a @code{NetDeviceContainer} to hold +the devices created by our @code{CsmaHelper}. We call the @code{Install} +method of the @code{CsmaHelper} to install the devices into the nodes of the +@code{csmaNodes NodeContainer}. + +We now have our nodes, devices and channels created, but we have no protocol +stacks present. Just as in the @code{first.cc} script, we will use the +@code{InternetStackHelper} to install these stacks. + +@verbatim + InternetStackHelper stack; + stack.Install (p2pNodes.Get (0)); + stack.Install (csmaNodes); +@end verbatim + +Recall that we took one of the nodes from the @code{p2pNodes} container and +added it to the @code{csmaNodes} container. Thus we only need to install +the stacks on the remaining @code{p2pNodes} node, and all of the nodes in the +@code{csmaNodes} container to cover all of the nodes in the simulation. + +Just as in the @code{first.cc} example script, we are going to use the +@code{Ipv4AddressHelper} to assign IP addresses to our device interfaces. +First we use the network 10.1.1.0 to create the two addresses needed for our +two point-to-point devices. + +@verbatim + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); +@end verbatim + +Recall that we save the created interfaces in a container to make it easy to +pull out addressing information later for use in setting up the applications. + +We now need to assign IP addresses to our CSMA device interfaces. The +operation works just as it did for the point-to-point case, except we now +are performing the operation on a container that has a variable number of +CSMA devices --- remember we made the number of CSMA devices changeable by +command line argument. The CSMA devices will be associated with IP addresses +from network number 10.1.2.0 in this case, as seen below. + +@verbatim + address.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4InterfaceContainer csmaInterfaces; + csmaInterfaces = address.Assign (csmaDevices); +@end verbatim + +Now we have a topology built, but we need applications. This section is +going to be fundamentally similar to the applications section of +@code{first.cc} but we are going to instantiate the server on one of the +nodes that has a CSMA node and the client on the node having only a +point-to-point device. + +First, we set up the echo server. We create a @code{UdpEchoServerHelper} and +provide a required attribute value to the constructor which is the server port +number. Recall that this port can be changed later using the +@code{SetAttribute} method if desired, but we require it to be provided to +the constructor. + +@verbatim + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); +@end verbatim + +Recall that the @code{csmaNodes NodeContainer} contains one of the +nodes created for the point-to-point network and @code{nCsma} ``extra'' nodes. +What we want to get at is the last of the ``extra'' nodes. The zeroth entry of +the @code{csmaNodes} container will the the point-to-point node. The easy +way to think of this, then, is if we create one ``extra'' CSMA node, then it +will be be at index one of the @code{csmaNodes} container. By induction, +if we create @code{nCsma} ``extra'' nodes the last one will be at index +@code{nCsma}. You see this exhibited in the @code{Get} of the first line of +code. + +The client application is set up exactly as we did in the @code{first.cc} +example script. Again, we provide required attributes to the +@code{UdpEchoClientHelper} in the constructor (in this case the remote address +and port). We tell the client to send packets to the server we just installed +on the last of the ``extra'' CSMA nodes. We install the client on the +leftmost point-to-point node seen in the topology illustration. + +@verbatim + UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); +@end verbatim + +Since we have actually built an internetwork here, we need some form of +internetwork routing. @command{Ns-3} provides what we call a global route +manager to set up the routing tables on nodes. This route manager has a +global function that runs though the nodes created for the simulation and does +the hard work of setting up routing for you. + +Basically, what happens is that each node behaves as if it were an OSPF router +that communicates instantly and magically with all other routers behind the +scenes. Each node generates link advertisements and communicates them +directly to a global route manager which uses this global information to +construct the routing tables for each node. Setting up this form of routing +is a one-liner: + +@verbatim + GlobalRouteManager::PopulateRoutingTables (); +@end verbatim + +The remainder of the script should be very familiar to you. We just enable +pcap tracing, run the simulation and exit the script. Notice that enabling +pcap tracing using the CSMA helper is done in the same way as for the pcap +tracing with the point-to-point helper. + +@verbatim + PointToPointHelper::EnablePcapAll ("second"); + CsmaHelper::EnablePcapAll ("second"); + + Simulator::Run (); + Simulator::Destroy (); + return 0; + } +@end verbatim + +In order to run this example, you have to copy the @code{second.cc} example +script into the scratch directory and use Waf to build just as you did with +the @code{first.cc} example. If you are in the top-level directory of the +repository you would type, + +@verbatim + cp examples/second.cc scratch/ + ./waf + ./waf --run scratch/second +@end verbatim + +Since we have set up the UDP echo applications to log just as we did in +@code{first.cc}, you will see similar output when you run the script. + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/second + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Sent 1024 bytes to 10.1.2.4 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.2.4 + ~/repos/ns-3-dev > +@end verbatim + +Recall that the first message, @code{Sent 1024 bytes to 10.1.2.4} is the +UDP echo client sending a packet to the server. In this case, the server +is on a different network (10.1.2.0). The second message, @code{Received 1024 +bytes from 10.1.1.1}, is from the UDP echo server, generated when it receives +the echo packet. The final message, @code{Received 1024 bytes from 10.1.2.4} +is from the echo client, indicating that it has received its echo back from +the server. + +If you now go and look in the top level directory, you will find a number of +trace files: + +@verbatim + ~/repos/ns-3-dev > ls *.pcap + second-0-0.pcap second-1-1.pcap second-3-0.pcap + second-1-0.pcap second-2-0.pcap second-4-0.pcap + ~/repos/ns-3-dev > +@end verbatim + +Let's take a moment to look at the naming of these files. They all have the +same form, @code{--.pcap}. For example, the first file +in the listing is @code{second-0-0.pcap} which is the pcap trace from node +zero - device zero. There are no other devices on node zero so this is the +only trace from that node. + +Now look at @code{second-1-0.pcap} and @code{second-1-1.pcap}. The former is +the pcap trace for device zero on node one and the latter is the trace file +for device one on node one. If you refer back to the topology illustrration at +the start of the section, you will see that node one is the node that has +both a point-to-point device and a CSMA device, so we should expect two pcap +traces for that node. + +Now, let's follow the echo packet through the internetwork. First, do a +tcpdump of the trace file for the leftmost point-to-point node --- node zero. + +@verbatim + ~/repos/ns-3-dev > tcpdump -r second-0-0.pcap -nn -tt + reading from file second-0-0.pcap, link-type PPP (PPP) + 2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.007382 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + ~/repos/ns-3-dev > +@end verbatim + +The first line of the dump indicates that the link type is PPP (point-to-point) +which we expect. You then see the echo packet leaving node zero via the +device associated with IP address 10.1.1.1 headed for IP address +10.1.2.4 (the rightmost CSMA node). This packet will move over the +point-to-point link and be received by the point-to-point net device on node +one. Let's take a look: + +@verbatim + ~/repos/ns-3-dev > tcpdump -r second-1-0.pcap -nn -tt + reading from file second-1-0.pcap, link-type PPP (PPP) + 2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.003695 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + ~/repos/ns-3-dev > +@end verbatim + +Here we see that the link type is also PPP as we would expect. You see the +packet from IP address 10.1.1.1 headed toward 10.1.2.4 appear on this +interface. Now, internally to this node, the packet will be forwarded to the +CSMA interface and we should see it pop out the other device headed for its +ultimate destination. Let's then look at second-1-1.pcap and see if its there. + +@verbatim + ~/repos/ns-3-dev > tcpdump -r second-1-1.pcap -nn -tt + reading from file second-1-1.pcap, link-type EN10MB (Ethernet) + 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003687 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.003687 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.003691 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.003691 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.003695 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + ~/repos/ns-3-dev > +@end verbatim + +As you can see, the link type is now ``Ethernet.'' Something new has appeared, +though. The bus network needs @code{ARP}, the Address Resolution Protocol. +The node knows it needs to send the packet to IP address 10.1.2.4, but it +doesn't know the MAC address of the corresponding node. It broadcasts on the +CSMA network (ff:ff:ff:ff:ff:ff) asking for the device that has IP address +10.1.2.4. In this case, the rightmost node replies saying it is at MAC address +00:00:00:00:00:06. This exchange is seen in the following lines, + +@verbatim + 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003687 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 +@end verbatim + +Then node one, device one goes ahead and sends the echo packet to the UDP echo +server at IP address 10.1.2.4. We can now look at the pcap trace for the +echo server, + +@verbatim + ~/repos/ns-3-dev > tcpdump -r second-4-0.pcap -nn -tt + reading from file second-4-0.pcap, link-type EN10MB (Ethernet) + 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003686 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.003690 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.003690 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.003692 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.003692 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + ~/repos/ns-3-dev > +@end verbatim + +Again, you see that the link type is ``Ethernet.'' The first two entries are +the ARP exchange we just explained. The third packet is the echo packet +being delivered to its final destination. + +The echo server turns the packet around and needs to send it back to the echo +client on 10.1.1.1 but it knows that this address is on another network that +it reaches via IP address 10.1.2.1. This is because we initialized global +routing and it has figured all of this out for us. But, the echo server node +doesn't know the MAC address of the first CSMA node, so it has to ARP for it +just like the first CSMA node had to do. We leave it as an exercise for you +to find the entries corresponding to the packet returning back on its way to +the client (we have already dumped the traces and you can find them in those +tcpdumps above. + +Let's take a look at one of the CSMA nodes that wasn't involved in the packet +exchange: + +@verbatim + ~/repos/ns-3-dev > tcpdump -r second-2-0.pcap -nn -tt + reading from file second-2-0.pcap, link-type EN10MB (Ethernet) + 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003691 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + ~/repos/ns-3-dev > +@end verbatim + +You can see that the CSMA channel is a broadcast medium and so all of the +devices see the ARP requests involved in the packet exchange. The remaining +pcap trace will be identical to this one. + +Finally, recall that we added the ability to control the number of CSMA devices +in the simulation by command line argument. You can change this argument in +the same way as when we looked at changing the number of packets echoed in the +@code{first.cc} example. Try setting the number of ``extra'' devices to four: + +@verbatim + ~/repos/ns-3-dev > ./waf --run "scratch/second --nCsma=4" + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Sent 1024 bytes to 10.1.2.5 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.2.5 + ~/repos/ns-3-dev > +@end verbatim + +Notice that the echo server has now been relocated to the last of the CSMA +nodes, which is 10.1.2.5 instead of the default case, 10.1.2.4. You can +increase the number to your hearts content, but remember that you will get a +pcap trace file for every node in the simulation. One thing you can do to +keep from getting all of those pcap traces with nothing but ARP exchanges in +them is to be more specific about which nodes and devices you want to trace. + +Let's take a look at @code{scratch/second.cc} and add that code enabling us +to be more specific. The file we provided used the @code{EnablePcapAll} +methods of the helpers to enable pcap on all devices. We now want to use the +more specific method, @code{EnablePcap}, which takes a node number and device +number as parameters. Go ahead and replace the @code{EnablePcapAll} calls +with the calls below. + +@verbatim + PointToPointHelper::EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0); + CsmaHelper::EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0); +@end verbatim + +We know that we want to create a pcap file with the base name "second" and +we also know that the device of interest in both cases is going to be zero, +so those parameters are not really interesting. In order to get the node +number, you have two choices: first, nodes are numbered in a monotonically +increasing fashion starting from zero in the order in which you created them. +One way to get a node number is to figure this number out ``manually'' by +contemplating the order of node creation. If you take a look at the network +topology illustration at the beginning of the file, we did this for you and +you can see that the last CSMA node is going to be node number +@code{nCsma + 1}. This approach can become annoyingly difficult in larger +simulations. + +An alternate way, which we use here, is to realize that the +@code{NodeContainers} contain pointers to @command{ns-3} @code{Node} Objects. +The @code{Node} Object has a method called @code{GetId} which will return that +node's ID, which is the node number we seek. Let's go take a look at the +Doxygen for the @code{Node} and locate that method, which is further down in +the @command{ns-3} core code than we've seen so far; but sometimes you have to +search diligently for useful things. + +Go to the Doxygen documentation for your release (recall that you can find it +on the project web site). You can get to the @code{Node} documentation by +looking through at the ``Classes'' tab and scrolling down the ``Class List'' +until you find @code{ns3::Node}. Select @code{ns3::Node} and you will be taken +to the documentation for the @code{Node} class. If you now scroll down to the +@code{GetId} method and select it, you will be taken to the detailed +documentation for the method. Using the @code{GetId} method can make +determining node numbers much easier in complex topologies. + +Now that we have got some trace filtering in place, it is reasonable to start +increasing the number of CSMA devices in our simulation. If you build the +new script and run the simulation setting @code{nCsma} to 100, you will see +the following output: + +@verbatim + ~/repos/ns-3-dev > ./waf --run "scratch/second --nCsma=100" + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Sent 1024 bytes to 10.1.2.101 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.2.101 + ~/repos/ns-3-dev > +@end verbatim + +Note that the echo server is now located at 10.1.2.101 which corresponds to +having 100 ``extra'' CSMA nodes with the echo server on the last one. If you +list the pcap files in the top level directory, + +@verbatim + ~/repos/ns-3-dev > ls *.pcap + second-0-0.pcap second-101-0.pcap + ~/repos/ns-3-dev > +@end verbatim + +you will see that we have, in fact, only created two trace files. The trace +file @code{second-0-0.pcap} is the ``leftmost'' point-to-point device which is +the echo packet source. The file @code{second-101-0.pcap} corresponds to the +rightmost CSMA device which is where the echo server resides. + +@c ======================================================================== +@c Building a Wireless Network Topology +@c ======================================================================== +@node Building a Wireless Network Topology +@section Building a Wireless Network Topology + +@cindex topology +@cindex wireless network topology +In this section we are going to further expand our knowledge of @command{ns-3} +network devices and channels to cover an example of a wireless network. +@command{Ns-3} provides a set of 802.11 models that attempt to provide an +accurate MAC-level implementation of the 802.11 specification and a +``not-so-slow'' PHY-level model of the 802.11a specification. + +Just as we have seen both point-to-point and CSMA topology helper objects when +constructing point-to-point topologies, we will see equivalent @code{Wifi} +topology helpers in this section. The appearance and operation of these +helpers should look quite familiar to you. + +We provide an example script in our @code{examples} directory. This script +builds on the @code{second.cc} script and adds a Wifi network. Go ahead and +open @code{examples/third.cc} in your favorite editor. You will have already +seen enough @command{ns-3} code to understand most of what is going on in +this example, but there are a few new things, so we will go over the entire +script and examine some of the output. + +Just as in the @code{second.cc} example (and in all @command{ns-3} examples) +the file begins with an emacs mode line and some GPL boilerplate. + +Take a look at the ASCII art (reproduced below) that shows the default network +topology constructed in the example. You can see that we are going to +further extend our example by hanging a wireless network off of the left side. +Notice that this is a default network topology since you can actually vary the +number of nodes created on the wired and wireless networks. Just as in the +@code{second.cc} script case, if you change @code{nCsma}, it will give you a +number of ``extra'' CSMA nodes. Similarly, you can set @code{nWifi} to +control how many @code{STA} (station) nodes are created in the simulation. +There will always be one @code{AP} (access point) node on the wireless +network. By default there are three ``extra'' CSMA nodes and three wireless +@code{STA} nodes. + +The code begins by loading module include files just as was done in the +@code{second.cc} example. There are a couple of new includes corresponding +to the Wifi module and the mobility module which we will discuss below. + +@verbatim +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/global-routing-module.h" +#include "ns3/wifi-module.h" +#include "ns3/mobility-module.h" +@end verbatim + +The network topology illustration follows: + +@verbatim + // Default Network Topology + // + // Wifi 10.1.3.0 + // AP + // * * * * + // | | | | 10.1.1.0 + // n5 n6 n7 n0 -------------- n1 n2 n3 n4 + // point-to-point | | | | + // ================ + // LAN 10.1.2.0 +@end verbatim + +You can see that we are adding a new network device to the node on the left +side of the point-to-point link that becomes the access point for the wireless +network. A number of wireless STA nodes are created to fill out the new +10.1.3.0 network as shown on the left side of the illustration. + +After the illustration, the @code{ns-3} namespace is @code{used} and a logging +component is defined. This should all be quite familiar by now. + +@verbatim + using namespace ns3; + + NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample"); +@end verbatim + +As has become the norm in this tutorial, the main program begins by enabling +the @code{UdpEchoClientApplication} and @code{UdpEchoServerApplication} +logging components at @code{INFO} level so we can see some output when we run +the simulation. + +@verbatim + int + main (int argc, char *argv[]) + { + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); +@end verbatim + +Next, you will see more familiar code that will allow you to change the number +of devices on the CSMA and Wifi networks via command line argument. + +@verbatim + uint32_t nCsma = 3; + uint32_t nWifi = 3; + CommandLine cmd; + cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); + cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi); + cmd.Parse (argc,argv); +@end verbatim + +Just as in all of the previous examples, the next step is to create two nodes +that we will connect via the point-to-point link. + +@verbatim + NodeContainer p2pNodes; + p2pNodes.Create (2); +@end verbatim + +Next, we see an old friend. We instantiate a @code{PointToPointHelper} and +set the associated default attributes so that we create a five megabit per +second transmitter on devices created using the helper and a two millisecond +delay on channels created by the helper. We then @code{Intall} the devices +on the nodes and the channel between them. + +@verbatim + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (p2pNodes); +@end verbatim + +Next, we delare another @code{NodeContainer} to hold the nodes that will be +part of the bus (CSMA) network. + +@verbatim + NodeContainer csmaNodes; + csmaNodes.Add (p2pNodes.Get (1)); + csmaNodes.Create (nCsma); +@end verbatim + +The next line of code @code{Gets} the first node (as in having an index of one) +from the point-to-point node container and adds it to the container of nodes +that will get CSMA devices. The node in question is going to end up with a +point-to-point device and a CSMA device. We then create a number of ``extra'' +nodes that compose the remainder of the CSMA network. + +We then instantiate a @code{CsmaHelper} and a @code{NetDeviceContainer} to +keep track of the CSMA net devices. Then we @code{Install} CSMA devices on +the selected nodes. + +@verbatim + CsmaHelper csma; + + NetDeviceContainer csmaDevices; + csmaDevices = csma.Install (csmaNodes); +@end verbatim + +Next, we are going to create the nodes that will be part of the Wifi network. +We are going to create a number of ``station'' nodes as specified by the +command line argument, and we are going to use the ``leftmost'' node of the +point-to-point link as the node for the access point. + +@verbatim + NodeContainer wifiStaNodes; + wifiStaNodes.Create (nWifi); + NodeContainer wifiApNode = p2pNodes.Get (0); +@end verbatim + +The next bit of code is going to be quite different from the helper-based +topology generation we've seen so far, so we're going to take it line-by-line +for a while. The next line of code you will see is: + +@verbatim + Ptr channel = CreateObject (); +@end verbatim + +Now, I'm not going to explain at this stage @emph{precisely} what this all +means, but hopefully with a very short digression I can give you enough +information so that this makes sense. + +C++ is an object oriented programming language. @command{Ns-3} extends the +basic C++ object model to implement a number of nifty features. We have seen +the @code{Attribute} system which is one of the major extensions we have +implemented. Another extension is to provide for relatively automatic memory +management. Like many systems, @command{ns-3} creates a base class called +@code{Object} that provides our extensions ``for free'' to other classes that + inherit from our @code{class Object}. + +In the code snippet above, the right hand side of the expression is a +call to a templated C++ function called @code{CreateObject}. The +@emph{template parameter} inside the angle brackets basically tells the +compiler what class it is we want to instantiate. Our system returns a +@emph{smart pointer} to the object of the class that was created and assigns +it to the smart pointer named @code{channel} that is declared on the left +hand side of the assignment. + +The @command{ns-3} smart pointer is also template-based. Here you see that +we declare a smart pointer to a @code{WifiChannel} which is the type of object +that was created in the @code{CreateObject} call. The feature of immediate +interest here is that we are never going to have to delete the underlying C++ +object. It is handled automatically for us. Nice, eh? + +The idea to take away from this discussion is that this line of code creates +an @command{ns-3} @code{Object} that will automatically bring you the benefits +of the @command{ns-3} @code{Attribute} system we've seen previously. The +resulting smart pointer works with the @code{Object} to perform memory +management automatically for you. If you are interested in more details about +low level ns-3 code and exactly what it is doing, you are encouraged to +explore the ns-3 manual and our ``how-to'' documents. + +Now, back to the example. The line of code above has created a wireless +@code{Wifi} channel. This channel model requires that we create and attach +other models that describe various behaviors. This provides an accomplished +user with even more opportunity to change the way the wireless network behaves +without changing the core code. + +The first opportunity we have to change the behavior of the wireless network is +by providing a propagation delay model. Again, I don't want to devolve this +tutorial into a manual on @code{Wifi}, but this model describes how the +electromagnetic signals are going to propagate. We are going to create the +simplest model, the @code{ConstantSpeedPropagationDelayModel} that, by default, +has the signals propagating at a constant speed --- approximately that of the +speed of light in air. + +Recall that we created the @code{WifiChannel} and assigned it to a smart +pointer. One of the features of a smart pointer is that you can use it +just as you would a ``normal'' C++ pointer. The next line of code will +create a @code{ConstantSpeedPropagationDelayModel} using the +@code{CreateObject} template function and pass the resulting smart pointer +to the chanel model as an unnamed parameter of the +@code{WifiChannel SetPropagationDelayModel} method. In English, we create +a model for propagation speed of electromagnetic signals and tell the +wireless channel to use it. + +@verbatim + channel->SetPropagationDelayModel ( + CreateObject ()); +@end verbatim + +The next lines of code use similar low-level @command{ns-3} methods to create +and set a ``propagation loss model'' for the channel. + +@verbatim + Ptr log = + CreateObject (); + + log->SetReferenceModel (CreateObject ()); + + channel->SetPropagationLossModel (log); +@end verbatim + +This snippet is used to tell the channel how it should calculate signal +attenuation of waves flowing in the channel. The details of these calcuations +are beyond the scope of a tutorial. You are encouraged to explore the Doxygen +documentation of classes @code{LogDistancePropagationLossModel} and +@code{FriisPropagationLossModel} if you are interested in the details. As +usual, you will find the documentation in the ``Classes'' tab of the Doxygen +documentation. + +Now we will return to more familiar ground. We next create a @code{WifiHelper} +object and set two default attributes that it will use when creating the actual +devices. + +@verbatim + WifiHelper wifi; + wifi.SetPhy ("ns3::WifiPhy"); + wifi.SetRemoteStationManager ("ns3::ArfWifiManager"); +@end verbatim + +The @code{SetPhy} method tells the helper the type of physical layer class +we want it to instantiate when building @code{Wifi} devices. In this case, +the script is asking for physical layer models based on the YANS 802.11a +model. Again, details are avialable in Doxygen. + +The @code{SetRemoteStationManager} method tells the helper the type of +rate control algorithm to use. Here, it is asking the helper to use the AARF +algorithm --- details are, of course, avialable in Doxygen. + +Just as we can vary attributes describing the physical layer, we can do the +same for the MAC layer. + +@verbatim + Ssid ssid = Ssid ("ns-3-ssid"); + wifi.SetMac ("ns3::NqstaWifiMac", + "Ssid", SsidValue (ssid), + "ActiveProbing", BooleanValue (false)); +@end verbatim + +This code first creates an 802.11 service set identifier (SSID) object that +will be used to set the value of the ``Ssid'' @code{Attribute} of the MAC +layer implementation. The particular kind of MAC layer is specified by +@code{Attribute} as being of the "ns3::NqstaWifiMac" type. This means that +the MAC will use a ``non-QoS station'' (nqsta) state machine. Finally, the +``ActiveProbing'' attribute is set to false. This means that probe requests +will not be sent by MACs created by this helper. + +Again, for the next lines of code we are back on familiar ground. This code +will @code{Install} Wifi net devices on the nodes we have created as STA nodes +and will tie them to the @code{WifiChannel}. Since we created the +@code{channel} manually rather than having the helper do it for us, we have to +pass it into the helper when we call the @code{Install} method. + +@verbatim + NetDeviceContainer staDevices; + staDevices = wifi.Install (wifiStaNodes, channel); +@end verbatim + +We have configured Wifi for all of our STA nodes, and now we need to +configure the AP (access point) node. We begin this process by changing +the default @code{Attributes} of the @code{WifiHelper} to reflect the +requirements of the AP. + +@verbatim + wifi.SetMac ("ns3::NqapWifiMac", + "Ssid", SsidValue (ssid), + "BeaconGeneration", BooleanValue (true), + "BeaconInterval", TimeValue (Seconds (2.5))); +@end verbatim + +In this case, the @code{WifiHelper} is going to create MAC layers of the +``ns3::NqapWifiMac'' (Non-Qos Access Point) type. We set the +``BeaconGeneration'' attribute to true and also set an interval between +beacons of 2.5 seconds. + +The next lines create the single AP and connect it to the channel in a +familiar way. + +@verbatim + NetDeviceContainer apDevices; + apDevices = wifi.Install (wifiApNode, channel); +@end verbatim + +Now, we are going to add mobility models. We want the STA nodes to be mobile, +wandering around inside a bounding box, and we want to make the AP node +stationary. We use the @code{MobilityHelper} to make this easy for us. +First, we instantiate a @code{MobilityHelper} obejct and set some attributes +controlling the ``position allocator'' functionality. + +@verbatim + MobilityHelper mobility; + + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (0.0), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (5.0), + "DeltaY", DoubleValue (10.0), + "GridWidth", UintegerValue (3), + "LayoutType", StringValue ("RowFirst")); +@end verbatim + +This code tells the mobility helper to use a two-dimensional grid to initially +place the STA nodes. Feel free to explore the Doxygen for class +@code{ns3::GridPositionAllocator} to see exactly what is being done. + +We have aranged our nodes on an initial grid, but now we need to tell them +how to move. We choose the @code{RandomWalk2dMobilityModel} which has the +nodes move in a random direction at a random speed around inside a bounding +box. + +@verbatim + mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", + "Bounds", RectangleValue (Rectangle (-50, 50, -50, 50))); +@end verbatim + +We now tell the @code{MobilityHelper} to install the mobility models on the +STA nodes. + +@verbatim + mobility.Install (wifiStaNodes); +@end verbatim + +We want the access point to remain in a fixed position during the simulation. +We accomplish this by setting the mobility model for this node to be the +@code{ns3::StaticMobilityModel}: + +@verbatim + mobility.SetMobilityModel ("ns3::StaticMobilityModel"); + mobility.Install (wifiApNode); +@end verbatim + +We now have our nodes, devices and channels created, and mobility models +chosen for the Wifi nodes, but we have no protocol stacks present. Just as +we have done previously many times, we will use the @code{InternetStackHelper} +to install these stacks. + +@verbatim + InternetStackHelper stack; + stack.Install (csmaNodes); + stack.Install (wifiApNode); + stack.Install (wifiStaNodes); +@end verbatim + +Just as in the @code{second.cc} example script, we are going to use the +@code{Ipv4AddressHelper} to assign IP addresses to our device interfaces. +First we use the network 10.1.1.0 to create the two addresses needed for our +two point-to-point devices. Then we use network 10.1.2.0 to assign addresses +the the CSMA network and then we assign addresses from network 10.1.3.0 to +both the STA devices and the AP on the wireless network. + +@verbatim + Ipv4AddressHelper address; + + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + + address.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4InterfaceContainer csmaInterfaces; + csmaInterfaces = address.Assign (csmaDevices); + + address.SetBase ("10.1.3.0", "255.255.255.0"); + address.Assign (staDevices); + address.Assign (apDevices); +@end verbatim + +We put the echo server on the ``rightmost'' node in the illustration at the +start of the file. We have done this before. + +@verbatim + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); +@end verbatim + +And we put the echo client on the last STA node we created, pointing it to +the server on the CSMA network. We have also seen similar operations before. + +@verbatim + UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = + echoClient.Install (wifiStaNodes.Get (nWifi - 1)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); +@end verbatim + +Since we have built an internetwork here, we need enable internetwork routing +just as we did in the @code{second.cc} example script. + +@verbatim + GlobalRouteManager::PopulateRoutingTables (); +@end verbatim + +One thing that can surprise some users is the fact that the simulation we just +created will never ``naturally'' stop. This is because we asked the wireless +access point to generate beacons. It will generate beacons forever, so we must +tell the simulator to stop even though it may have beacon generation events +scheduled. The following line of code tells the simulator to stop so that +we don't simulate beacons forever and enter what is essentially an endless +loop. + +@verbatim + Simulator::Stop (Seconds (10.0)); +@end verbatim + +We use the same trick as in the @code{second.cc} script to only generate +pcap traces from the nodes we find interesting. Note that we use the same +``formula'' to get pcap tracing enabled on Wifi devices as we did on the +CSMA and point-to-point devices. + +@verbatim + WifiHelper::EnablePcap ("third", + wifiStaNodes.Get (nWifi - 1)->GetId (), 0); + CsmaHelper::EnablePcap ("third", + csmaNodes.Get (nCsma)->GetId (), 0); +@end verbatim + +Finally, we actually run the simulation, clean up and then exit the program. + +@verbatim + Simulator::Run (); + Simulator::Destroy (); + return 0; + } +@end verbatim + +In order to run this example, you have to copy the @code{third.cc} example +script into the scratch directory and use Waf to build just as you did with +the @code{second.cc} example. If you are in the top-level directory of the +repository you would type, + +@verbatim + cp examples/third.cc scratch/ + ./waf + ./waf --run scratch/third +@end verbatim + +Since we have set up the UDP echo applications just as we did in the +@code{second.cc} script, you will see similar output. + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/third + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Sent 1024 bytes to 10.1.2.4 + Received 1024 bytes from 10.1.3.3 + Received 1024 bytes from 10.1.2.4 + ~/repos/ns-3-dev > +@end verbatim + +Recall that the first message, @code{Sent 1024 bytes to 10.1.2.4} is the +UDP echo client sending a packet to the server. In this case, the client +is on the wireless network (10.1.3.0). The second message, +@code{Received 1024 bytes from 10.1.3.3}, is from the UDP echo server, +generated when it receives the echo packet. The final message, +@code{Received 1024 bytes from 10.1.2.4} is from the echo client, indicating +that it has received its echo back from the server. + +If you now go and look in the top level directory, you will find two trace +files: + +@verbatim + ~/repos/ns-3-dev > ls *.pcap + third-4-0.pcap third-7-0.pcap + ~/repos/ns-3-dev > +@end verbatim + +The file ``third-4-0.pcap'' corresponds to the pcap trace for node four - +device zero. This is the CSMA network node that acted as the echo server. +Take a look at the tcpdump for this device: + +@verbatim + ~/repos/ns-3-dev > tcpdump -r third-4-0.pcap -nn -tt + reading from file third-4-0.pcap, link-type EN10MB (Ethernet) + 2.005855 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.005855 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.005859 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.005859 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.005861 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.005861 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 + ~/repos/ns-3-dev > +@end verbatim + +This should be familiar and easily understood. If you've forgotten, go back +and look at the discussion in @code{second.cc}. This is the same sequence. + +Now, take a look at the other trace file, ``third-7-0.pcap.'' This is the +trace file for the wireless STA node that acts as the echo client. + +@verbatim + ~/repos/ns-3-dev > tcpdump -r third-7-0.pcap -nn -tt + reading from file third-7-0.pcap, link-type IEEE802_11 (802.11) + 0.000146 Beacon (ns-3-ssid) ... + H: 0 + 0.000180 Assoc Request (ns-3-ssid) ... + 0.000336 Acknowledgment RA:00:00:00:00:00:07 + 0.000454 Assoc Response AID(0) :: Succesful + 0.000514 Acknowledgment RA:00:00:00:00:00:0a + 0.000746 Assoc Request (ns-3-ssid) ... + 0.000902 Acknowledgment RA:00:00:00:00:00:09 + 0.001020 Assoc Response AID(0) :: Succesful + 0.001036 Acknowledgment RA:00:00:00:00:00:0a + 0.001219 Assoc Request (ns-3-ssid) ... + 0.001279 Acknowledgment RA:00:00:00:00:00:08 + 0.001478 Assoc Response AID(0) :: Succesful + 0.001538 Acknowledgment RA:00:00:00:00:00:0a + 2.000000 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 + 2.000172 Acknowledgment RA:00:00:00:00:00:09 + 2.000318 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 + 2.000581 arp reply 10.1.3.4 is-at 00:00:00:00:00:0a + 2.000597 Acknowledgment RA:00:00:00:00:00:0a + 2.000693 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.002229 Acknowledgment RA:00:00:00:00:00:09 + 2.009663 arp who-has 10.1.3.3 (ff:ff:ff:ff:ff:ff) tell 10.1.3.4 + 2.009697 arp reply 10.1.3.3 is-at 00:00:00:00:00:09 + 2.009869 Acknowledgment RA:00:00:00:00:00:09 + 2.011487 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 + 2.011503 Acknowledgment RA:00:00:00:00:00:0a + 2.500112 Beacon[|802.11] + 5.000112 Beacon[|802.11] + 7.500112 Beacon[|802.11] + ~/repos/ns-3-dev > +@end verbatim + +You can see that the link type is now 802.11 as you would expect. We leave +it as an exercise to parse the dump and trace packets across the internetwork. + +Now, we spent a lot of time setting up mobility models for the wireless network +and so it would be a shame to finish up without even showing that the STA +nodes are actually moving around. Let's do this by hooking into the +@code{MobilityModel} course change trace source. This is usually considered +a fairly advanced topic, but let's just go for it. + +As mentioned in the Tweaking Ns-3 section, the @command{ns-3} tracing system +is divided into trace sources and trace sinks, and we provide functions to +connect the two. We will use the mobility model predefined course change +trace source to originate the trace events. We will need to write a trace +sink to connect to that source that will display some pretty information for +us. Despite its reputation as being difficult, it's really quite simple. +Just before the main program of the @code{scratch/third.cc} script, add the +following function: + +@verbatim + void + CourseChange (std::string context, Ptr model) + { + Vector position = model->GetPosition (); + NS_LOG_UNCOND (context << + " x = " << position.x << ", y = " << position.y); + } +@end verbatim + +This code just pulls the position information from the mobility model and +unconditionally logs the x and y position of the node. We are +going to arrange for this function to be called every time the wireless +node with the echo client changes its position. We do this using the +@code{Config::Connect} function. Add the following lines of code to the +script just before the @code{Simulator::Run} call. + +@verbatim + std::ostringstream oss; + oss << + "/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () << + "/$ns3::MobilityModel/CourseChange"; + + Config::Connect (oss.str (), MakeCallback (&CourseChange)); +@end verbatim + +What we do here is to create a string containing the tracing namespace path +of the event to which we want to connect. First, we have to figure out which +node it is we want using the @code{GetId} method as described earlier. In the +case of the default number of CSMA and wireless nodes, this turns out to be +node seven and the tracing namespace path to the mobility model would look +like, + +@verbatim + /NodeList/7/$ns3::MobilityModel/CourseChange +@end verbatim + +Based on the discussion in the tracing section, you can easily infer that +this trace path references the seventh node in the NodeList. It specifies +what is called an aggregated object of type @code{ns3::MobilityModel}. The +dollar sign prefix implies that the MobilityModel is aggregated to node seven. +The last component of the path means that we are hooking into the +``CourseChange'' event of that model. + +We make a connection between the trace source in node seven with our trace +sink by calling @code{Config::Connect} and passing this namespace path. Once +this is done, every course change event on node seven will be hooked into our +trace sink, which will in turn print out the new position. + +If you now run the simulation, you will see the course changes displayed as +they happen. + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/third + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + /NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.1304, y = 0.493761 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.70417, y = 1.39837 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.94799, y = 2.05274 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.82597, y = 1.57404 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.3003, y = 0.723347 + Sent 1024 bytes to 10.1.2.4 + Received 1024 bytes from 10.1.3.3 + Received 1024 bytes from 10.1.2.4 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.74083, y = 1.62109 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.00146, y = 0.655647 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.98731, y = 0.823279 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.50206, y = 1.69766 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.68108, y = 2.26862 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.25992, y = 1.45317 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.55655, y = 0.742346 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.21992, y = 1.68398 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.81273, y = 0.878638 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.83171, y = 1.07256 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.60027, y = 0.0997156 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.45367, y = 0.620978 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.68484, y = 1.26043 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.53659, y = 0.736479 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.51876, y = 0.548502 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.89778, y = 1.47389 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.98984, y = 1.893 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.91524, y = 1.51402 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.98761, y = 1.14054 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.16617, y = 0.570239 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.02954, y = 1.56086 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.09551, y = 2.55868 + ~/repos/ns-3-dev > +@end verbatim + +If you are feeling brave, there is a list of all trace sources in the +@uref{http://www.nsnam.org/doxygen-release/index.html,,ns-3 Doxygen} +which you can find in the ``Modules'' tab. +Under the ``core'' section, you will find a link to ``The list of all trace +sources.'' You may find it interesting to try and hook some of these +traces yourself. Additionally in the ``Modules'' documentation, there is +a link to ``The list of all attributes.'' You can set the default value of +any of these attributes via the command line as we have previously discussed. + +We have just scratched the surface of @command{ns-3} in this tutorial, but we +hope we have covered enough to get you started doing useful work. + +-- The @command{ns-3} development team. diff --git a/doc/tutorial/conceptual-overview.texi b/doc/tutorial/conceptual-overview.texi new file mode 100644 index 000000000..873eab9b5 --- /dev/null +++ b/doc/tutorial/conceptual-overview.texi @@ -0,0 +1,815 @@ + +@c ======================================================================== +@c Begin document body here +@c ======================================================================== + +@c ======================================================================== +@c Conceptual Overview +@c ======================================================================== +@node Conceptual Overview +@chapter Conceptual Overview + +@menu +* Key Abstractions:: +* A First ns-3 Script:: +@end menu + +The first thing we need to do before actually starting to look at or write +@command{ns-3} code is to explain a few core concepts and abstractions in the +system. Much of this may appear transparently obvious to some, but we +recommend taking the time to read through this section just to ensure you +are starting on a firm foundation. + +@node Key Abstractions +@section Key Abstractions + +In this section, we'll review some terms that are commonly used in +networking, but have a specific meaning in @command{ns-3}. + +@subsection Node +@cindex Node +In Internet jargon, a computing device that connects to a network is called +a @emph{host} or sometimes an @emph{end system}. Because @command{ns-3} is a +@emph{network} simulator, not specifically an @emph{Internet} simulator, we +intentionally do not use the term host since it is closely associated with +the Internet and its protocols. Instead, we use a more generic term also +used by other simulators that originates in Graph Theory --- the @emph{node}. + +@cindex class Node +In @command{ns-3} the basic computing device abstraction is called the +node. This abstraction is represented in C++ by the class @code{Node}. The +@code{Node} class provides methods for managing the representations of +computing devices in simulations. + +You should think of a @code{Node} as a computer to which you will add +functionality. One adds things like applications, protocol stacks and +peripheral cards with their associated drivers to enable the computer to do +useful work. We use the same basic model in @command{ns-3}. + +@subsection Application +@cindex Application +Typically, computer software is divided into two broad classes. @emph{System +Software} organizes various computer resources such as memory, processor +cycles, disk, network, etc., according to some computing model. System +software usually does not use those resources to complete tasks that directly +benefit a user. A user would typically run an @emph{application} that acquires +and uses the resources controlled by the system software to accomplish some +goal. + +@cindex system call +Often, the line of separation between system and application software is made +at the privilege level change that happens in operating system traps. +In @command{ns-3} there is no real concept of operating system and especially +no concept of privilege levels or system calls. We do, however, have the +idea of an application. Just as software applications run on computers to +perform tasks in the ``real world,'' @command{ns-3} applications run on +@command{ns-3} @code{Nodes} to drive simulations in the simulated world. + +@cindex class Application +In @command{ns-3} the basic abstraction for a user program that generates some +activity to be simulated is the application. This abstraction is represented +in C++ by the class @code{Application}. The @code{Application} class provides +methods for managing the representations of our version of user-level +applications in simulations. Developers are expected to specialize the +@code{Application} class in the object-oriented programming sense to create new +applications. In this tutorial, we will use specializations of class +@code{Application} called @code{UdpEchoClientApplication} and +@code{UdpEchoServerApplication}. As you might expect, these applications +compose a client/server application set used to generate and echo simulated +network packets + +@subsection Channel +@cindex Channel + +In the real world, one can connect a computer to a network. Often the media +over which data flows in these netowrks are called @emph{channels}. When +you connect your Ethernet cable to the plug in the wall, you are connecting +your computer to an Ethernet communication channel. In the simulated world +of @command{ns-3}, one connects a @code{Node} to an object representing a +communication channel. Here the basic communication subnetwork abstraction +is called the channel and is represented in C++ by the class @code{Channel}. + +The @code{Channel} class provides methods for managing communication +subnetwork objects and connecting nodes to them. @code{Channels} may also be +specialized by developers in the object oriented programming sense. A +@code{Channel} specialization may model something as simple as a wire. The +specialized @code{Channel} can also model things as complicated as a large +Ethernet switch, or three-dimensional space full of obstructions in the case +of wireless networks. + +We will use specialized versions of the @code{Channel} called +@code{CsmaChannel}, @code{PointToPointChannel} and @code{WifiChannel} in this +tutorial. The @code{CsmaChannel}, for example, models a version of a +communication subnetwork that implements a @emph{carrier sense multiple +access} communication medium. This gives us Ethernet-like functionality. + +@subsection Net Device +@cindex NetDevice +@cindex Ethernet +It used to be the case that if you wanted to connect a computers to a network, +you had to buy a specific kind of network cable and a hardware device called +(in PC terminology) a @emph{peripheral card} that needed to be installed in +your computer. If the peripheral card implemented some networking function, +theys were called Network Interface Cards, or @emph{NICs}. Today most +computers come with the network interface hardware built in and users don't +see these building blocks. + +A NIC will not work without a software driver to control the hardware. In +Unix (or Linux), a piece of peripheral hardware is classified as a +@emph{device}. Devices are controlled using @emph{device drivers}, and network +devices (NICs) are controlled using @emph{network device drivers} +collectively known as @emph{net devices}. In Unix and Linux you refer +to these net devices by names such as @emph{eth0}. + +In @command{ns-3} the @emph{net device} abstraction covers both the software +driver and the simulated hardware. A net device is ``installed'' in a +@code{Node} in order to enable the @code{Node} to communicate with other +@code{Nodes} in the simulation via @code{Channels}. Just as in a real +computer, a @code{Node} may be connected to more than one @code{Channel} via +multiple @code{NetDevices}. + +The net device abstraction is represented in C++ by the class @code{NetDevice}. +The @code{NetDevice} class provides methods for managing connections to +@code{Node} and @code{Channel} objects; and may be specialized by developers +in the object-oriented programming sense. We will use the several specialized +versions of the @code{NetDevice} called @code{CsmaNetDevice}, +@code{PointToPointNetDevice}, and @code{WifiNetDevice} in this tutorial. +Just as an Ethernet NIC is designed to work with an Ethernet network, the +@code{CsmaNetDevice} is designed to work with a @code{CsmaChannel}; the +@code{PointToPointNetDevice} is designed to work with a +@code{PointToPointChannel} and a @code{WifiNetNevice} is designed to work with +a @code{WifiChannel}. + +@subsection Topology Helpers +@cindex helper +@cindex topology +@cindex topology helper +In a real network, you will find host computers with added (or built-in) +NICs. In @command{ns-3} we would say that you will find @code{Nodes} with +attached @code{NetDevices}. In a large simulated network you will need to +arrange many connections between @code{Nodes}, @code{NetDevices} and +@code{Channels}. + +Since connecting @code{NetDevices} to @code{Nodes}, @code{NetDevices} +to @code{Channels}, assigning IP addresses, etc., are such common tasks +in @command{ns-3}, we provide what we call @emph{topology helpers} to make +this as easy as possible. For example, it may take many distinct +@command{ns-3} core operations to create a NetDevice, add a MAC address, +install that net device on a @code{Node}, configure the node's protocol stack, +and then connect the @code{NetDevice} to a @code{Channel}. Even more +operations would be required to connect multiple devices onto multipoint +channels and then to connect individual networks together into internetworks. +We provide topology helper objects that combine those many distinct operations +into an easy to use model for your convenience. + +@c ======================================================================== +@c A First ns-3 script +@c ======================================================================== +@node A First ns-3 Script +@section A First ns-3 Script +@cindex first script +If you downloaded the system as was suggested above, you will have a release +of @command{ns-3} in a directory called @code{repos} under your home +directory. Change into that release directory, and you should find a +directory structure something like the following: + +@verbatim + AUTHORS examples/ README samples/ utils/ waf.bat* + build/ LICENSE regression/ scratch/ VERSION wscript + doc/ ns3/ RELEASE_NOTES src/ waf* +@end verbatim + +@cindex first.cc +Change into the examples directory. You should see a file named +@code{first.cc} located there. This is a script that will create a simple +point-to-point link between two nodes and echo a single packet between the +nodes. Let's take a look at that script line by line, so go ahead and open +@code{first.cc} in your favorite editor. + +@subsection Boilerplate +The first line in the file is an emacs mode line. This tells emacs about the +formatting conventions (coding style) we use in our source code. + +@verbatim + /* -*- Mode:C++; c-file-style:''gnu''; indent-tabs-mode:nil; -*- */ +@end verbatim + +This is always a somewhat controversial subject, so we might as well get it +out of the way immediately. The @code{ns-3} project, like most large +projects, has adopted a coding style to which all contributed code must +adhere. If you want to contribute your code to the project, you will +eventually have to conform to the @command{ns-3} coding standard as described +in the file @code{doc/codingstd.txt} or shown on the project web page +@uref{http://www.nsnam.org/codingstyle.html,,here}. + +We recommend that you, well, just get used to the look and feel of @code{ns-3} +code and adopt this standard whenever you are working with our code. All of +the development team and contributors have done so with various amounts of +grumbling. The emacs mode line above makes it easier to get the formatting +correct if you use the emacs editor. + +The @command{ns-3} simulator is licensed using the GNU General Public +License. You will see the appropriate GNU legalese at the head of every file +in the @command{ns-3} distribution. Often you will see a copyright notice for +one of the institutions involved in the @code{ns-3} project above the GPL +text and an author listed below. + +@verbatim + /* + * 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 + */ +@end verbatim + +@subsection Module Includes +The code proper starts with a number of include statements. + +@verbatim + #include "ns3/core-module.h" + #include "ns3/simulator-module.h" + #include "ns3/node-module.h" + #include "ns3/helper-module.h" +@end verbatim + +To help our high-level script users deal with the large number of include +files present in the system, we group includes according to relatively large +modules. We provide a single include file that will recursively load all of +the include files used in each module. Rather than having to look up exactly +what header you need, and possibly have to get a number of dependencies right, +we give you the ability to load a group of files at a large granularity. This +is not the most efficient approach but it certainly makes writing scripts much +easier. + +Each of the @command{ns-3} include files is placed in a directory called +@code{ns3} (under the build directory) during the build process to help avoid +include file name collisions. The @code{ns3/core-module.h} file corresponds +to the ns-3 module you will find in the directory @code{src/core} in your +downloaded release distribution. If you list this directory you will find a +large number of header files. When you do a build, Waf will place public +header files in an @code{ns3} directory under the appropriate +@code{build/debug} or @code{build/optimized} directory depending on your +configuration. Waf will also automatically generate a module include file to +load all of the public header files. + +Since you are, of course, following this tutorial religiously, you will +already have done a + +@verbatim + ./waf -d debug configure +@end verbatim + +in order to configure the project to perform debug builds. You will also have +done a + +@verbatim + ./waf +@end verbatim + +to build the project. So now if you look in the directory +@code{build/debug/ns-3} you will find the four module include files shown +above. You can take a look at the contents of these files and find that they +do include all of the public include files in their respective modules. + +@subsection Ns3 Namespace +The next line in the @code{first.cc} script is a namespace declaration. + +@verbatim + using namespace ns3; +@end verbatim + +The @command{ns-3} project is implemented in a C++ namespace called +@code{ns3}. This groups all @command{ns-3}-related declarations in a scope +outside the global namespace, which we hope will help with integration with +other code. The C++ @code{using} statement introduces the @code{ns-3} +namespace into the current (global) declarative region. This is a fancy way +of saying that after this declaration, you will not have to type @code{ns3::} +scope resolution operator before all of the @code{ns-3} code in order to use +it. If you are unfamiliar with namespaces, please consult almost any C++ +tutorial and compare the @code{ns3} namespace and usage here with instances of +the @code{std} namespace and the @code{using namespace std;} statements you +will often find in discussions of @code{cout} and streams. + +@subsection Logging +The next line of the script is the following, + +@verbatim + NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); +@end verbatim + +We will use this statement as a convenient place to talk about our Doxygen +documentation system. If you look at the project web site, +@uref{http://www.nsnam.org,,ns-3 project}, you will find a link to ``APIs +(Doxygen)'' in the navigation bar. If you select this link, you will be +taken to our documentation page. + +Along the left side, you will find a graphical representation of the structure +of the documentation. A good place to start is the @code{NS-3 Modules} +``book.'' If you expand @code{Modules} you will see a list of @command{ns-3} +module documentation. The concept of module here ties directly into the +module include files discussed above. It turns out that the @command{ns-3} +logging subsystem is part of the @code{core} module, so go ahead and expand +that documentation node. Now, expand the @code{Debugging} book and then +select the @code{Logging} page. + +You should now be looking at the Doxygen documentation for the Logging module. +In the list of @code{#define}s at the top of the page you will see the entry +for @code{NS_LOG_COMPONENT_DEFINE}. Before jumping in, it would probably be +good to look for the ``Detailed Description'' of the logging module to get a +feel for the overall operation. You can either scroll down or select the +``More...'' link under the collaboration diagram to do this. + +Once you have a general idea of what is going on, go ahead and take a look at +the specific @code{NS_LOG_COMPONENT_DEFINE} documentation. I won't duplicate +the documentation here, but to summarize, this line declares a logging +component called @code{FirstScriptExample} that allows you to enable and +disable console message logging by reference to the name. + +@subsection Main Function +The next lines of the script you will find are, + +@verbatim + int + main (int argc, char *argv[]) + { +@end verbatim + +This is just the declaration of the main function of your program (script). +Just as in any C++ program, you need to define a main function that will be +the first function run. There is nothing at all special here. Your +@command{ns-3} script is just a C++ program. + +The next two lines of the script are used to enable two logging components that +are built into the Echo Client and Echo Server applications: + +@verbatim + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); +@end verbatim + +If you have read over the Logging component documentation you will have seen +that there are a number of levels of logging verbosity/detail that you can +enable on each component. These two lines of code enable debug logging at the +INFO level for echo clients and servers. This will result in the application +printing out messages as packets are sent and received during the simulation. + +Now we will get directly to the business of creating a topology and running +a simulation. We use the topology helper objects to make this job as +easy as possible. + +@subsection Topology Helpers +@subsubsection NodeContainer +The next two lines of code in our script will actually create the +@command{ns-3} @code{Node} objects that will represent the computers in the +simulation. + +@verbatim + NodeContainer nodes; + nodes.Create (2); +@end verbatim + +Let's find the documentation for the @code{NodeContainer} class before we +continue. Another way to get into the documentation for a given class is via +the @code{Classes} tab in the Doxygen pages. If you still have the Doxygen +handy, just scroll up to the top of the page and select the @code{Classes} +tab. You should see a new set of tabs appear, one of which is +@code{Class List}. Under that tab you will see a list of all of the +@command{ns-3} classes. Scroll down, looking for @code{ns3::NodeContainer}. +When you find the class, go ahead and select it to go to the documentation for +the class. + +You may recall that one of our key abstractions is the @code{Node}. This +represents a computer to which we are going to add things like protocol stacks, +applications and peripheral cards. The @code{NodeContainer} topology helper +provides a convenient way to create, manage and access any @code{Node} objects +that we create in order to run a simulation. The first line above just +declares a NodeContainer which we call @code{nodes}. The second line calls the +@code{Create} method on the @code{nodes} object and asks the container to +create two nodes. As described in the Doxygen, the container calls down into +the @command{ns-3} system proper to create two @code{Node} objects and stores +pointers to those objects internally. + +The nodes as they stand in the script do nothing. The next step in +constructing a topology is to connect our nodes together into a network. +The simplest form of network we support is a single point-to-point link +between two nodes. We'll construct one of those links here. + +@subsubsection PointToPointHelper +We are constructing a point to point link, and, in a pattern which will become +quite familiar to you, we use a topology helper object to do the low-level +work required to put the link together. Recall that two of our key +abstractions are the @code{NetDevice} and the @code{Channel}. In the real +world, these terms correspond roughly to peripheral cards and network cables. +Typically these two things are intimately tied together and one cannot expect +to interchange, for example, Ethernet devices and wireless channels. Our +Topology Helpers follow this intimate coupling and therefore you will use a +single @code{PointToPointHelper} to configure and connect @command{ns-3} +@code{PointToPointNetDevice} and @code{PointToPointChannel} objects in this +script. + +The next three lines in the script are, + +@verbatim + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); +@end verbatim + +The first line + +@verbatim + PointToPointHelper pointToPoint; +@end verbatim + +instantiates a @code{PointToPointHelper} object on the stack. From a +high-level perspective the next line, + +@verbatim + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); +@end verbatim + +tells the @code{PointToPointHelper} object to use the value ``5mbps'' +(five megabits per second) as the ``DataRate'' when it creates a +@code{PointToPointNetDevice} object. + +From a more detailed perspective, the string ``DataRate'' corresponds +to what we call an @code{Attribute} of the @code{PointToPointNetDevice}. +If you look at the Doxygen for class @code{ns3::PointToPointNetDevice} and +find the documentation for the @code{GetTypeId} method, you will find a list +of @code{Attributes} defined for the device. Among these is the ``DataRate'' +attribute. Most user-visible @command{ns-3} objects have similar lists of +attributes. We use this mechanism to easily configure simulations without +recompiling as you will see in a following section. + +Similar to the ``DataRate'' on the @code{PointToPointNetDevice} you will find a +``Delay'' attribute associated with the @code{PointToPointChannel}. The +final line, + +@verbatim + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); +@end verbatim + +tells the @code{PointToPointHelper} to use the value ``2ms'' (two milliseconds) +as the value of the transmission delay of every point to point channel it +subsequently creates. + +@subsubsection NetDeviceContainer +At this point in the script, we have a @code{NodeContainer} that contains +two nodes. We have a @code{PointToPointHelper} that is primed and ready to +make @code{PointToPointNetDevices} and wire @code{PointToPointChannel} objects +between them. Just as we used the @code{NodeContainer} topology helper object +to create the @code{Nodes} for our simulation, we will ask the +@code{PointToPointHelper} to do the work involved in creating, configuring and +installing our devices for us. We will need to have a list of all of the +NetDevice objects that are created, so we use a NetDeviceContainer to hold +them just as we used a NodeContainer to hold the nodes we created. The +following two lines of code, + +@verbatim + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); +@end verbatim + +will finish configuring the devices and channel. The first line declares the +device container mentioned above and the second does the heavy lifting. The +@code{Install} method of the @code{PointToPointHelper} takes a +@code{NodeContainer} as a parameter. Internally, a @code{NetDeviceContainer} +is created. For each node in the @code{NodeContainer} (there must be exactly +two for a point-to-point link) a @code{PointToPointNetDevice} is created and +saved in the device container. A @code{PointToPointChannel} is created and +the two @code{PointToPointNetDevices} are attached. When objects are created +by the @code{PointToPointHelper}, the attributes previously set in the helper +are used to initialize the corresponding attributes in the created objects. + +After executing the the @code{pointToPoint.Install (nodes)} call we will have +two nodes, each with an installed point-to-point net device and a +point-to-point channel between them. Both devices will be configured to +transmit data at five megabits per second over the channel which has a two +millisecond transmission delay. + +@subsubsection InternetStackHelper +We now have nodes and devices configured, but we don't have any protocol stacks +installed on our nodes. The next two lines of code will take care of that. + +@verbatim + InternetStackHelper stack; + stack.Install (nodes); +@end verbatim + +The @code{InternetStackHelper} is a topology helper that is to internet stacks +what the @code{PointToPointHelper} is to point-to-point net devices. The +@code{Install} method takes a @code{NodeContainer} as a parameter. When it is +executed, it will install an Internet Stack (TCP, UDP, IP, etc.) on each of +the nodes in the node container. + +@subsubsection Ipv4AddressHelper +Next we need to associate the devices on our nodes with IP addresses. We +provide a topology helper to manage the allocation of IP addresses. The only +user-visible API is to set the base IP address and network mask to use when +performing the actual address allocation (which is done at a lower level +inside the helper). + +The next two lines of code in our example script, @code{first.cc}, + +@verbatim + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); +@end verbatim + +declare an address helper object and tell it that it should begin allocating IP +addresses from the network 10.1.1.0 using the mask 255.255.255.0 to define +the allocatable bits. By default the addresses allocated will start at one +and increase monotonically, so the first address allocated from this base will +be 10.1.1.1, followed by 10.1.1.2, etc. The low level @command{ns-3} system +actually remembers all of the IP addresses allocated and will generate a +fatal error if you accidentally cause the same address to be generated twice +(which is a very hard to debug error, by the way). + +The next line of code, + +@verbatim + Ipv4InterfaceContainer interfaces = address.Assign (devices); +@end verbatim + +performs the actual address assignment. In @command{ns-3} we make the +association between an IP address and a device using an @code{Ipv4Interface} +object. Just as we sometimes need a list of net devices created by a helper +for future reference we sometimes need a list of @code{Ipv4Interface} objects. +The @code{Ipv4InterfaceContainer} provides this functionality. + +Now we have a point-to-point network built, with stacks installed and IP +addresses assigned. What we need at this point are applications to generate +traffic. + +@subsection Applications +Another one of the core abstractions of the ns-3 system is the +@code{Application}. In this script we use two specializations of the core +@command{ns-3} class @code{Application} called @code{UdpEchoServerApplication} +and @code{UdpEchoClientApplication}. Just as we have in our previous +explanations, we use helper objects to help configure and manage the +underlying objects. Here, we use @code{UdpEchoServerHelper} and +@code{UdpEchoClientHelper} objects to make our lives easier. + +@subsubsection UdpEchoServerHelper +The following lines of code in our example script, @code{first.cc}, are used +to set up a UDP echo server application on one of the nodes we have previously +created. + +@verbatim + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (nodes.Get (1)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); +@end verbatim + +The first line of code in the above snippet declares the +@code{UdpEchoServerHelper}. As usual, this isn't the application itself, it +is an object used to help us create the actual applications. One of our +conventions is to place required attributes in the helper constructor. In this +case, the helper can't do anything useful unless it is provided with a port +number that the client also knows about. Rather than just picking one and +hoping it all works out, we require the port number as a parameter to the +constructor. The constructor, in turn, simply does a @code{SetAttribute} +with the passed value. You can, if desired, set the ``Port'' attribute to +another value later. + +Similar to many other helper objects, the @code{UdpEchoServerHelper} object +has an @code{Install} method. It is the execution of this method that actually +causes the underlying echo server application to be instantiated and attached +to a node. Interestingly, the @code{Install} method takes a +@code{NodeContainter} as a parameter just as the other @code{Install} methods +we have seen. This is actually what is passed to the method even though it +doesn't look so in this case. There is a C++ @emph{implicit conversion} at +work here. + +We now see that @code{echoServer.Install} is going to install a +@code{UdpEchoServerApplication} on the node found at index number one of the +@code{NodeContainer} we used to manage our nodes. @code{Install} will return +a container that holds pointers to all of the applications (one in this case +since we passed a @code{NodeContainer} containing one node) created by the +helper. + +Applications require a time to ``start'' generating traffic and may take an +optional time to ``stop.'' We provide both. These times are set using the +@code{ApplicationContainer} methods @code{Start} and @code{Stop}. These +methods take @code{Time} parameters. In this case, we use an explicit C++ +conversion sequence to take the C++ double 1.0 and convert it to an +@command{ns-3} @code{Time} object using a @code{Seconds} cast. The two lines, + +@verbatim + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); +@end verbatim + +will cause the echo server application to @code{Start} (enable itself) at one +second into the simulation and to @code{Stop} (disable itself) at ten seconds +into the simulation. By virtue of the fact that we have implicilty declared +a simulation event (the application stop event) to be executed at ten seconds, +the simulation will last at least ten seconds. + +@subsubsection UdpEchoClientHelper + +The echo client application is set up in a method substantially similar to +that for the server. There is an underlying @code{UdpEchoClientApplication} +that is managed by an @code{UdpEchoClientHelper}. + +@verbatim + UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (nodes.Get (0)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); +@end verbatim + +For the echo client, however, we need to set five different attributes. The +first two attributes are set during construction of the +@code{UdpEchoClientHelper}. We pass parameters that are used (internally to +the helper) to set the ``RemoteAddress'' and ``RemotePort'' attributes in +accordance with our convention to make required attributes parameters in the +helper constructors. + +Recall that we used an @code{Ipv4InterfaceContainer} to keep track of the IP +addresses we assigned to our devices. The zeroth interface in the +@code{interfaces} container is going to coorespond to the IP address of the +zeroth node in the @code{nodes} container. The first interface in the +@code{interfaces} container cooresponds to the IP address of the first node +in the @code{nodes} container. So, in the first line of code (from above), we +are creating the helper and telling it so set the remote address of the client +to be the IP address assigned to the node on which the server resides. We +also tell it to arrange to send packets to port nine. + +The ``MaxPackets'' attribute tells the client the maximum number of packets +we allow it to send during the simulation. The ``Interval'' attribute tells +the client how long to wait between packets, and the ``PacketSize'' attribute +tells the client how large its packet payloads should be. With this +particular combination of attributes, we are telling the client to send one +1024-byte packet. + +Just as in the case of the echo server, we tell the echo client to @code{Start} +and @code{Stop}, but here we start the client one second after the server is +enabled (at two seconds into the simulation). + +@subsection Simulator +What we need to do at this point is to actually run the simulation. This is +done using the global function @code{Simulator::Run}. + +@verbatim + Simulator::Run (); +@end verbatim + +When we previously called the methods, + +@verbatim + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + ... + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); +@end verbatim + +we actually scheduled events in the simulator at 1.0 seconds, 2.0 seconds and +10.0 seconds. When @code{Simulator::Run} is called, the system will begin +looking through the list of scheduled events and executing them. First it +will run the event at 1.0 seconds, which will enable the echo server +application. Then it will run the event scheduled for t=2.0 seconds which +will start the echo client application. The start event implementation in +the echo client application will begin the data transfer phase of the +simulation by sending a packet to the server. + +The act of sending the packet to the server will trigger a chain of events +that will be automatically scheduled behind the scenes and which will perform +the mechanics of the packet echo according to the various timing parameters +that we have set in the script. + +Eventually, since we only send one packet, the chain of events triggered by +that single client echo request will taper off and the simulation will go +idle. Once this happens, the remaining events will be the @code{Stop} events +for the server and the client. When these events are executed, there are +no further events to process and @code{Simulator::Run} returns. The simulation +is complete. + +All that remains is to clean up. This is done by calling the global function +@code{Simulator::Destroy}. As the helper functions (or low level +@command{ns-3} code) executed, they arranged it so that hooks were inserted in +the simulator to destroy all of the objects that were created. You did not +have to keep track of any of these objects yourself --- all you had to do +was to call @code{Simulator::Destroy} and exit. The @command{ns-3} system +took care of the hard part for you. The remaining lines of our first +@command{ns-3} script, @code{first.cc}, do just that: + +@verbatim + Simulator::Destroy (); + return 0; + } +@end verbatim + +@subsection Building Your Script +We have made it trivial to build your simple scripts. All you have to do is +to drop your script into the scratch directory and it will automatically be +built if you run Waf. Let's try it. Copy @code{examples/first.cc} into +the @code{scratch} directory. + +@verbatim + ~/repos/ns-3-dev > cp examples/first.cc scratch/ +@end verbatim + +and then build it using waf, + +@verbatim + ~/repos/ns-3-dev > ./waf + Entering directory `/home/craigdo/repos/ns-3-dev/build' + [467/511] cxx: scratch/first.cc -> build/debug/scratch/first_1.o + [468/511] cxx: scratch/multiple-sources/simple-main.cc -> build/debug/scratch/multiple-sources/simple-main_2.o + [469/511] cxx: scratch/multiple-sources/simple-simulation.cc -> build/debug/scratch/multiple-sources/simple-simulation_2.o + [470/511] cxx: scratch/simple.cc -> build/debug/scratch/simple_3.o + [508/511] cxx_link: build/debug/scratch/first_1.o -> build/debug/scratch/first + Compilation finished successfully + ~/repos/ns-3-dev > +@end verbatim + +You can now run the example (note that if you build your program in the scratch +directory you must run it out of the scratch direcory): + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + ~/repos/ns-3-dev > +@end verbatim + +Here you see that the build system checks to make sure that the file has been +build and then runs it. You see the logging component on the echo client +indicate that it has sent one 1024 byte packet to the Echo Server on +10.1.1.2. You also see the logging component on the echo server say that +it has received the 1024 bytes from 10.1.1.1. The echo server silently +echoes the packet and you see the echo client log that it has received its +packet back from the server. + +@c ======================================================================== +@c Browsing ns-3 +@c ======================================================================== + +@node Ns-3 Source Code +@section Ns-3 Source Code + +Now that you have used some of the @command{ns-3} helpers you may want to +have a look at some of the source code that implements that functionality. +The most recent code can be browsed on our web server at the following link: +@uref{http://code.nsnam.org/?sort=lastchange}. If you click on the bold +repository names on the left of the page, you will see @emph{changelogs} for +these repositories, and links to the @emph{manifest}. From the manifest +links, one can browse the source tree. + +The top-level directory for one of our @emph{repositories} will look +something like: +@verbatim +drwxr-xr-x [up] +drwxr-xr-x doc manifest +drwxr-xr-x examples manifest +drwxr-xr-x ns3 manifest +drwxr-xr-x regression manifest +drwxr-xr-x samples manifest +drwxr-xr-x scratch manifest +drwxr-xr-x src manifest +drwxr-xr-x tutorial manifest +drwxr-xr-x utils manifest +-rw-r--r-- 135 .hgignore file | revisions | annotate +-rw-r--r-- 891 .hgtags file | revisions | annotate +-rw-r--r-- 441 AUTHORS file | revisions | annotate +-rw-r--r-- 17987 LICENSE file | revisions | annotate +-rw-r--r-- 4948 README file | revisions | annotate +-rw-r--r-- 4917 RELEASE_NOTES file | revisions | annotate +-rw-r--r-- 7 VERSION file | revisions | annotate +-rwxr-xr-x 99143 waf file | revisions | annotate +-rwxr-xr-x 28 waf.bat file | revisions | annotate +-rw-r--r-- 30584 wscript file | revisions | annotate +@end verbatim + +The source code is mainly in the @code{src} directory. You can view source +code by clicking on the @code{manifest} link to the right of the directory +name. If you click on the @code{manifest} link to the right of the src +directory you will find a subdirectory. If you click on the @code{manifest} +link next to the @code{core} subdirectory in under @code{src}, you will find +a list of files. The first file you will find is @code{assert.h}. If you +click on the @code{file} link, you will be sent to the source file for +@code{assert.h}. + +Our example scripts are in the @code{examples} directory. The source code for +the helpers we have used in this chapter can be found in the +@code{src/helpers} directory. diff --git a/doc/tutorial/figures/README b/doc/tutorial/figures/README index 4f63268dc..0b9965deb 100644 --- a/doc/tutorial/figures/README +++ b/doc/tutorial/figures/README @@ -1,18 +1,18 @@ Please write image files in a vector graphics format, when possible, and generate the .png and .pdf versions on the fly (see ../Makefile). -Currently supported tools are dia and tgif. xfig could be added similarly +The currently supported tool is dia. xfig could be added similarly if someone wants to add it. The main requirement for adding another format is that the tool to edit it is freely available and that a cron script can -autogenerate the pdf and png from the figure source. +autogenerate the pdf and png from the figure source. Tgif (.obj) files +were once used but the file conversions require a valid X display to +be running, and are therefore to be avoided since our code server +does not run such a server. Tgif pdf conversions were also cumbersome. -Store the .dia, or .obj versions in mercurial, but not the .png or .pdfs. +Store the .dia versions in mercurial, but not the .png or .pdfs. If the figure is not available in a vector graphics format, store both a .png and a .pdf version in this directory. -If you add a source (.dia, .obj) file here, remember to add it to +If you add a source (.dia) file here, remember to add it to the list of figure sources in the Makefile in the directory above -Note: tgif can convert from .obj to .pdf, but the pdf that results takes -up a whole page. Instead, we convert to an intermediate .eps step, and -then run epstopdf. diff --git a/doc/tutorial/figures/helpers.dia b/doc/tutorial/figures/helpers.dia new file mode 100644 index 000000000..2f4f24fcc Binary files /dev/null and b/doc/tutorial/figures/helpers.dia differ diff --git a/doc/tutorial/figures/helpers.obj b/doc/tutorial/figures/helpers.obj deleted file mode 100644 index 22362079f..000000000 --- a/doc/tutorial/figures/helpers.obj +++ /dev/null @@ -1,115 +0,0 @@ -%TGIF 4.1.43-QPL -state(0,37,100.000,0,0,0,32,1,9,1,1,0,0,1,2,1,0,'Courier',0,80640,0,2,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). -% -% @(#)$Header$ -% %W% -% -unit("1 pixel/pixel"). -color_info(11,65535,0,[ - "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, - "red", 65535, 0, 0, 65535, 0, 0, 1, - "green", 0, 65535, 0, 0, 65535, 0, 1, - "blue", 0, 0, 65535, 0, 0, 65535, 1, - "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, - "pink", 65535, 49344, 52171, 65535, 49344, 52171, 1, - "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, - "CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1, - "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, - "black", 0, 0, 0, 0, 0, 0, 1, - "DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1 -]). -script_frac("0.6"). -fg_bg_colors('black','white'). -dont_reencode("FFDingbests:ZapfDingbats"). -page(1,"",1,''). -text('black',272,195,2,0,1,248,36,0,13,5,0,0,0,0,2,248,36,0,0,"",0,0,0,0,208,'',[ -minilines(248,36,0,0,0,0,0,[ -mini_line(200,13,5,0,0,0,[ -str_block(0,200,13,5,0,-8,0,0,0,[ -str_seg('black','Courier',0,80640,200,13,5,0,-8,0,0,0,0,0, - "low-level APIs (all src/ ")]) -]), -mini_line(248,13,5,0,0,0,[ -str_block(0,248,13,5,0,-2,0,0,0,[ -str_seg('black','Courier',0,80640,248,13,5,0,-2,0,0,0,0,0, - "directories except src/helper/)")]) -]) -])]). -rcbox('black','',96,240,384,288,5,1,1,0,16,2,0,0,0,0,'1',0,[ -]). -text('black',192,259,1,0,1,112,18,3,13,5,2,0,0,0,2,112,18,0,0,"",0,0,0,0,272,'',[ -minilines(112,18,0,0,0,0,0,[ -mini_line(112,13,5,0,0,0,[ -str_block(0,112,13,5,0,0,0,0,0,[ -str_seg('black','Courier',0,80640,112,13,5,0,0,0,0,0,0,0, - "ns-3 simulator")]) -]) -])]). -poly('black','',2,[ - 272,208,240,240],0,1,1,17,0,0,2,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). -poly('black','',2,[ - 240,176,240,240],1,1,1,18,0,0,0,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). -rcbox('black','',176,128,384,176,5,1,1,0,16,25,0,0,0,0,'1',0,[ -]). -text('black',192,131,2,0,1,120,36,26,13,5,2,0,0,0,2,120,36,0,0,"",0,0,0,0,144,'',[ -minilines(120,36,0,0,0,0,0,[ -mini_line(120,13,5,0,0,0,[ -str_block(0,120,13,5,0,-1,0,0,0,[ -str_seg('black','Courier',0,80640,120,13,5,0,-1,0,0,0,0,0, - "ns-3 helper API")]) -]), -mini_line(96,13,5,0,0,0,[ -str_block(0,96,13,5,0,-2,0,0,0,[ -str_seg('black','Courier',0,80640,96,13,5,0,-2,0,0,0,0,0, - "(src/helper)")]) -]) -])]). -rcbox('black','',96,16,384,64,0,1,1,0,16,32,0,0,0,0,'1',0,[ -]). -poly('black','',2,[ - 240,64,240,128],1,1,1,36,0,0,0,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). -text('black',272,83,2,0,1,200,36,40,13,5,0,0,0,0,2,200,36,0,0,"",0,0,0,0,96,'',[ -minilines(200,36,0,0,0,0,0,[ -mini_line(200,13,5,0,0,0,[ -str_block(0,200,13,5,0,-2,0,0,0,[ -str_seg('black','Courier',0,80640,200,13,5,0,-2,0,0,0,0,0, - "helper APIs (src/helper/)")]) -]), -mini_line(192,13,5,0,0,0,[ -str_block(0,192,13,5,0,-1,0,0,0,[ -str_seg('black','Courier',0,80640,192,13,5,0,-1,0,0,0,0,0, - "call into low-level APIs")]) -]) -])]). -poly('black','',2,[ - 272,96,240,128],0,1,1,41,0,0,2,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). -text('black',128,19,2,0,1,232,36,47,13,5,0,0,0,0,2,232,36,0,0,"",0,0,0,0,32,'',[ -minilines(232,36,0,0,0,0,0,[ -mini_line(224,13,5,0,0,0,[ -str_block(0,224,13,5,0,-2,0,0,0,[ -str_seg('black','Courier',0,80640,224,13,5,0,-2,0,0,0,0,0, - "ns-3 scripts (main programs)")]) -]), -mini_line(232,13,5,0,0,0,[ -str_block(0,232,13,5,0,-1,0,0,0,[ -str_seg('black','Courier',0,80640,232,13,5,0,-1,0,0,0,0,0, - "- may use either or both APIs")]) -]) -])]). -poly('black','',2,[ - 144,64,144,240],1,1,1,50,0,0,0,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). diff --git a/doc/tutorial/figures/packet.obj b/doc/tutorial/figures/packet.obj deleted file mode 100644 index c6a66cd71..000000000 --- a/doc/tutorial/figures/packet.obj +++ /dev/null @@ -1,227 +0,0 @@ -%TGIF 4.1.43-QPL -state(0,37,100.000,0,64,0,32,0,9,1,1,1,0,0,0,1,0,'Courier-Bold',1,103680,0,3,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). -% -% @(#)$Header$ -% %W% -% -unit("1 pixel/pixel"). -color_info(11,65535,0,[ - "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, - "red", 65535, 0, 0, 65535, 0, 0, 1, - "green", 0, 65535, 0, 0, 65535, 0, 1, - "blue", 0, 0, 65535, 0, 0, 65535, 1, - "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, - "pink", 65535, 49344, 52171, 65535, 49344, 52171, 1, - "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, - "CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1, - "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, - "black", 0, 0, 0, 0, 0, 0, 1, - "DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1 -]). -script_frac("0.6"). -fg_bg_colors('black','white'). -dont_reencode("FFDingbests:ZapfDingbats"). -page(1,"",1,''). -box('black','',32,48,240,256,0,3,1,0,0,0,0,0,0,'3',0,[ -]). -text('black',64,10,1,0,1,121,28,3,22,6,0,0,0,0,2,121,28,0,0,"",0,0,0,0,32,'',[ -minilines(121,28,0,0,0,0,0,[ -mini_line(121,22,6,0,0,0,[ -str_block(0,121,22,6,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,138240,121,22,6,0,0,0,0,0,0,0, - "class Packet")]) -]) -])]). -text('black',416,100,1,0,1,116,28,15,22,6,0,0,0,0,2,116,28,0,0,"",0,0,0,0,122,'',[ -minilines(116,28,0,0,0,0,0,[ -mini_line(116,22,6,0,0,0,[ -str_block(0,116,22,6,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,138240,116,22,6,0,0,0,0,0,0,0, - "class Buffer")]) -]) -])]). -text('black',48,178,4,0,1,83,69,32,14,4,0,0,0,0,2,83,69,0,0,"",0,0,0,0,192,'',[ -minilines(83,69,0,0,0,0,0,[ -mini_line(80,14,4,0,0,0,[ -str_block(0,80,14,4,0,-1,0,0,0,[ -str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0, - "private data:")]) -]), -mini_line(59,14,3,0,0,0,[ -str_block(0,59,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,59,14,3,0,0,0,0,0,0,0, - "- unique id")]) -]), -mini_line(83,14,3,0,0,0,[ -str_block(0,83,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,83,14,3,0,0,0,0,0,0,0, - "- Buffer object")]) -]), -mini_line(76,14,3,0,0,0,[ -str_block(0,76,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,76,14,3,0,0,0,0,0,0,0, - "- Tags object")]) -]) -])]). -text('black',112,288,1,0,1,103,28,82,22,6,0,0,0,0,2,103,28,0,0,"",0,0,0,0,310,'',[ -minilines(103,28,0,0,0,0,0,[ -mini_line(103,22,6,0,0,0,[ -str_block(0,103,22,6,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,138240,103,22,6,0,-1,0,0,0,0,0, - "class Tags")]) -]) -])]). -text('black',48,50,5,0,1,175,86,176,14,4,0,0,0,0,2,175,86,0,0,"",0,0,0,0,64,'',[ -minilines(175,86,0,0,0,0,0,[ -mini_line(105,14,4,0,0,0,[ -str_block(0,105,14,4,0,-1,0,0,0,[ -str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0, - "public functions:")]) -]), -mini_line(80,14,3,0,0,0,[ -str_block(0,80,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,80,14,3,0,-1,0,0,0,0,0, - "- constructors")]) -]), -mini_line(175,14,3,0,0,0,[ -str_block(0,175,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,175,14,3,0,-1,0,0,0,0,0, - "- add/remove/peek at Headers")]) -]), -mini_line(155,14,3,0,0,0,[ -str_block(0,155,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,155,14,3,0,-1,0,0,0,0,0, - "- add/remove/peek at Tags")]) -]), -mini_line(88,14,3,0,0,0,[ -str_block(0,88,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,88,14,3,0,0,0,0,0,0,0, - "- fragmentation")]) -]) -])]). -box('black','',384,144,614,352,0,3,1,245,0,0,0,0,0,'3',0,[ -]). -text('black',400,274,4,0,1,204,69,246,14,4,0,0,0,0,2,204,69,0,0,"",0,0,0,0,288,'',[ -minilines(204,69,0,0,0,0,0,[ -mini_line(80,14,4,0,0,0,[ -str_block(0,80,14,4,0,-1,0,0,0,[ -str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0, - "private data:")]) -]), -mini_line(193,14,3,0,0,0,[ -str_block(0,193,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,193,14,3,0,0,0,0,0,0,0, - "- struct BufferData, a dynamically")]) -]), -mini_line(160,14,3,0,0,0,[ -str_block(0,160,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,160,14,3,0,0,0,0,0,0,0, - "varying byte buffer to which")]) -]), -mini_line(204,14,3,0,0,0,[ -str_block(0,204,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,204,14,3,0,0,0,0,0,0,0, - "data can be prepended or appended")]) -]) -])]). -text('black',400,146,5,0,1,188,86,247,14,4,0,0,0,0,2,188,86,0,0,"",0,0,0,0,160,'',[ -minilines(188,86,0,0,0,0,0,[ -mini_line(105,14,4,0,0,0,[ -str_block(0,105,14,4,0,-1,0,0,0,[ -str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0, - "public functions:")]) -]), -mini_line(172,14,3,0,0,0,[ -str_block(0,172,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,172,14,3,0,0,0,0,0,0,0, - "- Iterators to move byte buffer")]) -]), -mini_line(171,14,3,0,0,0,[ -str_block(0,171,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,171,14,3,0,0,0,0,0,0,0, - "pointers forward or backward")]) -]), -mini_line(188,14,3,0,0,0,[ -str_block(0,188,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,188,14,3,0,0,0,0,0,0,0, - "- functions to read and write data")]) -]), -mini_line(132,14,3,0,0,0,[ -str_block(0,132,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,132,14,3,0,-1,0,0,0,0,0, - "of various sized chunks")]) -]) -])]). -box('black','',96,324,304,532,0,3,1,264,0,0,0,0,0,'3',0,[ -]). -text('black',112,454,4,0,1,167,69,265,14,4,0,0,0,0,2,167,69,0,0,"",0,0,0,0,468,'',[ -minilines(167,69,0,0,0,0,0,[ -mini_line(80,14,4,0,0,0,[ -str_block(0,80,14,4,0,-1,0,0,0,[ -str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0, - "private data:")]) -]), -mini_line(167,14,3,0,0,0,[ -str_block(0,167,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,167,14,3,0,0,0,0,0,0,0, - "- singly linked-list of TagData")]) -]), -mini_line(158,14,3,0,0,0,[ -str_block(0,158,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,158,14,3,0,0,0,0,0,0,0, - "structures, with a reference")]) -]), -mini_line(32,14,3,0,0,0,[ -str_block(0,32,14,3,0,0,0,0,0,[ -str_seg('black','Times-Roman',0,80640,32,14,3,0,0,0,0,0,0,0, - "count")]) -]) -])]). -text('black',112,326,5,0,1,155,86,266,14,4,0,0,0,0,2,155,86,0,0,"",0,0,0,0,340,'',[ -minilines(155,86,0,0,0,0,0,[ -mini_line(105,14,4,0,0,0,[ -str_block(0,105,14,4,0,-1,0,0,0,[ -str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0, - "public functions:")]) -]), -mini_line(80,14,3,0,0,0,[ -str_block(0,80,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,80,14,3,0,-1,0,0,0,0,0, - "- constructors")]) -]), -mini_line(155,14,3,0,0,0,[ -str_block(0,155,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,155,14,3,0,-1,0,0,0,0,0, - "- templates to add, remove,")]) -]), -mini_line(148,14,3,0,0,0,[ -str_block(0,148,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,148,14,3,0,-1,0,0,0,0,0, - "or peek at Tags of various")]) -]), -mini_line(31,14,3,0,0,0,[ -str_block(0,31,14,3,0,-1,0,0,0,[ -str_seg('black','Times-Roman',0,80640,31,14,3,0,-1,0,0,0,0,0, - "types")]) -]) -])]). -poly('black','',2,[ - 59,245,96,320],0,2,1,272,0,0,3,0,0,0,0,'2',0,0, - "0","",[ - 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ -]). -poly('black','',2,[ - 123,246,288,320],0,2,1,280,0,0,3,0,0,0,0,'2',0,0, - "0","",[ - 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ -]). -poly('black','',2,[ - 141,219,379,147],0,2,1,286,0,0,3,0,0,0,0,'2',0,0, - "0","",[ - 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ -]). -poly('black','',2,[ - 132,226,375,335],0,2,1,287,0,0,3,0,0,0,0,'2',0,0, - "0","",[ - 0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[ -]). diff --git a/doc/tutorial/getting-started.texi b/doc/tutorial/getting-started.texi new file mode 100644 index 000000000..1a1106893 --- /dev/null +++ b/doc/tutorial/getting-started.texi @@ -0,0 +1,342 @@ + +@c ======================================================================== +@c Begin document body here +@c ======================================================================== + +@c ======================================================================== +@c PART: Getting Started +@c ======================================================================== +@c The below chapters are under the major heading "Getting Started" +@c This is similar to the Latex \part command +@c +@c ======================================================================== +@c Getting Started +@c ======================================================================== +@node Getting Started +@chapter Getting Started + +@menu +* Downloading ns-3:: +* Building ns-3:: +* Testing ns-3:: +* Running a Script:: +@end menu + +@c ======================================================================== +@c Downloading ns-3 +@c ======================================================================== + +@node Downloading ns-3 +@section Downloading ns-3 + +@cindex Linux +@cindex Cygwin +@cindex GNU +@cindex toolchain +@cindex Mercurial +@cindex Waf +From this point forward, we are going to assume that the reader is working in +Linux or a Linux emulation environment (Linux, Cygwin, etc.) and has the GNU +toolchain installed and verified. We are also going to assume that you have +Mercurial and Waf installed and running on the target system as described in +the Getting Started section of the @command{ns-3} web site: +@uref{http://www.nsnam.org/getting_started.html}. + +@cindex tarball +The @command{ns-3} code is available in Mercurial repositories on the server +code.nsnam.org. You can download a tarball release at +@uref{http://www.nsnam.org/releases/}, or you can work with repositories +using Mercurial. + +@cindex repository +If you go to the following link: @uref{http://code.nsnam.org/}, +you will see a number of repositories. Many are the private repositories of +the @command{ns-3} development team. The repositories of interest to you will +be prefixed with ``ns-3''. The current development snapshot (unreleased) +of @command{ns-3} may be found at: @uref{http://code.nsnam.org/ns-3-dev/}. +Official releases of @command{ns-3} will be numbered as @code{ns-3.} +with any required hotfixes added as minor release numbers. For example, a +second hotfix to a hypothetical release nine of @command{ns-3} would be +numbered @code{ns-3.9.2}. + +The current development snapshot (unreleased) of @command{ns-3} may be found +at: @uref{http://code.nsnam.org/ns-3-dev/}. The developers attempt to keep +this repository in a consistent, working state but it is a development area +with unreleased code present, so you may want to consider staying with an +official release if you do not need newly-introduced features. + +Since the release numbers are going to be changing, I will stick with +the more constant ns-3-dev here in the tutorial, but you can replace the +string ``ns-3-dev'' with your choice of release (e.g., ns-3.2) in the text +below. You can find the latest version of the code either by inspection of +the repository list or by going to the ``Getting Started'' web page and +looking for the latest release identifier. + +One practice is to create a directory called @code{repos} in one's home +directory under which one can keep local Mercurial repositories. +@emph{Hint: we will assume you do this later in the tutorial.} If you adopt +that approach, you can get a copy of the development version of +@command{ns-3} by typing the following into your Linux shell (assuming you +have installed Mercurial): + +@verbatim + cd + mkdir repos + cd repos + hg clone http://code.nanam.org/ns-3-dev +@end verbatim + +As the hg (Mercurial) command executes, you should see something like the +following, + +@verbatim + destination directory: ns-3-dev + requesting all changes + adding changesets + adding manifests + adding file changes + added 3276 changesets with 12301 changes to 1353 files + 594 files updated, 0 files merged, 0 files removed, 0 files unresolved +@end verbatim + +After the clone command completes, you should have a directory called +ns-3-dev under your @code{~/repos} directory, the contents of which should +look something like the following: + +@verbatim + AUTHORS examples/ README samples/ utils/ waf.bat* + build/ LICENSE regression/ scratch/ VERSION wscript + doc/ ns3/ RELEASE_NOTES src/ waf* +@end verbatim + +Similarly, if working from a released version instead, you can simply +@verbatim + cd + mkdir repos + wget http://www.nsnam.org/releases/ns-3.2.tar.bz2 + bunzip2 ns-3.2.tar.bz2 + tar xvf ns-3.2.tar +@end verbatim + +You are now ready to build the @command{ns-3} distribution. + +@c ======================================================================== +@c Building ns-3 +@c ======================================================================== + +@node Building ns-3 +@section Building ns-3 + +@cindex building with Waf +@cindex configuring Waf +@cindex building debug version with Waf +@cindex compiling with Waf +@cindex unit tests with Waf +@cindex regression tests with Waf +We use Waf to build the @command{ns-3} project. The first thing you will need +to do is to configure the build. For reasons that will become clear later, +we are going to work with debug builds in the tutorial. To explain to Waf +that it should do debug builds you will need to execute the following command, + +@verbatim + ./waf -d debug configure +@end verbatim + +This runs Waf out of the local directory (which is provided as a convenience +for you). As the build system checks for various dependencies you should see +output that looks similar to the following, + +@verbatim +Checking for program g++ : ok /usr/bin/g++ +Checking for compiler version : ok Version 4.0.1 +Checking for program cpp : ok /usr/bin/cpp +Checking for program ar : ok /usr/bin/ar +Checking for program ranlib : ok /usr/bin/ranlib +Checking for compiler could create programs : ok +Checking for compiler could create shared libs : ok +Checking for compiler could create static libs : ok +Checking for flags -O2 -DNDEBUG : ok +Checking for flags -g -DDEBUG : ok +Checking for flags -g3 -O0 -DDEBUG : ok +Checking for flags -Wall : ok +Checking for g++ : ok +Checking for -Wno-error=deprecated-declarations compilation flag support : no +Checking for header stdlib.h : ok +Checking for header stdlib.h : ok +Checking for header signal.h : ok +Checking for library rt : not found +Checking for header pthread.h : ok +Checking for high precision time implementation: 128-bit integer +Checking for header stdint.h : ok +Checking for header inttypes.h : ok +Checking for header sys/inttypes.h : not found +Checking for package gtk+-2.0 >= 2.12 : not found +Checking for library sqlite3 : ok +Checking for package goocanvas gthread-2.0 : not found +Checking for program python : ok /usr/local/bin/python +Checking for Python version >= 2.3 : ok 2.4.3 +Checking for library python2.4 : not found +Checking for library python2.4 : not found +Checking for library python24 : not found +Checking for program python2.4-config : not found +Checking for header Python.h : not found +Checking for program diff : ok /usr/bin/diff +Checking for program hg : ok /opt/local/bin/hg +---- Summary of optional NS-3 features: +Threading Primitives : enabled +Real Time Simulator : enabled +GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found) +SQlite stats data output : enabled +Network Simulation Cradle : not enabled (--enable-nsc configure option not given) +Python Bindings : not enabled (Python development headers not found.) +Configuration finished successfully; project is now ready to build. +@end verbatim + +Note the trailing portion of the above output. Some ns-3 options are +not enabled by default or require support from the underlying system. +For instance, to enable Python bindings, Python development headers must +be installed on the host machine, and they were not found in the above +example, so Python scripting will not be supported in the resulting build. +For this tutorial, we will focus on the non-optional pieces of ns-3. + +The build system is now configured and you can build the debug versions of +the @command{ns-3} programs by simply typing, + +@verbatim + ./waf +@end verbatim + +(Hint: if you have a multicore machine, use the "-j JOBS" option to speed +up your build, where JOBS is the number of cores) +You will see many Waf status messages displayed as the system compiles. The +most important is the last one: + +@verbatim + Compilation finished successfully +@end verbatim + +@c ======================================================================== +@c Testing ns-3 +@c ======================================================================== + +@node Testing ns-3 +@section Testing ns-3 + +@cindex unit tests +You can run the unit tests of the @command{ns-3} distribution by running the +``check'' command, + +@verbatim + ./waf check +@end verbatim + +You should see a report from each unit test that executes indicating that the +test has passed. + +@verbatim + ~/repos/ns-3-dev > ./waf check + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + PASS AddressHelper + PASS Wifi + PASS DcfManager + + ... + + PASS Object + PASS Ptr + PASS Callback + ~/repos/ns-3-dev > +@end verbatim + +This command is typically run by @code{users} to quickly verify that an +@command{ns-3} distribution has built correctly. + +@cindex regression tests +You can also run our regression test suite to ensure that your distribution and +tool chain have produced binaries that generate output that is identical to +reference output files stored in a central location. To run the regression +tests, you provide Waf with the regression flag. + +@verbatim + ./waf --regression +@end verbatim + +Waf will verify that the current files in the @command{ns-3} distribution are +built and will then look for trace files in the aforementioned centralized +location. If your tool chain includes Mercurial, the regression tests will +be downloaded from a repository at @code{code.nsnam.org}. If you do not have +Mercurial installed, the reference traces will be downloaded from a tarball +located in the releases section of @code{www.nsnam.org}. The particular name +of the reference trace location is built from the @command{ns-3} version +located in the VERSION file, so don't change that string yourself unless you +know what you are doing. (Warning: The ns-3.2 release requires you +to be online when you run regression tests because it synchronizes the +trace directory with an online repository). + +Once the reference traces are downloaded to your local machine, Waf will run +a number of tests that generate what we call trace files. The content of +these trace files are compared with the reference traces just downloaded. If +they are identical, the regression tests report a PASS status. If the +regression tests pass, you should see something like, + +@verbatim + ~/repos/ns-3-dev > ./waf --regression + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + ========== Running Regression Tests ========== + Synchronizing reference traces using Mercurial. + Pulling http://code.nsnam.org/ns-3-dev-ref-traces from repo. + Skipping csma-bridge: Python bindings not available. + SKIP test-csma-bridge + PASS test-csma-broadcast + PASS test-csma-multicast + PASS test-csma-one-subnet + PASS test-csma-packet-socket + PASS test-realtime-udp-echo + PASS test-simple-error-model + PASS test-simple-global-routing + PASS test-simple-point-to-point-olsr + PASS test-tcp-large-transfer + PASS test-udp-echo + PASS test-wifi-wired-bridging + + ~/repos/ns-3-dev > +@end verbatim + +If a regression tests fails you will see a FAIL indication along with a +pointer to the offending trace file and its associated reference trace file +along with a suggestion on diff parameters and options in order to see what +has gone awry. Python regression tests will be SKIPped if Python bindings +are not built. + +@c ======================================================================== +@c Running a Script +@c ======================================================================== + +@node Running a Script +@section Running a Script +@cindex running a script with Waf +We typically run scripts under the control of Waf. This allows the build +system to ensure that the shared library paths are set correctly and that +the libraries are available at run time. To run a program, simply use the +@code{--run} option in Waf. Let's run the @command{ns-3} equivalent of the +ubiquitous hello world program by typing the following: + +@verbatim + ./waf --run hello-simulator +@end verbatim + +Waf first checks to make sure that the program is built correctly and +executes a build if required. Waf then then executes the program, which +produces the following output. + +@verbatim + Hello Simulator +@end verbatim + +@emph{Congratulations. You are now an ns-3 user.} + +If you want to run programs under another tool such as gdb or valgrind, +see this @uref{http://www.nsnam.org/wiki/index.php/User_FAQ#How_to_run_NS-3_programs_under_another_tool,,wiki entry}. + diff --git a/doc/tutorial/in-process/Makefile b/doc/tutorial/in-process/Makefile new file mode 100644 index 000000000..58857b0dd --- /dev/null +++ b/doc/tutorial/in-process/Makefile @@ -0,0 +1,49 @@ +TEXI2HTML = texi2html +TEXI2PDF = texi2dvi --pdf +EPSTOPDF = epstopdf +TGIF = tgif +DIA = dia +CONVERT = convert +CSS = --css-include=tutorial.css +SPLIT = --split section + +DIA_SOURCES = pp.dia dumbbell.dia star.dia +TGIF_SOURCES = helpers.obj + +DIA_EPS = ${DIA_SOURCES:.dia=.eps} +DIA_PNG = ${DIA_SOURCES:.dia=.png} +DIA_PDF = ${DIA_SOURCES:.dia=.pdf} + +TGIF_EPS = ${TGIF_SOURCES:.obj=.eps} +TGIF_PNG = ${TGIF_SOURCES:.obj=.png} +TGIF_PDF = ${TGIF_SOURCES:.obj=.pdf} + +all: images html split-html pdf + +# Note: tgif requires a valid x display to convert from .obj to .png. +# If running this makefile on a remote console, the X virtual frame +# buffer may be needed (xorg-x11-server-Xvfb) to provide a "fake" +# display +images: + cd figures/; $(DIA) -t png $(DIA_SOURCES) + cd figures/; $(DIA) -t eps $(DIA_SOURCES) + cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);) + cd figures/; $(TGIF) -print -png $(TGIF_SOURCES) + cd figures/; $(TGIF) -print -eps $(TGIF_SOURCES) + cd figures/; $(foreach FILE,$(TGIF_EPS),$(EPSTOPDF) $(FILE);) + +html: images + $(TEXI2HTML) ${CSS} tutorial.texi + +split-html: images + $(TEXI2HTML) ${CSS} ${SPLIT} tutorial.texi + +pdf: images + $(TEXI2PDF) tutorial.texi + +figures-clean: + cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF) + cd figures/; rm -rf $(TGIF_EPS); rm -rf $(TGIF_PNG); rm -rf $(TGIF_PDF) + +clean: figures-clean + rm -rf tutorial.aux tutorial.cp tutorial.cps tutorial.fn tutorial.ky tutorial.pg tutorial.tp tutorial.vr tutorial.toc tutorial.log tutorial.pdf tutorial.html tutorial/ diff --git a/doc/tutorial/attributes.texi b/doc/tutorial/in-process/attributes.texi similarity index 100% rename from doc/tutorial/attributes.texi rename to doc/tutorial/in-process/attributes.texi diff --git a/doc/tutorial/helpers.texi b/doc/tutorial/in-process/helpers.texi similarity index 100% rename from doc/tutorial/helpers.texi rename to doc/tutorial/in-process/helpers.texi diff --git a/doc/tutorial/in-process/introduction.texi b/doc/tutorial/in-process/introduction.texi new file mode 100644 index 000000000..248120e3f --- /dev/null +++ b/doc/tutorial/in-process/introduction.texi @@ -0,0 +1,2034 @@ + +@c ======================================================================== +@c Begin document body here +@c ======================================================================== + +@c ======================================================================== +@c Tutorial Goals +@c ======================================================================== + +@node Tutorial Goals +@unnumbered Tutorial Goals + +@c This is an unnumbered section, like a preface. Numbering +@c starts with section 1 (Introduction) + +The goal of this ns-3 tutorial is to introduce new users of ns-3 to enough +of the system to enable them to author simple simulation scripts and extract +useful information from the simulations. We begin by introducing some of the +other important resources that are available to those interested in using or +writing scripts, models and even those interested in making contributions to +the core ns-3 system. We provide an overview of some of the +important abstractions, design patterns and idioms used when writing +ns-3 scripts, and then dig right in by begining to write simulation +scripts, run them and interpret results. + +After completing this tutorial, one should be able to: +@itemize @bullet +@item Find documentation resources in the distribution and on the web; +@item Download and compile the ns-3 system; +@item Understand the key software conventions of ns-3; +@item Modify configuration parameters of existing scripts; +@item Change the simulation output (tracing, logging, statistics); +@item Extend the simulator to use new objects +@item Write new ns-3 applications; +@item See how to port code from ns-2; +@item ... (more to follow) +@end itemize + +@c ======================================================================== +@c PART: Introduction +@c ======================================================================== +@c The below chapters are under the major heading "Introduction" +@c This is similar to the Latex \part command +@c +@c ======================================================================== +@c Overview +@c ======================================================================== +@node Overview +@chapter Overview + +@menu +* For ns-2 users:: +* Contributing:: +* Tutorial organization:: +@end menu + +The ns-3 simulator is a discrete-event network +simulator targeted primarily for research and educational use. +The @uref{http://www.nsnam.org,,ns-3 project}, started in +2006, is an open-source project. The goal of the project is to +build a new network simulator primarily for research and educational use. + +Primary documentation for the ns-3 project is available in +three forms: +@itemize @bullet +@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator +@item Tutorial (this document) +@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} +@end itemize + +The purpose of this tutorial is to introduce new ns-3 users to the +system in a structured way. It is sometimes difficult for new users to +glean essential information from detailed manuals and to convert this +information into working simulations. In this tutorial, we will build +several example simulations, introducing and explaining key concepts and +features as we go. + +As the tutorial unfolds, we will introduce the full ns-3 +documentation +and provide pointers to source code for those interested in delving deeper +into the workings of the system. + +A few key points are worth noting at the onset: +@itemize @bullet +@item ns-3 is not an extension of @uref{http://www.isi.edu/nsnam/ns,,ns-2}; +it is a new +simulator. The two simulators are both written in C++ but ns-3 +is a new simulator that does not support the ns-2 APIs. +Some models from ns-2 have already been ported from ns-2 +to ns-3. The project will continue to maintain ns-2 while +ns-3 is being built, and will study transition and +integration mechanisms. +@item ns-3 is open-source, and the project strives to maintain +an open environment for researchers to contribute and share their +software. +@end itemize + +@node For ns-2 users +@section For ns-2 users + +For those familiar with ns-2, the most visible outward change +when moving to ns-3 is the choice of scripting language. +ns-2 is typically scripted in Tcl and results of simulations can +be visualized using the Network Animator @command{nam}. In +ns-3 there is currently no visualization module, and Python +bindings have been developed (Tcl bindings have been prototyped +using @uref{http://www.swig.org,,SWIG}, but are not supported by the +current development team). +In this tutorial, we will concentrate on +scripting directly in C++ and interpreting results via trace files. + +But there are similarities as well (both, for example, are based +on C++ objects, and some code from ns-2 has already been ported +to ns-3). We will try to highlight differences between ns-2 and ns-3 +as we proceed in this tutorial. + +@node Contributing +@section Contributing + +@cindex software configuration management +ns-3 is a research and educational simulator, by and for the +research community. It will rely on the ongoing contributions of +the community to develop new models, debug or maintain +existing ones, and share results. There are a few policies +that we hope will encourage people to contribute to ns-3 like they +have for ns-2: +@itemize @bullet +@item open source licensing based on GNU GPLv2 compatibility +@item @uref{http://www.nsnam.org/wiki/index.php,,wiki} +@item @uref{http://www.nsnam.org/wiki/index.php/Contributed_Code,,Contributed Code} page, similar to ns-2's popular +@uref{http://nsnam.isi.edu/nsnam/index.php/Contributed_Code,,Contributed Code} +page +@item @code{src/contrib} directory (we will host your contributed code) +@item open @uref{http://www.nsnam.org/bugzilla,,bug tracker} +@item ns-3 developers will gladly help potential contributors to get +started with the simulator (please contact @uref{http://www.nsnam.org/people.html,,one of us}) +@end itemize + +If you are an ns user, please consider to provide your feedback, +bug fixes, or code to the project. + +@node Tutorial organization +@section Tutorial organization + +The tutorial assumes that new users might follow a path such as follows: + +@itemize @bullet +@item browse the source code and documentation, to get a feel for +the simulator and what it might be like to handle; +@item try to download and build a copy; +@item try to run a few sample programs, and perhaps change some configurations; +@item look at simulation output, and try to adjust it +@item study the software architecture of the system, to consider hacking it or +extending it; +@item write new models or port existing code to ns-3, and eventually post those +models back to the community. +@end itemize + +As a result, we have tried to organize the tutorial along the above +broad sequences of events. + +@c ======================================================================== +@c Browsing ns-3 +@c ======================================================================== + +@node Browsing +@chapter Browsing ns-3 + +@menu +* Source code:: +* Doxygen:: +* Other documentation:: +@end menu + +@node Source code +@section Source code + +The most recent code can be browsed on our web server at the following link: +@uref{http://code.nsnam.org/?sort=lastchange}. If you click on the bold +repository names on the left of the page, you will see changelogs for +these repositories, and links to the @emph{manifest}. From the manifest +links, one can browse the source tree. + +The top-level directory will look something like: +@verbatim + AUTHORS RELEASE_NOTES examples/ src/ waf* + LICENSE VERSION ns3/ tutorial/ waf.bat* + README doc/ samples/ utils/ wscript +@end verbatim +The source code is mainly in the @code{src} directory. Example +scripts are in the @code{examples} directory. Both are good directories +to start browsing some code. + +For ns-2 users, who may be familiar with the @code{simple.tcl} example script +in the ns-2 documentation, an analogous script is found in +@code{examples/simple-point-to-point.cc} with a Python equivalent found +in @emph{(pending Python merge)}. + +@node Doxygen +@section Doxygen + +We document all of APIs using @uref{http://www.stack.nl/~dimitri/doxygen/,,Doxygen}. Current builds of this documentation are available at: +@uref{http://www.nsnam.org/doxygen/index.html}, which are worth an initial +look. + +@node Other documentation +@section Other documentation + +See: @uref{http://www.nsnam.org/documents.html}. + +@c ======================================================================== +@c Resources +@c ======================================================================== + +@node Resources +@chapter Resources + +@menu +* The-Web:: +* Mercurial:: +* Waf:: +* Environment-Idioms-Design-Patterns:: +* Socket-Programming:: +@end menu + +@node The-Web +@section The Web + +@cindex www.nsnam.org +There are several important resources of which any ns-3 user must be +aware. The main web site is located at @uref{http://www.nsnam.org} +and provides access to basic information about the ns-3 system. +Detailed documentation is available through the main web site at +@uref{http://www.nsnam.org/documents.html}. + +@cindex documentation +@cindex architecture +You can find documents relating to the system architecture from this page, +and also gain access to the detailed software documentation. The software +system is documented in great detail using +@uref{http://www.stack.nl/~dimitri/doxygen/,,Doxygen}. There is a Wiki that +complements the main ns-3 web site which you will find at +@uref{http://www.nsnam.org/wiki/}. + +You will find user and developer FAQs there as well as troubleshooting guides, +third-party contributed code, papers, etc. The source code may be found +and browsed at @uref{http://code.nsnam.org/}. + +@cindex repository!ns-3-dev +@cindex repository!releases +There you will find the current development tree in the repository named +@code{ns-3-dev}. Past releases and experimental repositories of the core +developers may also be found there. + +@node Mercurial +@section Mercurial + +Complex software systems need some way to manage the organization and +changes to the underlying code and documentation. There are many ways to +perform this feat, and you may have heard of some of the systems that are +currently used to do this. The Concurrent Version System (CVS) is probably +the most well known. + +@cindex software configuration management +@cindex Mercurial +The ns-3 project uses Mercurial as its source code management system. +Although you do not need to know much about Mercurial in order to complete +this tutorial, we recommend becoming familiar with Mercurial and using it +to access the source code. Mercurial has a web site at +@uref{http://www.selenic.com/mercurial/}, +from which you can get binary or source releases of this Software +Configuration Management (SCM) system. Selenic (the developer of Mercurial) +also provides a tutorial at +@uref{http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/}, +and a QuickStart guide at +@uref{http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/}. + +You can also find vital information about using Mercurial and ns-3 +on the main ns-3 web site. + +@node Waf +@section Waf + +@cindex Waf +@cindex make +@cindex build +Once you have source code downloaded to your local system, you will need +to compile that source to produce usable programs. Just as in the case of +source code management, there are many tools available to perform this +function. Probably the most famous of these tools is @code{make}. Along +with being the most famous, @code{make} is probably the most difficult to +use in a very large and highly configurable system. Because of this, many +alternatives have been developed. Recently these systems have been developed +using the Python language. + +The build system @code{Waf} is used on the ns-3 project. It is one +of the new generation of Python-based build systems. You will not need to +understand any Python to build the existing ns-3 system, and will +only have to understand a tiny and intuitively obvious subset of Python in +order to extend the system in most cases. + +For those interested in the gory details of Waf, the main web site can be +found at @uref{http://freehackers.org/\~tnagy/waf.html}. + +@node Environment-Idioms-Design-Patterns +@section Environment, Idioms, and Design Patterns + +@cindex C++ +As mentioned above, scripting in ns-3 is done in C++. A working +knowledge of C++ and object-oriented concepts is assumed in this document. +We will take some time to review some of the more advanced concepts or +possibly unfamiliar language features, idioms and design patterns as they +appear. We don't want this tutorial to devolve into a C++ tutorial, though, +so we do expect a basic command of the language. There are an almost +unimaginable number of sources of information on C++ available on the web or +in print. + +If you are new to C++, you may want to find a tutorial- or cookbook-based +book or web site and work through at least the basic features of the language +before proceeding. + +@subsection Environment + +@cindex toolchain +@cindex GNU +The ns-3 system uses the GNU ``toolchain'' for development. +A software toolchain is the set of programming tools available in the given +environment. For a quick review of what is included in the GNU toolchain see, +@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. + +@cindex Linux +Typically an ns-3 author will work in Linux or a Linux-like +environment. For those running under Windows, there do exist environments +which simulate the Linux environment to various degrees. The ns-3 +project supports development in the Cygwin and the MinGW environments for +these users. See @uref{http://www.cygwin.com/} and +@uref{http://www.mingw.org/} for details on downloading and using these +systems. Cygwin provides many of the popular Linux system commands. +It can, however, sometimes be problematic due to the way it +actually does its emulation, and sometimes interactions with other Windows +software can cause problems. + +@cindex Cygwin +@cindex MinGW +If you do use Cygwin or MinGW; and use Logitech products, we will save you +quite a bit of heartburn right off the bat and encourage you to take a look +at the @uref{http://www.mingw.org/MinGWiki/index.php/FAQ,,MinGW FAQ}. + +@cindex Logitech +Search for ``Logitech'' and read the FAQ entry, ``why does make often +crash creating a sh.exe.stackdump file when I try to compile my source code.'' +Believe it or not, the @code{Logitech Process Monitor} insinuates itself into +every DLL in the system when it is running. It can cause your Cygwin or +MinGW DLLs to die in mysterious ways and often prevents debuggers from +running. Beware of Logitech. + +@subsection Idioms and Design Patterns + +@cindex idiom +In any system, there are a number of problems to be solved that happen +repeatedly. Often the solutions to these problems can be generalized and +applied in a similar way across the system. These solutions are called +Design Patterns. The ns-3 system relies on several classic design +patterns. + +@cindex design pattern +Also, in any language, there are constructs that, while they aren't part of the +language per se, are commonly found and useful. For example, at the lowest +level a C programmer should be able to immediately recognize the purpose and +intent of the following code without having to reflect on the details: + +@verbatim + for (;;) +@end verbatim + +These low-level constructs, or idioms, extend upward in complexity, eventually +becoming implementations of design patterns. As you are exposed to more +and more of the ns-3 system, you will begin to recognize and be +comfortable with the C++ implementations (idioms) of several important design +patterns. + +@cindex functor +@cindex callback +@cindex smart pointer +The ns-3 code relies heavily on +@emph{Generalized Functors, Callbacks, +Smart Pointers, Singletons, and Object Factories}. Although we will +not assume any detailed knowledge of the idioms and design patterns used +in the ns-3 +system, it will be useful for readers who intend to delve deeply into the +system to understand some important related concepts. We recommend two +resources: @uref{http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612/,,Design Patterns: Elements of Reusable Object-Oriented Software, Gamma et. al.} and +@uref{http://www.amazon.com/exec/obidos/ASIN/0201704315,,Modern C++ Design: Generic Programming and Design Patterns Applied, Alexandrescu}. + +Gamma addresses the abstract design patterns, and Alexandrescu addresses the +C++ idioms you will often see throughout the ns-3 code. + +@cindex template +Almost any use of ns-3 will require some basic knowledge of C++ +templates. +We will discuss the high-level uses in this tutorial. However, if you venture +deeply into the source code, you will see fairly heavy use of relatively +sophisticated C++ templates in some of low-level modules of the system. The +You don't have to be a template guru to complete this tutorial but if you +expect to work in ns-3 within the simulation core, you will have to be +somewhat fluent +with templates. If you want to truly grok C++ templates we recommend, +@uref{http://www.amazon.com/Templates-Complete-Guide-David-Vandevoorde/dp/0201734842/,,C++ Templates: The Complete Guide, Vandevoorde and Josuttis}. + +@node Socket-Programming +@section Socket Programming + +@cindex sockets +We will assume a basic facility with the Berkeley Sockets API in the examples +used in this tutorial. If you are new to sockets, we recommend reviewing the +API and some common usage cases. For a good overview of programming TCP/IP +sockets we recommend @uref{http://www.elsevier.com/wps/product/cws_home/680765,,Practical TCP/IP Sockets in C, Donahoo and Calvert}. + +There is an associated web site that includes source for the examples in the +book, which you can find at: +@uref{http://cs.baylor.edu/~donahoo/practical/CSockets/}. + +If you understand the first four chapters of the book (or for those who do +not have access to a copy of the book, the echo clients and servers shown in +the website above) you will be in good shape to understand the tutorial. +There is a similar book on Multicast Sockets, +@uref{http://www.elsevier.com/wps/product/cws_home/700736,,Multicast Sockets, Makofske and Almeroth}. +that covers material you may need to understand for the multicast examples. + +@c ======================================================================== +@c Downloading and Compiling +@c ======================================================================== + +@node Downloading and Compiling +@chapter Downloading and Compiling + +@cindex Linux +@cindex Cygwin +@cindex GNU +@cindex toolchain +From this point forward, we are going to assume that the reader is working in +Linux or a Linux emulation environment (Linux, Cygwin, etc.) and has the GNU +toolchain installed and verified. + +@cindex Mercurial +@cindex Waf +We are going to assume that you have Mercurial and Waf installed and running +on the target system as described in the Getting Started section of the +ns-3 web site: @uref{http://www.nsnam.org/getting_started.html}. + +@section Downloading +@cindex tarball +The ns-3 code is available in Mercurial repositories on the server +code.nsnam.org. You can download a tarball, but we recommend working with +Mercurial --- it will make your life easier in the long run. + +@cindex repository +If you go to the following link: @uref{http://code.nsnam.org/}, +you will see a number of repositories. Many are the private repositories of +the ns-3 development team. The repositories of interest to you +will be +prefixed with ``ns-3''. The current development snapshot (unreleased) of +ns-3 may be found at: @uref{http://code.nsnam.org/ns-3-dev/}. + +The developers attempt to keep this repository in a consistent, working state +but it is a development area with unreleased code present, so you may want to +consider downloading an official release. + +There will be a number of released repositories present at code.nsnam.org. +These repos will have names like ns-3.0.1 --- which referes to release 3.0.1 +of the network simulator (or if you like, release 0.1 of ns-3). +Since the releases are changing at a rate of one per month, I will stick with +the more constant ns-3-dev here, but you can replace the string ns-3-dev with +your choice of release (e.g., ns-3.0.5) below. You can find the latest +version of the code either by inspection of the repository list or by going +to the ``Getting Started'' web page and looking for the latest release +identifier. + +One practice is to create a directory called @code{repos} in one's home +directory under which one can keep local Mercurial repositories. +@emph{Hint: we will +assume you do this later in the tutorial.} If you adopt that approach, you +can get a copy of any of the development versions of ns-3 by typing +the following into your Linux shell (assuming you have installed Mercurial): + +@verbatim + cd + mkdir repos + cd !$ + hg clone http://code.nanam.org/ns-3-dev +@end verbatim + +As the hg command executes, you should see something like the following, + +@verbatim + destination directory: ns-3-dev + requesting all changes + adding changesets + adding manifests + adding file changes + added 1513 changesets with 5687 changes to 733 files + 358 files updated, 0 files merged, 0 files removed, 0 files unresolved +@end verbatim + +After the clone command completes, you should have a directory called +ns-3-dev under your @code{~/repos} directory, the contents of which should +look something like the following: + +@verbatim + AUTHORS RELEASE_NOTES examples/ src/ waf* + LICENSE VERSION ns3/ tutorial/ waf.bat* + README doc/ samples/ utils/ wscript +@end verbatim + +You are now ready to build the ns-3 distribution. + +@section Building +@cindex Waf!build +@cindex Waf!configure +@cindex Waf!debug +@cindex Waf!compile +We use Waf to build the ns-3 project. The first thing you +will need to do is to configure the build. For reasons that will become clear +later, we are going to work with debug builds in the tutorial. To explain to +Waf that it should do debug builds you will need to execute the following +command, + +@verbatim + ./waf -d debug configure +@end verbatim + +This runs the copy of Waf in the local directory (which is provided as a +convenience for you). As the build system checks for various dependencies +you should see output that looks similar to the following, + +@verbatim + ~/repos/ns-3-dev >./waf -d debug configure + Checking for program g++ : ok /usr/bin/g++ + Checking for program cpp : ok /usr/bin/cpp + Checking for program ar : ok /usr/bin/ar + Checking for program ranlib : ok /usr/bin/ranlib + Checking for compiler could create programs : ok + Checking for compiler could create shared libs : ok + Checking for compiler could create static libs : ok + Checking for flags -Wall : ok + Checking for flags -O2 : ok + Checking for flags -g -DDEBUG : ok + Checking for flags -g3 -O0 -DDEBUG : ok + Checking for g++ : ok + Checking for header stdlib.h : ok + Checking for header stdlib.h : ok + Checking for header signal.h : ok + Checking for high precision time implementation: 128-bit integer + Checking for header stdint.h : ok + Checking for header inttypes.h : ok + Checking for header sys/inttypes.h : not found + Configuration finished successfully; project is now ready to build. + ~/repos/ns-3-dev > +@end verbatim + +The build system is now configured and you can build the debug versions of +the ns-3 programs by simply typing, + +@verbatim + ./waf check +@end verbatim + +You will see many Waf status messages displayed as the system compiles. The +most important is the last one, + +@verbatim + Compilation finished successfully +@end verbatim + +and you will see a number of software unit tests subsequently execute. + +@section Running a Script +@cindex Waf!run +We typically run scripts under the control of Waf. This allows the build +system to ensure that the shared library paths are set correctly and that +the libraries are available at run time. To run a program, simply use the +@code{run} option in Waf. Let's run the ns-3 equivalent of the hello +world program by typing the following: + +@verbatim + ./waf --run hello-simulator +@end verbatim + +Waf first checks to make sure that the program is built correctly and +executes a build if required. Waf then then executes the program, which +produces the following output. + +@verbatim + Hello Simulator +@end verbatim + +If you want to run programs under another tool such as gdb or valgrind, +see this @uref{http://www.nsnam.org/wiki/index.php/User_FAQ#How_to_run_NS-3_programs_under_another_tool,,wiki entry}. + +@emph{Congratulations. You are now an ns-3 user.} + +@c ======================================================================== +@c Some Prerequisites +@c ======================================================================== + +@node Some-Prerequisites +@chapter Some Prerequisites + +The first thing we need to do before actually starting to code is to explain +a few core concepts, abstractions and idioms in the system. Much of this may +appear transparently obvious to some, but we recommend taking the time to read +through this chapter just to ensure you are starting on a firm foundation. + +@section Abstractions + +In this section, we'll review some terms that are commonly used in +networking, but have a specific meaning in ns-3. + +@subsection Node +@cindex Node +In Internet jargon, a computing device that connects to a network is called +a @emph{host} or sometimes an @emph{end system}. Because ns-3 is a +@emph{network} simulator, not specifically an @emph{Internet} simulator, we +intentionally do not use the term host since it is closely associated with +the Internet and its protocols. Instead, we use a more generic term also +used by other simulators that originates in Graph Theory --- the @emph{node}. + +@cindex Node!class +In ns-3 the basic computing device abstraction is called the +node. This abstraction is represented in C++ by the class @code{Node}. The +@code{Node} class provides methods for managing the representations of +computing devices in simulations. Developers are expected to specialize the +@code{Node} in the object-oriented programming sense to create new computing +device models. In this tutorial, we will use a specialization of class +@code{Node} called @code{InternetNode}. As you might expect, the +@code{InternetNode} is a class that represents a host in the Internet sense, +and automatically provides core IPv4 networking protocols. + +You should think of a @code{Node} as a computer to which you will add +functionality. One adds things like applications, protocol stacks and +peripheral cards with their associated drivers to enable the computer to do +useful work. We use the same basic model in ns-3. + +@subsection Application +@cindex Application +Typically, computer software is divided into two broad classes. @emph{System +Software} organizes various computer resources such as memory, processor +cycles, disk, network, etc., according to some computing model. System +software usually does not use those resources to complete tasks that directly +benefit a user. A user would typically run an @emph{application} that acquires +and uses the resources controlled by the system software to accomplish some +goal. + +@cindex system call +Often, the line of separation between system and application software is made +at the privilege level change that happens in operating system traps. +In ns-3 there is no real concept of operating system and especially +no concept of privilege levels or system calls. We do, however, have the +idea of an application. Just as software applications run on computers to +perform tasks in the ``real world,'' ns-3 applications run on +ns-3 @code{Node}s to drive simulations in the simulated world. + +@cindex Application!class +In ns-3 the basic abstraction for a user program that generates some +activity to be simulated is the application. This abstraction is represented +in C++ by the class @code{Application}. The @code{Application} class provides +methods for managing the representations of our version of user-level +applications in simulations. Developers are expected to specialize the +@code{Application} in the object-oriented programming sense to create new +applications. In this tutorial, we will use specializations of class +@code{Application} called @code{UdpEchoClient} and @code{UdpEchoServer}. +As you might expect, these applications compose a client/server application set +used to generate and echo simulated network packets + +@subsection Channel +@cindex Channel + +In the real world, one can connect a computer to a network. Often the media +over which data flows in these netowrks are called @emph{channels}. When +you connect your Ethernet cable to the plug in the wall, you are connecting +your computer to an Ethernet communication channel. In the simulated world +of ns-3 one connects a @code{Node} to an object representing a +communication channel. Here the basic communication subnetwork abstraction +is called the channel and is represented in C++ by the class @code{Channel}. + +The @code{Channel} class provides methods for managing communication +subnetwork objects and connecting nodes to them. They may also be specialized +by developers in the object oriented programming sense. A @code{Channel} +specialization may model something as simple as a wire. The specialized +@code{Channel} can also model things as complicated as a large Ethernet +switch, or three-dimensional space in the case of wireless networks. + +We will use specialized versions of the @code{Channel} called +@code{CsmaChannel} and @code{PointToPointChannel} in this tutorial. The +@code{CsmaChannel}, for example, models a version of a communication subnetwork +that implements a @emph{carrier sense multiple access} communication medium. +This gives us Ethernet-like functionality. + +@subsection Net Device +@cindex NetDevice +@cindex Ethernet + +It used to be the case that if you wanted to connect a computers to a network, +you had to buy a specific kind of network cable and a hardware device called +(in PC terminology) a @emph{peripheral card} that needed to be installed in +your computer. These cards were called Network Interface Cards, or +@emph{NIC}s. Today most computers come with the network controller hardware +built in and users don't see these building blocks. + +A NIC will not work without a software driver to control the hardware. In +Unix (or Linux), a piece of peripheral hardware is classified as a +@emph{device}. Devices are controlled using @emph{device drivers}, and network +devices (NICs) are controlled using @emph{network device drivers} +collectively known as @emph{net devices}. In Unix and Linux you refer +to these net devices by names such as @emph{eth0}. + +In ns-3 the @emph{net device} abstraction covers both the software +driver and the simulated hardware. A net device is ``attached'' to a +@code{Node} in order to enable the @code{Node} to communicate with other +@code{Node}s in the simulation via @code{Channel}s. Just as in a real +computer, a @code{Node} may be connected to more than one @code{Channel} via +multiple @code{NetDevice}s. + +The net device abstraction is represented in C++ by the class @code{NetDevice}. +The @code{NetDevice} class provides methods for managing connections to +@code{Node} and @code{Channel} objects; and may be specialized by developers +in the object-oriented programming sense. We will use the specialized version +of the @code{NetDevice} called the @code{CsmaNetDevice} in this tutorial. +Just as an Ethernet NIC is designed to work with an Ethernet network, the +@code{CsmaNetDevice} is designed to work with a @code{CsmaChannel}. + +@subsection Topology Helpers +In a real network, you will find host computers with added (or built-in) +NICs. In ns-3 we would say that you will find @code{Nodes} with +attached @code{NetDevices}. In a large simulated network you will need to +arrange many connections between @code{Node}s, @code{NetDevice}s and +@code{Channel}s. + +Since connecting a @code{NetDevice} to a @code{Node}, and a @code{NetDevice} +to a @code{Channel} is such a common task in ns-3 we provide what we +call @emph{topology helpers} to make this as easy as possible. Topology +helpers perform much of the dirty work of creating and connecting net devices. +For example, it may take several distinct method calls to create a NetDevice, +add a MAC address, connect the net device to a @code{Node} and configure +the protocol stack, and then connect the @code{NetDevice} to a @code{Channel}. +We use topology helper functions to compose those distinct operations into +an easy to use model. + +Topology helper functions use the abstractions (described above) of Network +Interface Cards and Cables. When you think of adding a new kind of network, +you may think of going out to the local computer retailer and buying a kit. +This kit might include a nework cable and some number of peripheral cards and +thier associated software drivers. You can think of topology helpers in +roughly the same way. Instead of buying a kit for a given type of network, +you will use a topology helper class for a given type of network, to accomplish +the equivalent of installing the network ``kit.'' + +@section Important Idioms +Now that we have identified that there are C++ classes in the system called +@code{Node} and @code{InternetNode}, we need to understand how to bring +objects of these classes into existance, and manage their lifetimes. Let's +examine this in some detail here. + +@cindex InternetNode +@cindex CreateObject +@cindex Ptr +In ns-3, if we want to create an @code{InternetNode} in a +script, we will +typically do something like the following example: + +@verbatim + Ptr p = CreateObject (); +@end verbatim + +@cindex smart pointer +To some, it may seem intuitively obvious that we're creating an +@code{InternetNode} object and assigning responsibility for managing the +object to a smart pointer named @code{p}. For the rest of us, there may be +a lot in that line that is unfamiliar, so let's look at what this line means +in some detail. + +@subsection Templates 101 +@cindex template +If you are familiar with C++ templates, you may skip this section as it is +just a cursory introduction to function and class templates. + +Referring back to the example line of code, reproduced below for your +convenience, the angle brackets you see in the code indicate that we are +using C++ @emph{templates}. + +@verbatim + Ptr p = CreateObject (); +@end verbatim + +The purpose of templates is to allow a programmer to write one version of code +that is applicable over multiple types. Some people consider templates to be +an enhancement of the C preprocessor macro functionality. At some level +this comparison reveal some similarities, but C++ templates are really +quite different. + +@cindex template!declaration +@cindex template!definition +@cindex template!use +In C++, just as with most language constructs, templates are @emph{declared}, +@emph{defined} and @emph{used}. A declaration of a template might look +something like, + +@verbatim + template T Add (T first, T second); +@end verbatim + +@cindex template!typename +This line uses the keyword @code{template} followed by a declaration of a +type name (in this case @code{T}) in angle brackets. The angle brackets +should indicate to you that a template is being declared, defined or used. +The type name @code{T} can be thought of as a string that will be substitited +during the use phase of the template. For example, the @code{T} may be +replaced by the word @code{int}. It is this substitution that leads people +to compare templates with macros. + +Without going into too much more detail, this snippet declares that a piece +of code exists that will be able to call a function @code{Add} that will +add arbitrary types together. The @code{T} will be eventually replaced by +a C++ data type name. For example, + +@verbatim + T Add (T first, T second); +@end verbatim + +might eventually become + +@verbatim + int Add (int first, int second); +@end verbatim + +If the template has been declared, we need to @emph{define} what that piece of +code will actually do. That might look something like, + +@verbatim + template + T Add (T first, T second) + { + return first + second; + } +@end verbatim + +All we've done here is to provide an implementation of the template that +adds the two variables together and returns the result. Note that this +implementation works for any type that provides an @code{operator+}. + +The puzzle all comes together when you understand that @emph{using} a template +causes the compiler to automatically instantiate code for a specific function +according to the given template parameters. You might use the above template +like, + +@verbatim + int x, y, z; + z = Add (x, y); +@end verbatim + +@cindex template!instantiate +When the compiler sees @code{Add} it understands that it needs to make +sure that code is instantiated (created) to perform the @code{Add} using the +specified type @code{}. To a first approximation, the compiler will +replace the typename @code{T} with the specified type @code{int} and +automagically generate code equivalent to, + +@verbatim + int Add (int first, int second) + { + return first + second; + } +@end verbatim + +A user of the template definition could just as easily have provided a use +that assigned the type float. This would simply be done like, + +@verbatim + float x, y, z; + z = Add (x, y); +@end verbatim + +In this case, the compiler would automatically generate code that looked like, + +@verbatim + float Add (float first, float second) + { + return first + second; + } +@end verbatim + +@cindex template!function +This particular kind of template programming uses what are called +@emph{function templates}. They are called function templates since you +are @emph{templating} function declarations and definitions. + +@cindex template!class +Templates can also be used in conjunction with classes, in which case you are +said to be using, not too surprisingly, @emph{class templates}. The syntax and +use is similar. To declare a class template you might use something like, + +@verbatim + template + class MyStack + { + void Push (T data); + T Pop (void); + }; +@end verbatim + +The methods can be defined separately in a method similar to function template +definitions, + +@verbatim + template void MyStack::Push (T data) + { + ... + }; +@end verbatim + +You can then use the new templated class in the following way, + +@verbatim + int x, y; + + MyStack stack; + stack.Push (x); + y = stack.Pop (); +@end verbatim + +Similarly to the function template case, the compiler knows that it has to +automatically generate code to fill out the class and method declarations +and definitions using the appropriate type specified by @code{}. + +@node Smart Pointers 101 +@subsection Smart Pointers 101 +If you are familiar with C++ smart pointers, you may skip this section as it +is just a cursory introduction to smart pointers and intrusive reference +counting. + +@cindex smart pointer +Referring back to the example line of code, partially reproduced below for +your convenience below, the left hand side is the declaration and +initialization of a class template that implements a @emph{smart pointer}. + +@verbatim + Ptr p = ... +@end verbatim + +To a first approximation, you can think of @code{Ptr} as the a new kind +of declaration of a pointer to a @code{Node} object. The difference is that +a smart pointer is a user-defined data type (instantiated via a templated +class) that @emph{simulates} a classical pointer but provides additional +features. As an aside, you typically pronounce @code{Ptr} as +``pooter node'' where pooter rhymes with footer. + +@cindex memory management +One of the most important ``additional feature'' provided by smart pointers is +automatic memory management. Since you now understand class templates, you +will understand how the template allows us to write the pointer code once, but +allows us to point to many different kinds of objects. Later in the tutorial +you will see variations such as @code{Ptr} and @code{Ptr}, +which are smart pointers to an IP version 4 object and a channel object, +respectively. + +The use of built-in pointers in C and C++ is a major source of bugs. Constant +allocation of, passing of responsibility for, and deallocation of underlying +data makes it very likely that errors will occur. In one of these errors, +the usual problem is that the responsibility for deallocating a memory block +is misplaced. This may result in a memory leak or a duplicate deallocation. +Smart pointers try to prevent this kind of problem by working with the +@emph{scope} and @emph{extent} rules of the language to make memory +deallocation automatic. + +The scope of a variable defines where in a program a given variable may be +referred to. The extent of a variable defines when in the program's execution +the variable has a valid value. Consider a simple subroutine that contains a +smart pointer. + +@verbatim + void SimpleSubroutine (void) + { + Ptr p; + } +@end verbatim + +@cindex scope +The variable named @code{p} has a scope limited to the subroutine itself. The +variable is said to @emph{come into scope} as the subroutine is entered during +execution. At this time, the constructor of the underlying class is executed +and a valid variable is available for use. When the subroutine is done +executing, the variable is said to @emph{go out of scope}. This causes the +destructor of the underlying class to be executed and the variable no longer +has a valid value. This is not a problem since it is no longer valid to refer +to the parameter. Smart pointers take advantage of these defined actions at +points where variables must be valid and become discardable to determine when +underlying data can be freed. + +@cindex reference counting!intrusive +The ns-3 smart pointer mechanism uses a mechanism called intrusive +reference counting to determine when a memory block should be automatically +deallocated. The term ``intrusive'' means that a reference count (a count of +variables required to have valid data) is stored in the object being managed +instead of in a proxy object. This means that each piece of memory managed by +a ns-3 smart pointer includes a reference count. When a smart +pointer to a reference counted object is created, this reference count is +incremented. This indicates that a new variable requires a valid data object +be present. When a smart pointer to a reference counted object is destroyed +(for example, when going out of scope) the reference count of the managed +object is decremented. When the reference count goes to zero it means that +all smart pointers to the underlying object have gone out of scope and the +object is no longer needed by any past ``users'' of the object. This in turn +means that the object can be safely deallocated, and this is done +automatically for you as the ``last'' smart pointer goes out of scope. + +Consider how this might work as you pass a smart pointer to an object down +a protocol stack. At each level of the stack, you pass the smart pointer +by value. This causes a copy of the smart pointer to be made, which +increments the reference count of the underlying object. When the +@emph{calling} method is done executing, the calling smart pointer goes out of +scope and the reference count is decremented. This leaves the single smart +pointer in the @emph{called} method with a reference to the underlying object. +When the smart pointer in the called method goes out of scope, the destructor +for the smart pointer is called. The destructor checks the reference count +of the underlying object and sees that it becomes zero. This indicates that +the object can be deallocated, and the destructor does so. This results in +the lifetime management of the underlying object being automatically managed, +a boon if you have experience with ``manual'' memory management and finding +memory leaks. + +Now, we want to make this feature available as widely as possible to objects +in the ns-3 system. The basic operations of the smart pointer class +are the same across any intrusively reference counted object. C++ provides a +mechanism to achieve this kind of generic behavior --- the template. Let's +examine the declaration of the smart pointer in more detail. First consider +the way you might declare and use a built-in pointer. For the sake of +simplicity, just assume that a C++ object of the class @code{MyClass} exists. +Further assume that @code{MyClass} provides one method called @code{method}. +Using built-in pointers, you could do something like the following: + +@verbatim + MyClass *p = ... + p->method (); +@end verbatim + +@cindex smart pointer +One of the key design points of smart pointers is that they should simulate +built-in pointers. In C++ this is done by overloading @code{operator->}, +@code{operator=} and @code{operator*}. To implement a smart pointer we need +to provide a generic class that implements these operators. This generic +class should allow operations that appear as if it were a built-in pointer +to the reference counted object. Typically this is accomplished via a +relatively simple C++ class template. If you are interested in the details +of how this may be accomplished, see Alexandrescu for a good treatment, + +@cindex template +Taking the template as given, in order to declare a smart pointer you will +need to create a smart pointer object and provide the template parameter +needed to instantiate the required code. This parameter will be the name +of the reference counted class to which you want to point. The smart +pointer class overrides @code{operator=} which allows initialization of the +smart pointer just as if it were a built-in pointer. The end result is that +you use smart pointers just as if they were built-in pointers: + +@verbatim + SmartPointer p = ... + p->method (); +@end verbatim + +@node Object Creation +@subsection Object Creation +@cindex CreateObject +On the right hand side of the line of code we're examining (reproduced below +for convenience) is the creation of an @code{InternetNode} object. + +@verbatim + ... = CreateObject (); +@end verbatim + +@cindex template!function +This turns out to be an instance of use of a C++ @emph{function template}. The +definition of the @code{CreateObject()} template calls the new +operator to create an object of the type T. It then creates a new smart +pointer of the appropriate type (i.e., @code{Ptr}). This new smart +pointer is assigned initial responsibility for the new object which has its +reference count set to one. + +Since the underlying creation mechanism is via the @code{new} operator, and +you can pass parameters to the constructor for an object, we provide several +templates that you can use for passing parameters to the object constructors. +If the constructor for the object requires a parameter, you simply pass that +parameter to the @code{Create} function like this, + +@verbatim + int parm = 1; + ... = CreateObject (parm); +@end verbatim + +We provide Create templates with up to seven parameters, so you could +conceivably use the @code{Create} template in situations such as, + +@verbatim + int parm = 1; + ... = CreateObject (p1, p2, p3, p4, p5, p6, p7); +@end verbatim + +@subsection Type Safety +Lets take one final look at the now infamous example line of code that we +have been examining for some time (again reproduced below). + +@verbatim + Ptr p = CreateObject (); +@end verbatim + +@cindex smart pointer +@cindex Node +@cindex Create +You may have noticed that the smart pointer on the left hand side of the +assignment is associated with the type @code{Node} and the @code{Create} +template on the right hand side creates an @code{InternetNode} object and +returns a @code{Ptr} smart pointer. For this assignment of a +@code{Ptr} to a @code{Ptr} to work, there must be some +kind of type conversion going on. + +@cindex implicit conversion +Many programmers use @code{implicit conversions} without even realizing it +since they are sometimes so intuitive. For example, in the following code, + +@verbatim + int i = 1; + double d = 2.; + if (n == d) ... +@end verbatim + +@cindex standard conversion +the integer (1) is implicitly converted to a double (1.) before the comparison +takes place. This conversion is performed using what is known as a C++ +@emph{standard conversion}. There are a number of standard conversions defined +by the C++ standard. Among them are, + +@itemize @bullet +@item Integral Promotions +@item Integral Conversions +@item Floating Conversions +@item Pointer Conversions +@item Reference Conversions +@end itemize + +@cindex assignment operator +@cindex Ptr +For the case of interest here, we need to know what happens in the +assignment operator (@code{operator=}) of our smart pointer @code{Ptr}. +This operator takes a reference to a @code{Ptr} and not a reference to +a @code{Ptr}. The one situation where this works automatically +in C++ is if the ``destination'' reference is to a visible, unambiguous base +class of the ``source'' reference. In this case, the underlying pointer is +@emph{cast} from one type to the other automatically. + +To summarize: The magic happens in the assignment operator. Class +@code{InternetNode} inherits from class @code{Node}. The reference to the +@code{InternetNode} object in question is, in essence, a pointer to an +@code{InternetNode} object. The @code{InternetNode} class inherits from the +@code{Node} base class in a way that makes @code{Node} visible and unambiguous. +Therefore, there exists a standard conversion from an @code{InternetNode *} +to a @code{Node *} and by extension from an @code{InternetNode &} to a +@code{Node &}. This conversion is applied automatically (and invisibly) +during paramater passing in the assignment operator we are examining. + +@cindex base class +This is a rather involved way of saying there's an invisible pointer cast +to a base class happening in the assignment. That means that + +@verbatim + Ptr p = CreateObject (); +@end verbatim + +or, + +@verbatim + Ptr p = CreateObject (); +@end verbatim + +will work just fine. Of course, if you try something @emph{bad} (TM), like: + +@verbatim + Ptr p = CreateObject (); +@end verbatim + +the compiler will quite appropriately complain that there is no conversion +between these completely unrelated objects (CsmaChannel and Node). + +@subsection Summary +Going back to our infamous first line of ns-3 code, we said that if +we want to create an InternetNode in a script, we will typically do something +like: + +@verbatim + Ptr p = CreateObject (); +@end verbatim + +@cindex Create +@cindex InternetNode +@cindex smart pointer +Now we know that this is really a simple statement. We create an +@code{InternetNode} object on the heap (indirecly using operator @code{new} +and passing no parameters to its constructor) and assign responsibility for +managing the new object's lifetime to a smart pointer. This smart pointer is +a pointer to a @code{Node} object, so there was a hidden cast from +@code{InternetNode} to a @code{Node} done via a standard C++ conversion. + +This may have been quite a hurdle to get past that first line of code, but +we have covered quite a few of the important idioms that you'll encounter in +this tutorial. + +@c ======================================================================== +@c A First ns-3 script +@c ======================================================================== + +@node A-First-ns-3-Script +@chapter A First ns-3 script +@cindex design pattern +@cindex idiom +Lets build a simple network using the ns-3 design patterns, idioms, +classes and helpers we have just looked at. If you downloaded the system as +was suggested above, you will have a release of ns-3 in a directory +called @code{repos} under your home directory. Change into that directory, +where you should see a directory structure something like the following. + +@verbatim + AUTHORS RELEASE_NOTES examples/ src/ waf* + LICENSE VERSION ns3/ tutorial/ waf.bat* + README doc/ samples/ utils/ wscript +@end verbatim + +@cindex hello-simulator.cc +Change into the tutorial directory. You should see a file named +@code{hello-simulator.cc} located there. Copy this file into one named +@code{simple.cc}. If you open this new file in your favorite editor you will +see some copyright information and the following C++ code: + +@verbatim + #include "ns3/log.h" + + NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); + + using namespace ns3; + + int + main (int argc, char *argv[]) + { + LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO); + + NS_LOG_INFO ("Hello Simulator"); + } +@end verbatim + +This is the ns-3 version of the ubiquitous hello-world program. It +uses the ns-3 Log module to print ``Hello Simulator'' into the + standard error output stream. + +@cindex logging +Log components are named objects that provide for controlling the verbosity of +debugging output in the system. We'll have a lot more to say about logging +later on, but for now you can just consider the macro @code{NS_LOG_INFO} to be +a kind of fancy printf to the standard error. + +@section A Simple Network +@cindex InternetNode +Let's create a simple network of @code{InternetNode} elements. In order to +actually create an @code{InternetNode}, you will have to include some header +files. Put the following code after the include statement in @code{simple.cc}. + +@verbatim + #include "ns3/ptr.h" + #include "ns3/internet-stack.h" +@end verbatim + +@cindex include files +The ns-3 build system places the core include files it needs into a +directory called @code{ns-3} and so whenever you need to include one of the +core files you need to explicitly code this. The file @code{ptr.h} defines +the generic smart pointer that we use. The file @code{internet-stack.h} +defines the class InternetNode which, as described above, represents an IP +version 4-based computing element in the simulator. + +So let's create a few new @code{InternetNode}s by adding the following lines +of code after the call to @code{NS_LOG_INFO} in the simple.cc file right +after the call to @code{NS_LOG_INFO}. + +@verbatim + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + Ptr n3 = CreateObject (); +@end verbatim + +As we now understand, this will create four @code{InternetNode} objects on +the heap and create four @code{Ptr} smart pointer objects on the stack +to manage them. You should remember that by using the smart pointers you are +freed from the responsibility to delete the objects you assign to them. + +@cindex Channel +@cindex CsmaChannel +The next step is to create a channel over which these nodes can communicate. +Let's use the CsmaChannel and create a local area network that will allow us +to hook up nodes similarly to an Ethernet. + +As usual, we'll need to include the file that provides the appropriate class +declarations: + +@verbatim + #include "ns3/csma-channel.h" +@end verbatim + +Next, Add the following line of code (typically done after node creation) to +create a channel with a five megabit per second data rate and a two +millisecond speed-of-light delay between all nodes. The idiom for creating +the channel is similar to that of the node, but the actual @code{Create} +function is hidden from us in the topology code. Observe that we are +using a Csma topology helper function to free us from the details regarding +how the Carrier Sense Multiple Access Channel is actually brought into +existence and initialized. + +@verbatim + Ptr lan = + CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); +@end verbatim + +@cindex idiom!unnamed parameter +You may be unfamiliar with the @emph{unnamed parameter} idiom used here. +When added to a list of parameters, the code @code{DataRate (5000000)} +constructs a DataRate object on the stack using the appropriate constructor. +The resulting object has no name, and therefore cannot be referenced +elsewhere, but is passed to the callee method where it has a valid name and +can be used. This idiom is essentially a shorthand version of the following: + +@verbatim + DataRate rate (5000000); + Time latency (MilliSeconds (2)); + Ptr lan = CsmaTopology::CreateCsmaChannel (rate, latency); +@end verbatim + +@cindex constructor +@cindex constructor!Time +We should pause for a moment and discuss the constructor to the @code{Time} +data type. There are a number of different constructors for these objects, and +so there are a number of ways that this initialization could have been done. +There is a constructor that takes a string argument, consisting of expressions +using the units @code{s, ms, us, ns, ps} or @code{fs}, so this could have been +written, + +@verbatim + Time latency ("2ms"); +@end verbatim + +There are also helper functions available that create time units (one of these +was used in the example): + +@itemize @bullet +@item @code{Seconds (double)} +@item @code{MilliSeconds (uint64_t)} +@item @code{MicroSeconds (uint64_t)} +@item @code{NanoSeconds (uint64_t)} +@item @code{PicoSeconds (uint64_t)} +@item @code{FemtoSeconds (uint64_t)} +@end itemize + +C++ will attempt to promote parameters appropriately, but you will typically +see constructions that respect the type corrrectness of the constructor, as +in @code{Seconds (1.)} and @code{MilliSeconds (2)}. Notice that the code +@code{Seconds (1)} will work just as well as @code{Seconds (1.)} since the +integer 1 will be automatically promoted to a double 1. in the former code. +The converse will not work --- i.e., you cannot write code that says +@code{MilliSeconds (2.)} since a @emph{type demotion} would be required that +could lose information and the compiler will not do such things ``behind your +back.'' Don't be thrown off by this kind of automatic conversion. + +@cindex MAC!address +Okay, now we have code to create four nodes and a local area network. The +next step is to wire the network together. We do this by adding net devices +to the node. When we add the net device, we also specify the network to which +the net device is connected and provide a MAC address appropriate to the +device and network types. Since we're creating an IP version 4 network using +a Csma channel, you may expect that we'll be using topology helpers +appropriate to those types --- the CsmaIpv4Topology helper. As you may expect, +we'll need to include some files to get the appropriate definitions: + +@verbatim + #include "ns3/mac48-address.h" + #include "ns3/csma-net-device.h" + #include "ns3/csma-topology.h" + #include "ns3/csma-ipv4-topology.h" +@end verbatim + +Now, all that is left is to do the ``wiring'': + +@verbatim + uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, + Mac48Address("08:00:2e:00:00:00")); +@end verbatim + +[Note the additional unnamed parameter idiom usage here.] + +This code calls the topology helper relating to Csma channels and IP version +four nodes. It asks to install a Csma net device ``into'' node zero +(@code{n0}) connecting the device to the channel named (@code{lan}). It also +assigns a MAC address to the net device. You can add similar lines of code +connecting the other nodes to the lan (remembering to assign new MAC +addresses). + +@verbatim + uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, + Mac48Address("08:00:2e:00:00:01")); + + uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, + Mac48Address("08:00:2e:00:00:02")); + + uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, + Mac48Address("08:00:2e:00:00:03")); +@end verbatim + +@cindex IP!address +@cindex IP!network mask +@cindex multihome +Finally, we need to add IP addresses to our nodes. The pointers to the +nodes are stored in n0, n1, n2 and n3. We added net devices to each of +the nodes and remembered the net device index numbers as nd0, nd1, nd2 and +nd3. You can add multiple net devices to each node resulting in a situation +similar to a multi-homed host. Each time you add a net device, you will get +a new index. Since the IP address for a multi-homed host is associated with +a net device, we need to provide that index (which we have saved) to the +topology helper. We provide an IP version four address via the ns-3 +class @code{Ipv4Address} which takes a dotted decimal string as a constructor +parameter. We also provide a network mask using the ns-3 class +@code{Ipv4Mask} which also takes a dotted decimal string. The code to +perform the IP address assignment, then, looks like the following: + +@verbatim + CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), + Ipv4Mask ("255.255.255.0")); +@end verbatim + +We have now constructed a simulated network. Your code should now look +something like the following, + +@verbatim + #include "ns3/log.h" + #include "ns3/ptr.h" + #include "ns3/internet-stack.h" + #include "ns3/csma-channel.h" + #include "ns3/mac48-address.h" + #include "ns3/csma-net-device.h" + #include "ns3/csma-topology.h" + #include "ns3/csma-ipv4-topology.h" + + NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); + + using namespace ns3; + + int + main (int argc, char *argv[]) + { + LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO); + + NS_LOG_INFO ("Hello Simulator"); + + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + Ptr n3 = CreateObject (); + + Ptr lan = + CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); + + uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, + Mac48Address("08:00:2e:00:00:00")); + + uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, + Mac48Address("08:00:2e:00:00:01")); + + uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, + Mac48Address("08:00:2e:00:00:02")); + + uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, + Mac48Address("08:00:2e:00:00:03")); + + CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), + Ipv4Mask ("255.255.255.0")); + } +@end verbatim + +This script won't actually do anything yet. The next trick will be to +convince our nodes to try and send some data over the network. + +@section Using Applications +@cindex Create +As mentioned above, we use @code{Application}s in ns-3 to generate +the data used to drive simulations. An @code{Application} is added to a +ns-3 node conceptually just as if you would add an application to a +computer. When an application is created (using the @code{Create} template) +we tell the application which @code{Node} it belongs to (and therefore on +which node it is running) by passing a smart pointer to that @code{Node} in +the constructor arguments. + +@subsection A UDP Echo Client Application +To use an application, we first have to load the header file in which it is +defined. For the UDP echo client, this would mean adding the line, + +@verbatim +#include "ns3/udp-echo-client.h" +@end verbatim + +In order to create the UDP echo client application we will need to add the +following code: + +@verbatim + uint32_t packetSize = 1024; + uint16_t port = 7; + uint32_t maxPacketCount = 1; + Time interPacketInterval = Seconds (1.); + + Ptr client = CreateObject (n0, "10.1.1.2", + port, maxPacketCount, interPacketInterval, packetSize); +@end verbatim + +@cindex packet +The first four lines have broken out the configuration parameters for the +application as named parameters for clarity. We are telling the application +to generate 1024 byte packets (@code{packetSize = 1024}); and to send these +packets to port 7 (@code{port = 7;}). The application is told to send at most +one packet (@code{maxPacketCount = 1;}); and to delay for one second between +packet sends (@code{interpacketInterval = Seconds(1.)}) which is not used since +only one packet is sent. We will defer addressing the type @code{Time} until +we discuss the simulator engine. For now just understand the semantics are +to wait for one second. + +The code to actually create the @code{UdpEchoClient} application uses the +same creation idiom as we have used previously. Notice that we have a case +where the @code{Create} template is used to pass parameters to the constructor +of the underlying object. + +@cindex implicit conversion sequence +Notice that a string is passed as the second parameter. The formal parameter +to the constructor of the @code{UdpEchoClient} object is actually an +@code{Ipv4Address}. We get away with this since C++ allows what are called +@emph{implicit conversion sequences} to occur between the argument in the +function call and the corresponding parameter in the function declaration. +Basically, C++ will try to figure out a way to convert parameters for you +transparently. + +In this case the conversion sequence is based on the constructor for the +Ipv4Address that takes a @code{char const *} as a parameter. C++ notices +that @code{"10.1.1.2"} refers to a @code{char const *} and knows that it +needs to get from there to an @code{Ipv4Address}. The compiler notices that +there is an @code{Ipv4Address} constructor that takes a @code{char const *} +and so it uses that constructor transparently to arrange for the conversion. + +You therefore have several options for passing this value. You can use an +explicit named variable as in the following: + +@verbatim + Ipv4Address addr ("10.1.1.2"); + ... + + Ptr client = CreateObject (n0, addr, port, + maxPacketCount, interPacketInterval, packetSize); +@end verbatim + +@cindex idiom|unnamed parameter +You can use the unnamed parameter idiom that we have previously seen: + +@verbatim + Ptr client = CreateObject (n0, + Ipv4Address ("10.1.1.2"), port, maxPacketCount, interPacketInterval, + packetSize); +@end verbatim + +Or you can rely on implicit conversion sequences as we just saw: + +@verbatim + Ptr client = CreateObject (n0, "10.1.1.2", + port, maxPacketCount, interPacketInterval, packetSize); +@end verbatim + +Which approach to take is a matter of style, really, and you will probably +see all three approaches taken in the ns-3 code. You should be +comfortable seeing and using all three methods. + +@subsection A UDP Echo Server Application +As usual, to use the UDP echo server we need to add a line to define the +application: + +@verbatim +#include "ns3/udp-echo-server.h" +@end verbatim + +In order to create the UDP echo server application we will need to add the +following code: + +@verbatim + Ptr server = CreateObject (n1, port); +@end verbatim + +We only need to tell the application which node to reside on and which port +to listen on for UDP packets. The code to actually create the +@code{UdpEchoServer} application uses the now quite familiar ns-3 object +creation idiom. + +@subsection A UDP Echo Client-Server Simulation +Now we're getting somewhere. Your code should look something like the +following (let's change the log component name and program banner from +``Hello Simulator''to something more descriptive while we're at it). + +@verbatim + #include "ns3/log.h" + #include "ns3/ptr.h" + #include "ns3/internet-stack.h" + #include "ns3/csma-channel.h" + #include "ns3/mac48-address.h" + #include "ns3/csma-net-device.h" + #include "ns3/csma-topology.h" + #include "ns3/csma-ipv4-topology.h" + #include "ns3/udp-echo-client.h" + #include "ns3/udp-echo-server.h" + + NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); + + using namespace ns3; + + int + main (int argc, char *argv[]) + { + LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); + + NS_LOG_INFO ("UDP Echo Simulation"); + + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + Ptr n3 = CreateObject (); + + Ptr lan = + CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); + + uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, + Mac48Address("08:00:2e:00:00:00")); + + uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, + Mac48Address("08:00:2e:00:00:01")); + + uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, + Mac48Address("08:00:2e:00:00:02")); + + uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, + Mac48Address("08:00:2e:00:00:03")); + + CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), + Ipv4Mask ("255.255.255.0")); + + uint32_t packetSize = 1024; + uint16_t port = 7; + uint32_t maxPacketCount = 1; + Time interPacketInterval = Seconds (1.); + + Ptr client = CreateObject (n0, "10.1.1.2", + port, maxPacketCount, interPacketInterval, packetSize); + + Ptr server = CreateObject (n1, port); + + } +@end verbatim + +@section Using the Simulation Engine +@cindex model +@cindex simulation executive +You could say that the heart of the ns-3 system is the +@emph{simulation engine} (sometimes called the simulation executive in other +systems). + +In a computer simulation, a computer @emph{model} of a real world @emph{system} +is constructed. This is typically done to minimize cost since you do not have +to actually buy, install and maintain physical hardware. In the case of +ns-3, a model is a representation of a networking component that is +designed to imitate some number of important behaviors or characteristics of +an actual component in a real network. A system is a collection of models +arranged for the purpose of analyzing some behavior. + +@section Models +@cindex CsmaNetDevice +@cindex CsmaChannel +@cindex InternetNode +@cindex NIC +@cindex CSMA +We have already encountered several ns-3 models without specifically +calling them so. The @code{InternetNode}, @code{CsmaNetDevice} and +@code{CsmaChannel} objects are models of an Internet computing node, a CSMA +network interface card (NIC), and a network cable able to move data to and +from other CSMA NICs. + +@cindex model +@cindex CSMA/CD +It is important to note that the @code{Csma} net devices and the @code{Csma} +channel do not correspond to any real world hardware that you can actually go +out and buy. These models implement an approximation, or subset, of the +behaviors that a real CSMA/CD network would have. In this case, the +@code{CsmaNetDevice} does not simulate collision detection (CD). It does +implement carrier sense and performs collision @emph{avoidance} using global +spatial knowledge available in the channel. This would be impossible in any +channel residing in our universe. + +@cindex Ethernet +No model will fully implement @emph{all} of the behaviors of a piece of +hardware. It is important to understand what is being modeled by the +ns-3 components you are using and what is not. For example, the Csma +components we use in this tutorial model a highly abstract multiple access +network that is topologically equivalent to an Ethernet. It is not necessarily +true that results found in a simulation using the Csma models will apply to +a real-world Ethernet network. You must understand what behaviors are +simulated in each of the models before trusting that any results can be +associated with real-world systems. + +@section Time, Events and Callbacks +@cindex time +@cindex event +In a @emph{discrete event simulator} time is not something that @emph{flows}, +nor is it something to be measured --- it is the driving force behind the +progress of the simulation. Time is progressed forward by the simulation +engine and anything that happens in the simulation is ultimately caused by +an @emph{event}. An event is some action in the system that is +@emph{scheduled} to happen at a certain time by the simulation engine. Time +does not flow continuously but steps discretely (in possibly large jumps) +from one scheduled event to another. + +@cindex packet +For example, to start the flow of a packet through the system, one would have +to schedule an event with the simulation engine @emph{before} the simulation +was started. This is important since the simulation engine only jumps time +forward if there is a next event to process. The simulation stops if there +are no more events, which is equivalent to a state where there is ``nothing +more to do.'' Before the simulation starts, one schedules driving events in +terms of absolute time. For example, one could schedule an event to start +the flow of a first packet at, say, ten simulated seconds. In this case, the +simulation would start its clock at zero seconds and look for the first event +in its @emph{event queue}. It would immediately jump time forward by ten +seconds and @emph{fire} the scheduled event --- that is, make the event happen. + +@cindex functor +@cindex function object +@cindex callback +@cindex Callback +In ns-3 an event is basically a pre-packaged function call called a +@emph{functor}. Functors are also known as @emph{function objects}, which is +a more descriptive term --- an object (in the object-oriented programming +sense) that can be called as if it was a function. Typically one uses a +functor to implement @emph{deferred execution} of a function or method. The +most commonly encoutered form of deferred execution is in a @emph{callback} +from an I/O system. In this case, the goal would be to start an I/O +operation and return immediately, without having to wait for the operation +to complete. One asks the I/O subsytem to notify you when an operation is +complete by calling some function you provide. This provided function is +known as a callback function. [Imagine calling someone on the telephone and +asking them to do something for you. You also ask them to @emph{call you back} +when they are done.] Events in the ns-3 system work conceptually +the same way, except that instead of an I/O completion driving the process, +the arrival of some simulated time drives the process. The ns-3 +deferred exectution mechanism is via a class called @code{Callback}. + +@cindex Time +@cindex Callback +The internal details of the classes representing @code{Time} and +@code{Callback} abstractions will be introduced as required. We won't see +events directly for some time, but you should know that they are happening +``under the sheets'' of the simulations you will be writing. + +@section Driving the Simulation +@cindex Application +As mentioned previously, time is the driving force behind the progress of +a ns-3 simulation. Events are scheduled to happen at certain times +by calling methods of the simulation engine, either directly or indirectly +through, for example, an @code{Application}. + +In order to get the simulation engine set up and running in our code, we must +first include the language definitions required to describe time- and +simulator-specific classes: + +@verbatim + #include "ns3/simulator.h" + #include "ns3/nstime.h" +@end verbatim + +@cindex Application +As we have seen, we need to ``seed'' the simulation with at least one event. +In the case of an @code{Application}, a method to do this is provided. This +method must be implemented by each specialization of the class and we must +call this method in our script before the simulation starts. We can also +provide an event (indirectly) to stop the output of the application at a +certain time. This is done by adding the following lines to our script: + +@verbatim + server->Start(Seconds(1.)); + client->Start(Seconds(2.)); + + server->Stop (Seconds(10.)); + client->Stop (Seconds(10.)); +@end verbatim + +@cindex Application +@cindex time +@cindex Time +@cindex socket +@cindex event +In the case of the UdpEchoServer, the call to @code{server->Start ()} gives +the @code{Application} the chance to schedule an event that will perform the +usual @emph{sockets} server sequence of socket creation, binding and +recvfrom (see Donahoo's UDPEchoServer.c). + +In the case of the UdpEchoClient, the call to @code{client->Start ()} gives +the @code{Application} the chance to schedule an event that will perform the +usual @emph{sockets} client sequence of socket creation, sendto and recvfrom +(see Donahoo's UDPEchoClient.c). + +@cindex event +Note that the start event for the server is scheduled to happen before the +start event of the client, just as you would start a server application before +you would attempt to start a client application in the real world. + +@cindex socket!sendto +The ns-3 equivalent of the call to @code{sendo} in the client will +schedule (immediately) the transmission of a UDP packet over the just created +socket. This will cause the packet to percolate down the protocol stack and +eventually into the channel. The channel will schedule a reception event in +the net device on the destination node. This event will eventually percolate +up into the server application. The server application will create a reply +packet and send it back down its stack and eventually back to the channel. +The channel will schedule a reception event back in the client and this will +cause the reply to be sent back up the protocol stack to the client +application. + +The calls to @code{Stop ()} for both applications cause the sockets to be +torn down and therefore the sending and receiving of packets will be stopped +irrespective of other application settings (such as max packets and interval +in the client). + +Finally, we need to run the simulation and when the simulation run is complete, +clean up any resources allocated during the run. This is done by the calling +the following static methods: + +@verbatim + Simulator::Run (); + Simulator::Destroy (); +@end verbatim + +We now have the makings of a complete ns-3 network simulation. The +source code for the script should look like the following: + +@verbatim + #include "ns3/log.h" + #include "ns3/ptr.h" + #include "ns3/internet-stack.h" + #include "ns3/csma-channel.h" + #include "ns3/mac48-address.h" + #include "ns3/csma-net-device.h" + #include "ns3/csma-topology.h" + #include "ns3/csma-topology.h" + #include "ns3/csma-ipv4-topology.h" + #include "ns3/udp-echo-client.h" + #include "ns3/udp-echo-server.h" + #include "ns3/simulator.h" + #include "ns3/nstime.h" + + NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); + + using namespace ns3; + + int + main (int argc, char *argv[]) + { + LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); + + NS_LOG_INFO ("UDP Echo Simulation"); + + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + Ptr n3 = CreateObject (); + + Ptr lan = + CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); + + uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, + Mac48Address("08:00:2e:00:00:00")); + + uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, + Mac48Address("08:00:2e:00:00:01")); + + uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, + Mac48Address("08:00:2e:00:00:02")); + + uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, + Mac48Address("08:00:2e:00:00:03")); + + CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), + Ipv4Mask ("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), + Ipv4Mask ("255.255.255.0")); + + uint32_t packetSize = 1024; + uint16_t port = 7; + uint32_t maxPacketCount = 1; + Time interPacketInterval = Seconds (1.); + + Ptr client = CreateObject (n0, "10.1.1.2", + port, maxPacketCount, interPacketInterval, packetSize); + + Ptr server = CreateObject (n1, port); + + server->Start(Seconds(1.)); + client->Start(Seconds(2.)); + + server->Stop (Seconds(10.)); + client->Stop (Seconds(10.)); + + Simulator::Run (); + Simulator::Destroy (); + } +@end verbatim + +@cindex tutorial-csma-echo.cc +Just to make sure you don't get caught up in debugging typographical errors +we have provided this source code for you (along with a copyright header) in +the @code{tutorial} subdirectory of the ns-3 distribution as +@code{tutorial-csma-echo.cc}. We used this opportunity to do some ``clean up'' +of some of our example cases by passing parameters using implicit conversion +sequences and removing some of the named parameters. [These were used for +pedagogic purposes and were not actually necessary.] + +@section Building the Script +@cindex Waf +C++ is a compiled language, so you know it had to happen. We have to build +the script before we run it. As mentioned before, we use the Waf build system +which is Python-based. We have to change gears slightly and switch ourselves +to Python mode in order to proceed. + +In each subdirectory of the ns-3 distribution in which there are +source files, you will find two files: one will be named @code{waf} and one +will be named @code{wscript}. The former, @code{waf}, is a link that allows +one to start the build process from any subdirectory. We can ignore that one. +The file we need to deal with is @code{wscript}. + +@cindex wscript +Open the file @code{ns-3-dev/tutorial/wscript} in your favorite editor +[remember I'm assuming that you have the distribution saved in a +repository under a directory called @code{repos} in you home directory.] + +@cindex Python +You should see the following Python code (after an emacs mode line). + +@verbatim + def build(bld): + obj = bld.create_ns3_program('hello-simulator') + obj.source = 'hello-simulator.cc' +@end verbatim + +These are the only instructions required to build a simulation (I told you +it wasn't going to be too bad). The line with the method +@code{bld.create_ns3_program} tells the build system to create an object +file that is a program (executable) named @code{hello-simulator}. The +following line, with the method @code{obj.source} tells the build system that +the source file for the program is the file @code{hello-simulator.cc'} in the +local directory. The required libraries are linked for you for free. + +All that needed to be done in order to build the new simulation using the new +source file was to copy the two lines describing the @code{hello-simulator} +program and change the names to @code{tutorial-csma-echo}. You can see these +lines in the @code{wscript} file, + +@verbatim + def build(bld): + obj = bld.create_ns3_program('hello-simulator') + obj.source = 'hello-simulator.cc' + + obj = bld.create_ns3_program('tutorial-csma-echo') + obj.source = 'tutorial-csma-echo.cc' + + ... +@end verbatim + +When you built the system above, you actually already built this new +simulation and a number of other examples. Since you have already configured +@code{Waf} and built the @code{tutorial-csma-echo} script, you can run the +simulation in the same way as you ran the @code{hello-simulator} script using +the @code{waf --run} command: + +@verbatim +~/repos/ns-3-dev/tutorial > waf --run tutorial-csma-echo +Entering directory `~/repos/ns-3-dev/build' +Compilation finished successfully +UDP Echo Simulation +~/repos/ns-3-dev/tutorial > +@end verbatim diff --git a/doc/tutorial/in-process/log.texi b/doc/tutorial/in-process/log.texi new file mode 100644 index 000000000..2f39efe59 --- /dev/null +++ b/doc/tutorial/in-process/log.texi @@ -0,0 +1,24 @@ +@node Logging +@chapter Logging +@anchor{chap:Logging} + +This chapter is the first in a series of chapters discussing things that +one can do to modify the input or output of existing ns-3 scripts. + +Examples: +@itemize @bullet +@item Enable or disable the generation of log messages, with fine granularity +@item Set default values for configuration values in the system +@item Generate a report of all configuration values used during a simulation +run (not yet implemented) +@item Set or get values of member variables on objects already instantiated +@item Customizing the tracing output of the script +@item Generate statistics on (not yet implemented) +@item Perform a large number of independent runs of the same simulation +@end itemize + +@node Logging Basics +@section Logging Basics + +@node Enabling Log Output +@section Enabling Log Output diff --git a/doc/tutorial/in-process/other.texi b/doc/tutorial/in-process/other.texi new file mode 100644 index 000000000..7b24e7809 --- /dev/null +++ b/doc/tutorial/in-process/other.texi @@ -0,0 +1,2189 @@ +@c ======================================================================== +@c Other Network Topologies +@c ======================================================================== + +@node Other-network-topologies +@chapter Other Network Topologies +@cindex topology +@cindex Channel +@cindex NetDevice +@cindex topology!bus +@cindex topology!point-to-point +@cindex PointToPointChannel +@cindex PointToPointNetDevice + +@emph{Network topology} is the study of the arrangement of of the elements +(in @command{ns-3} represented by the classes @code{Channel} and @code{Node}) +of a network. Two fundamental types of physical topologies are the +@emph{point-to-point} and @emph{bus} topologies. We have already been exposed +to the @command{ns-3} channel specialization named @code{CsmaChannel}. This is +a simulation of a bus network. We also provide a simulation of a +point-to-point channel with associated net devices. As described previously, +the associated C++ classes specialize the @command{ns-3} base classes +@code{NetDevice} and @code{Channel} and are called @code{PointToPointNetDevice} +and @code{PointToPointChannel} respectively. + +We will use combinations of these bus and point-to-point topology elements +to show how to create several commonly seen network topologies. + +@section A Point-to-Point Network +We're going to take what might be seen as a step backward and look at a simple +point-to-point network. We will be building the simplest network you can +imagine. A serial link (point to point) between two computers. When you +see this point-to-point network, you can think of an RS-422 (or RS-232 for +you old-timers) cable. This topology is shown below. + +@sp 1 +@center @image{figures/pp,,,,png} + +@cindex CreateObject +@cindex InternetNode +We have provided a file for you in the @code{tutorial} +directory called @code{tutorial-point-to-point.cc}. You should now be +familiar enough with the system to pick out fairly easily what has been +changed. Let's focus on the following lines: + +@verbatim + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + + Ptr link = PointToPointTopology::AddPointToPointLink ( + n0, n1, DataRate (38400), MilliSeconds (20)); + + PointToPointTopology::AddIpv4Addresses (link, n0, "10.1.1.1", + n1, "10.1.1.2"); +@end verbatim + +You can see that we created two @code{InternetNode} objects in the usual way. +Then, instead of creating a @code{CsmaChannel} we create a +@code{PointToPointChannel}. This point-to-point channel, which we call +@code{link}, connects node zero (@code{n0}) and node one (@code{n1}) over a +simulated link that runs at 38400 bits per second and has a 20 millisecond +simulated speed-of-light delay. This call also creates appropriate net devices +and attaches them to nodes zero and one. + +We then add IP addresses to the net devices we just created using the topology +helper @code{AddIpv4Addresses}. Node zero gets the IP address 10.1.1.1 and +node one gets the IP address 10.1.1.2 assigned. + +The alert tutorial user may wonder what the network number or prefix is of +those IP addresses. The point-to-point topology assumes that you want a +@code{/30} subnet and assigns an appropriate net mask for you. It then then +@emph{asserts} that the network numbers of the two net devices match. So there +is an implicit network mask created down in the topology code that looks like, + +@verbatim + Ipv4Mask netmask("255.255.255.252"); +@end verbatim + +The rest of the code you should recognize and understand. We are just going +to echo one packet across the point-to-point link. You should be now be able +to build and run this example and to locate and interpret the ASCII trace +file. This is left as an exercise for you. + +The file @code{tutorial-point-to-point.cc} is reproduced here for your +convenience: + +@verbatim +/* -*- 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/log.h" +#include "ns3/ptr.h" +#include "ns3/internet-stack.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/mac48-address.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/udp-echo-client.h" +#include "ns3/udp-echo-server.h" +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/global-route-manager.h" + +NS_LOG_COMPONENT_DEFINE ("PointToPointSimulation"); + +using namespace ns3; + +// Network topology +// +// point to point +// +--------------+ +// | | +// n0 n1 +// +int +main (int argc, char *argv[]) +{ + LogComponentEnable ("PointToPointSimulation", LOG_LEVEL_INFO); + + NS_LOG_INFO ("Point to Point Topology Simulation"); + + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + + Ptr link = PointToPointTopology::AddPointToPointLink ( + n0, n1, DataRate (38400), MilliSeconds (20)); + + PointToPointTopology::AddIpv4Addresses (link, n0, "10.1.1.1", + n1, "10.1.1.2"); + + uint16_t port = 7; + + Ptr client = CreateObject (n0, "10.1.1.2", + port, 1, Seconds(1.), 1024); + + Ptr server = CreateObject (n1, port); + + server->Start(Seconds(1.)); + client->Start(Seconds(2.)); + + server->Stop (Seconds(10.)); + client->Stop (Seconds(10.)); + + AsciiTrace asciitrace ("tutorial.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + Simulator::Run (); + Simulator::Destroy (); +} +@end verbatim + +@section A Star Network +A point-to-point network is considered a special case of a star network. As +you might expect, the process of constructing a star network is an extension +of the very simple process used for a point-to-point link. We have provided +a file for you in the @code{tutorial} directory called @code{tutorial-star.cc} +that implements a simple star network as seen below. + +@sp 1 +@center @image{figures/star,,,,png} + +In order to create a star network, we need to be able to instantiate some +number (greater than one) of net devices on a node. In the name of simplicity +of use, the @code{PointToPointTopology} topology helper does not allow one to +do this. We provided a separate topology helper class, the +@code{PointToPointIpv4Topology} helper class that provides the slightly finer +granularity we need to accomplish a star network. In order to use this new +helper we have to load the definitions by including the appropriate file. + +@verbatim + #include "ns3/point-to-point-ipv4-topology.h" +@end verbatim + +The star that we're going to create has a node in the center (@code{n0}) with +six nodes surrounding (@code{n1} - @code{n6}). You should be able to easily +find and understand the code that creates these nodes. + +@verbatim + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + Ptr n3 = CreateObject (); + Ptr n4 = CreateObject (); + Ptr n5 = CreateObject (); + Ptr n6 = CreateObject (); +@end verbatim + +Next, we get into the differences between the @code{PointToPointTopology} +helper and the @code{PointToPointIpv4Topology} helper. The +@code{PointToPointIpv4Topology} helper looks and feels a little like the +@code{CsmaIpv4Topology} helper. Just like you created a CSMA channel +previously, you need to create a point-to-point channel. The following +code creates a @code{PointToPointChannel} and calls it @code{link01}. You can +interpret this name as being the channel (or @emph{link}) from node zero to +node one. + +@verbatim + Ptr link01 = + PointToPointIpv4Topology::CreateChannel (DataRate (38400), + MilliSeconds (20)); +@end verbatim + +You need to provide a data rate for the channel which we set at 38400 bits +per second. You must also provide a speed-of-light delay which we set at +20 milliseconds. + +Just as you added a net device to the nodes in the CSMA tutorial section, you +do the same here but with a point-to-point net device. The following code +illustrates how we do that: + +@verbatim + uint32_t nd01 = PointToPointIpv4Topology::AddNetDevice (n0, + link01); +@end verbatim + +We call the @code{PointToPointIpv4Topology} helper and ask it to add a net +device to node zero (@code{n0}) and connect it to the appropriate +point-to-point link (@code{link01}) which you will recall is the serial link +from node zero to node one. + +If you look at the following code, you will see the same calls are repeated +to create the remaining five point-to-point channels and connect them +to net devices on node zero. + +The next new code is found after the ``spokes'' of the star have been created. +It looks like the following: + +@verbatim + uint32_t nd1 = PointToPointIpv4Topology::AddNetDevice (n1, link01); + uint32_t nd2 = PointToPointIpv4Topology::AddNetDevice (n2, link02); + uint32_t nd3 = PointToPointIpv4Topology::AddNetDevice (n3, link03); + uint32_t nd4 = PointToPointIpv4Topology::AddNetDevice (n4, link04); + uint32_t nd5 = PointToPointIpv4Topology::AddNetDevice (n5, link05); + uint32_t nd6 = PointToPointIpv4Topology::AddNetDevice (n6, link06); +@end verbatim + +Here we are creating the net devices on the nodes surrounding the center node. +In the first call, we are adding a net device on node one (@code{n1}) and +connecting that net device to the channel named @code{link01}. Remember that +we created the channel @code{link01} as the channel connecting node zero and +node one. We previously created a net device on node zero and attached that +device to @code{link01}. Here we are connecting the other side of that link +to node one. The return value from this call is the net device index of the +created net device. + +The next section of code adds addresses to the net devices we just created. +The first call adds the IP address 10.1.1.1 to the net device going from +node zero to node one. Recall that we first created a node named @code{n0} +and a channel called @code{link01}. We added a net device to @code{n0} and +remembered the net device index as the @code{uint32_t nd01}. This meant +the net device @emph{nd} on node @emph{0} that we connected to node @emph{1}. +We call @code{AddAddress} to add an IP address (10.1.1.1) to the net device +on node zero identified by the net device index @code{nd01}. We provide a +net mask suitable for a point to point network. This is typically a /30 +address but we don't force that in this API. + +After setting up the address on node zero, we do the same for the node on +the other end of the ``spoke'' --- in this case node one, with its single +net device. Note that the network number is the same on both sides of this +network. + +@verbatim + PointToPointIpv4Topology::AddAddress (n0, nd01, "10.1.1.1", + ``255.255.255.252''); + + PointToPointIpv4Topology::AddAddress (n1, nd1, "10.1.1.2", + ``255.255.255.252''); +@end verbatim + +The following code repeats this pattern assining similar IP addresses to the +remaining net devices. Note that there are no @code{Mac48Address} address +assignments --- they are not required. + +The rest of the code you should recognize and understand. We are just going +to echo one packet across the point-to-point link. You should be now be able +to build and run this example and to locate and interpret the ASCII trace +file. This is left as an exercise for you. + +The file @code{tutorial-star.cc} is reproduced here for your convenience: + +@verbatim +/* -*- 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/log.h" +#include "ns3/ptr.h" +#include "ns3/internet-stack.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/mac48-address.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/point-to-point-ipv4-topology.h" +#include "ns3/udp-echo-client.h" +#include "ns3/udp-echo-server.h" +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/global-route-manager.h" + +NS_LOG_COMPONENT_DEFINE ("StarSimulation"); + +using namespace ns3; + +// Network topology +// +// n3 n2 +// | / +// | / +// n4 --- n0 --- n1 +// / | +// / | +// n5 n6 + +int +main (int argc, char *argv[]) +{ + LogComponentEnable ("StarSimulation", LOG_LEVEL_INFO); + + NS_LOG_INFO ("Star Topology Simulation"); + + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + Ptr n3 = CreateObject (); + Ptr n4 = CreateObject (); + Ptr n5 = CreateObject (); + Ptr n6 = CreateObject (); + + Ptr link01 = + PointToPointIpv4Topology::CreateChannel (DataRate (38400), + MilliSeconds (20)); + + uint32_t nd01 = PointToPointIpv4Topology::AddNetDevice (n0, + link01); + + Ptr link02 = + PointToPointIpv4Topology::CreateChannel (DataRate (38400), + MilliSeconds (20)); + + uint32_t nd02 = PointToPointIpv4Topology::AddNetDevice (n0, + link02); + + Ptr link03 = + PointToPointIpv4Topology::CreateChannel (DataRate (38400), + MilliSeconds (20)); + + uint32_t nd03 = PointToPointIpv4Topology::AddNetDevice (n0, + link03); + + Ptr link04 = + PointToPointIpv4Topology::CreateChannel (DataRate (38400), + MilliSeconds (20)); + + uint32_t nd04 = PointToPointIpv4Topology::AddNetDevice (n0, + link04); + + Ptr link05 = + PointToPointIpv4Topology::CreateChannel (DataRate (38400), + MilliSeconds (20)); + + uint32_t nd05 = PointToPointIpv4Topology::AddNetDevice (n0, + link05); + + Ptr link06 = + PointToPointIpv4Topology::CreateChannel (DataRate (38400), + MilliSeconds (20)); + + uint32_t nd06 = PointToPointIpv4Topology::AddNetDevice (n0, link06); + + uint32_t nd1 = PointToPointIpv4Topology::AddNetDevice (n1, link01); + uint32_t nd2 = PointToPointIpv4Topology::AddNetDevice (n2, link02); + uint32_t nd3 = PointToPointIpv4Topology::AddNetDevice (n3, link03); + uint32_t nd4 = PointToPointIpv4Topology::AddNetDevice (n4, link04); + uint32_t nd5 = PointToPointIpv4Topology::AddNetDevice (n5, link05); + uint32_t nd6 = PointToPointIpv4Topology::AddNetDevice (n6, link06); + + PointToPointIpv4Topology::AddAddress (n0, nd01, "10.1.1.1", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n1, nd1, "10.1.1.2", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n0, nd02, "10.1.2.1", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n2, nd2, "10.1.2.2", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n0, nd03, "10.1.3.1", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n3, nd3, "10.1.2.2", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n0, nd04, "10.1.4.1", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n4, nd4, "10.1.4.2", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n0, nd05, "10.1.5.1", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n5, nd5, "10.1.5.2", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n0, nd06, "10.1.6.1", + "255.255.255.252"); + + PointToPointIpv4Topology::AddAddress (n6, nd6, "10.1.6.2", + "255.255.255.252"); + + uint16_t port = 7; + + Ptr client = CreateObject (n0, "10.1.1.2", + port, 1, Seconds(1.), 1024); + + Ptr server = CreateObject (n1, port); + + server->Start(Seconds(1.)); + client->Start(Seconds(2.)); + + server->Stop (Seconds(10.)); + client->Stop (Seconds(10.)); + + AsciiTrace asciitrace ("tutorial.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + Simulator::Run (); + Simulator::Destroy (); +} +@end verbatim + +@subsection Routing +If you are really excited about this simulator you may have already tried to +modify the scripts outside the tutorial. I know that one of the first things +that would have occurred to me when I saw the star network would have been to +start trying to add applications to echo packets from nodes other than zero. +If you tried, for example, to start the echo client on node one instead of +node zero, you would have found an empty trace file. The reason for this +is that you have now created an internetwork. This means you will need to +enable internetwork routing. + +We have provided a file for you in the @code{tutorial} directory called +@code{tutorial-star-routing.cc} to show you how this is done. This extremely +tricky and difficult change is shown below: + +@verbatim + GlobalRouteManager::PopulateRoutingTables (); +@end verbatim + +This one-line addition, located just before the simulation runs, tells the +@command{ns-3} @emph{global route manager} to walk the topology you created and +build internetwork routing tables for all of the nodes in the simulation. +We changed the client application so that it runs on node four: + +@verbatim + Ptr client = CreateObject (n4, "10.1.1.2", + port, 1, Seconds(1.), 1024); +@end verbatim + +Now if you build and run @code{tutorial-star-routing.cc} you can examine the +@code{tutorial.tr} file and see that your UDP echo packets are now correctly +routed through the topology. + +@section A Dumbbell Network +One of the most interesting simple topologies (from a phenomenological point of +view) is commonly called a dumbbell network. The name derives from a +superficial similarity in form to a piece of exercise equipment. + +The dumbbell model is typically composed of two bus or star network elements +connected via a point-to-point link. The point-to-point link is usually +configured with a lower bandwidth than the bus elements to provide a +@emph{choke point}. + +The following is a representation of the topology. + +@sp 1 +@center @image{figures/dumbbell,,,,png} + +We have provided a file that constructs this dumbbell network and creates +enough data flowing across the choke point that some packets will be dropped. +The file is called @code{tutorial-linear-dumbbell.cc} and is located in the +@code{tutorial} directory. We have already covered all of the code used to +create this network, so we will just quickly go over the main sections of the +script. + +The first section creates a CSMA lan that will become the left side of the +dumbbell network. This code should be very familiar since we used the same +process to create our first example. + +@verbatim +// +// Create the lan on the left side of the dumbbell. +// + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr n2 = CreateObject (); + Ptr n3 = CreateObject (); + + Ptr lan1 = + CsmaTopology::CreateCsmaChannel (DataRate (10000000), MilliSeconds (2)); + + uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan1, + "08:00:2e:00:00:00"); + + uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan1, + "08:00:2e:00:00:01"); + + uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1, + "08:00:2e:00:00:02"); + + uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1, + "08:00:2e:00:00:03"); + + CsmaIpv4Topology::AddIpv4Address (n0, nd0, "10.1.1.1", "255.255.255.0"); + CsmaIpv4Topology::AddIpv4Address (n1, nd1, "10.1.1.2", "255.255.255.0"); + CsmaIpv4Topology::AddIpv4Address (n2, nd2, "10.1.1.3", "255.255.255.0"); + CsmaIpv4Topology::AddIpv4Address (n3, nd3, "10.1.1.4", "255.255.255.0"); +@end verbatim + +The code to generate the CSMA lan on the right side is similar; only the names +have been changed. + +@verbatim +// +// Create the lan on the right side of the dumbbell. +// + Ptr n4 = CreateObject (); + Ptr n5 = CreateObject (); + Ptr n6 = CreateObject (); + Ptr n7 = CreateObject (); + + Ptr lan2 = + CsmaTopology::CreateCsmaChannel (DataRate (10000000), MilliSeconds (2)); + + uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan2, + "08:00:2e:00:00:04"); + + uint32_t nd5 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, lan2, + "08:00:2e:00:00:05"); + + uint32_t nd6 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n6, lan2, + "08:00:2e:00:00:06"); + + uint32_t nd7 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n7, lan2, + "08:00:2e:00:00:07"); + + CsmaIpv4Topology::AddIpv4Address (n4, nd4, "10.1.2.1", "255.255.255.0"); + CsmaIpv4Topology::AddIpv4Address (n5, nd5, "10.1.2.2", "255.255.255.0"); + CsmaIpv4Topology::AddIpv4Address (n6, nd6, "10.1.2.3", "255.255.255.0"); + CsmaIpv4Topology::AddIpv4Address (n7, nd7, "10.1.2.4", "255.255.255.0"); +@end verbatim + +Next, we create a point to point link to connect the two lans. We connect +the point-to-point channel between nodes three (on the left lan) and four +(on the right lan). You should recoginze this as substantially similar to +the link setup from the @code{point-to-point} example. + +@verbatim +// +// Create the point-to-point link to connect the two lans. +// + Ptr link = PointToPointTopology::AddPointToPointLink ( + n3, n4, DataRate (38400), MilliSeconds (20)); + + PointToPointTopology::AddIpv4Addresses (link, n3, "10.1.3.1", + n4, "10.1.3.2"); +@end verbatim + +Then we configure data flows. We create four echo clients that send UDP +packets from the left side lan to servers created on the right side lan. +Notice that we send 100 packets with an inter-packet gap of ten milliseconds +instead of the single packet we have previously used. This data rate is +sufficient to saturate the point-to-point link and will cause packets to be +dropped when the queue on the link net devices overflows (the default maximum +queue depth is 100 packets). Note that we stagger the start of the echo +clients to slowly bring up the data rates. + +@verbatim +// +// Create data flows across the link: +// n0 ==> n4 ==> n0 +// n1 ==> n5 ==> n1 +// n2 ==> n6 ==> n2 +// n3 ==> n7 ==> n3 +// + uint16_t port = 7; + + Ptr client0 = CreateObject (n0, "10.1.2.1", + port, 100, Seconds(.01), 1024); + Ptr client1 = CreateObject (n1, "10.1.2.2", + port, 100, Seconds(.01), 1024); + Ptr client2 = CreateObject (n2, "10.1.2.3", + port, 100, Seconds(.01), 1024); + Ptr client3 = CreateObject (n3, "10.1.2.4", + port, 100, Seconds(.01), 1024); + + Ptr server4 = CreateObject (n4, port); + Ptr server5 = CreateObject (n5, port); + Ptr server6 = CreateObject (n6, port); + Ptr server7 = CreateObject (n7, port); + + server4->Start(Seconds(1.)); + server5->Start(Seconds(1.)); + server6->Start(Seconds(1.)); + server7->Start(Seconds(1.)); + + client0->Start(Seconds(2.)); + client1->Start(Seconds(2.1)); + client2->Start(Seconds(2.2)); + client3->Start(Seconds(2.3)); + + server4->Stop (Seconds(10.)); + server5->Stop (Seconds(10.)); + server6->Stop (Seconds(10.)); + server7->Stop (Seconds(10.)); + + client0->Stop (Seconds(10.)); + client1->Stop (Seconds(10.)); + client2->Stop (Seconds(10.)); + client3->Stop (Seconds(10.)); +@end verbatim + +The remainder of the file should be quite familiar to you. Go ahead and +run @code{tutorial-linear-dumbbell}. Now take a look at the trace +(@code{tutorial.tr}) file. You will now see trace lines that begin with +@code{d}. Alternatively you can search for the string ``queue-drop'' which +is the expansion of the drop code ('d'). + +Interpretation of a dropped packet is straightforward. We have expanded +the first @code{queue-drop} trace for you below. See the section on ASCII +tracing for details. + +@verbatim + 00 d + 01 2.40938 + 02 nodeid=3 + 03 device=1 + 04 queue-drop + 05 pkt-uid=124 + 06 LLCSNAP(type 0x800) + 07 IPV4( + 08 tos 0x0 + 09 ttl 63 + 10 id 20 + 11 offset 0 + 12 flags [none] + 13 length: 1052) 10.1.1.3 > 10.1.2.3 + 14 UDP(length: 1032) + 15 49153 > 7 + 16 DATA (length 1024) +@end verbatim + +We leave it as an exercise to examine the trace files in more detail. + +@c ======================================================================== +@c Nonlinear Thinking +@c ======================================================================== + +@node Nonlinear-Thinking +@chapter Nonlinear Thinking + +One thing that all of our examples so far have in common is that they are +composed of a linear collection of calls into the @command{ns-3} system. The +programmers among the readers may have wondered why there is not as much +as a for-loop in all of the examples. The answer is that we wanted to +introduce you to @command{ns-3} scripting with a minimum of conceptual +overhead. We're going to remedy that situation shortly. + +We have written a number of @command{ns-3} scripts in C++. Although we have +been perfectly linear in our script implementations, just like any other C++ +program, an @command{ns-3} script can use any features of the language you +desire. If you will look back at the @code{tutorial-linear-dumbbell.cc} +example, you may notice that the code to create the left and right sides of +the dumbbell is operationally identical --- only the names change. An obvious +improvement of this program would be to use subroutines to create the sides. +Since we are working with C++, we should probably do this in an +object-oriented way. Since object-oriented design is somewhat of a black art +to some people, we'll take some time here and outline a simple methodology +you can follow. + +@section Object Design 101 --- Class Ipv4BusNetwork +If you are a master of object oriented design, feel free to skip or skim this +section, in which we derive a simplistic but fully operational bus network +class. + +So you want to create a BusNetwork class. Often the biggest hurdle in a +design is figuring out how to get started. One of the simplest and most +straightforward ways to do an object decomposition of a problem is to simply +write down a description of the problem and take a look at the words +you used. Let's take some time and do that, first at a very high level. + +@example +A bus network is an implementation of a particular network topology that +contains some number of nodes. Each of these nodes is attached to a single +multi-drop channel. The network itself has some attributes independent of +the topology such as a network mask, network number (prefix) and base IP +address. +@end example + +The first thing to do is to focus on the nouns and adjectives. These will +give you a starting point for required classes and member variables. + +Immediately we can notice that at the highest level we are talking about the +noun @emph{network}. This probably won't surprise you. We also have an +adjective that modifies the noun --- @emph{bus}. This should lead us to our +first class defintion. Usually class names are constructed in the same way +as an English language sentence would be spoken. For example, one would speak +of a @emph{bus network} in conversation, so we would normally create a +@code{class BusNetwork} to represent it. + +One thing to note is that we have used two words in our description quite +naturally: @emph{is} and @emph{has}. When you see these words should should +immediately think of the object-oriented concepts of @emph{ISA} (inheritance) +and @emph{HASA} (containment) respectively. We wrote that a bus network +@emph{is} an implementation of a particular network topology. Perhaps you +will agree that there is a natural base class called @code{Network} that +@emph{has} the attributes discussed above. The fact that a @code{BusNetwork} +@emph{ISA} kind of @code{Network} suggests inheritance. Let's capture that +thought right away remembering that we're focused on IP version four here: + +@verbatim + class Ipv4Network + { + public: + Ipv4Address m_network; + Ipv4Mask m_mask; + Ipv4Address m_baseAddress; + }; + + class Ipv4BusNetwork : public Ipv4Network + { + }; +@end verbatim + +Let's take a look at the @emph{HASA} relationships of the bus network. Clearly +it will @emph{have} a reference to the underlying channel that implements the +actual communications medium. We use smart pointers for those references, so +one member variable is obvious: + +@verbatim + Ptr m_channel; +@end verbatim + +A bus network will also need to contain references to all of the nodes we +eventually want to create. If you are working in C++ and see the words contain +or container, you should immediately think of the Standard Template Library +or STL. A quick search of the available containers there will probably lead +you to consider the vector class. A vector is a container that looks like an +array. This is just what we need here. Again, we want to use smart pointers +to reference our nodes, so the declaration of the vector would look like, + +@verbatim + std::vector > m_nodes; +@end verbatim + +It will save you headaches in the future if you notice that the space between +the two right brackets is required to differentiate this situation from a +right-shift operator. So we have a pretty good start already after just a +little work. Now we need to turn our attention to actions. Let's write +another little description of the things you consider doing to a Bus network. + +@example +We need to be able to create a bus network. We need to be able to delete a +bus network. We need to be able to get a handle to a node in order to add +applications. We need to be able to set the network, mask and base address +somehow, specify how many nodes to create and provide the underlying channel +its required bandwidth and delay parameters. +@end example + +We now look at the @emph{verbs} in that sentence. These will give a good +starting point for the methods of the classes. For example, the verbs +@emph{create} and @emph{delete} should suggest @emph{constructor} and +@emph{destructor}. The verb @emph{get} leads us to providing a method called +@code{GetNode}. We have to provide a number of parameters so we can either +provide @emph{setters} or we can simply pass them in as parameters to our +constructors. Since this is a simple example, we won't bother to implement +getters and setters (methods to get and set member variables to enhance data +hiding). Let's use this guidance to finish up our class declarations: + +@verbatim + class Ipv4Network + { + public: + Ipv4Network (Ipv4Address network, Ipv4Mask mask, Ipv4Address address); + virtual ~Ipv4Network (); + + Ipv4Address m_network; + Ipv4Mask m_mask; + Ipv4Address m_baseAddress; + }; + + class Ipv4BusNetwork : public Ipv4Network + { + public: + Ipv4BusNetwork ( + Ipv4Address network, + Ipv4Mask mask, + Ipv4Address startAddress, + DataRate bps, + Time delay, + uint32_t n); + + virtual ~Ipv4BusNetwork (); + + Ptr GetNode (uint32_t n); + + private: + std::vector > m_nodes; + Ptr m_channel; + }; +@end verbatim + +That's it. We have actually already walked through almost all of the code +required to construct a bus network in our @code{tutorial-csma-echo.cc} +example, so let's just jump forward and take a look at an implementation +of this thing. We provide an implementation for you in the files +@code{ipv4-bus-network.h} and @code{ipv4-bus-network.cc} located in the +@code{tutorial} directory. We also provide an example that uses the new +class in the file @code{tutorial-bus-network.cc}. + +The interesting method from our current perspective is the Ipv4BusNetwork +constructor, shown below: + +@verbatim + Ipv4BusNetwork::Ipv4BusNetwork ( + Ipv4Address network, + Ipv4Mask mask, + Ipv4Address baseAddress, + DataRate bps, + Time delay, + uint32_t n) + : + Ipv4Network (network, mask, baseAddress) + { + Ipv4AddressGenerator::SeedNetwork (mask, network); + Ipv4AddressGenerator::SeedAddress (mask, baseAddress); + + m_channel = CsmaTopology::CreateCsmaChannel (bps, delay); + + for (uint32_t i = 0; i < n; ++i) + { + Ptr node = CreateObject (); + uint32_t nd = CsmaIpv4Topology::AddIpv4CsmaNetDevice (node, m_channel, + Mac48Address::Allocate ()); + Ipv4Address address = Ipv4AddressGenerator::AllocateAddress (mask, + network); + CsmaIpv4Topology::AddIpv4Address (node, nd, address, mask); + m_nodes.push_back (node); + } + } +@end verbatim + +Notice that we do the simple and straightforward thing and pass all of our +parameters to the constructor. For those unfamiliar with C++, the line after +the colon and before the opening brace (shown below), + +@verbatim + : + Ipv4Network (network, mask, baseAddress) + { +@end verbatim + +Passes the appropriate parameters to the constructor of the base class +@code{Ipv4Network}. There are two new calls that we haven't seen immediately +after this initialization. They are: + +@verbatim + Ipv4AddressGenerator::SeedNetwork (mask, network); + Ipv4AddressGenerator::SeedAddress (mask, baseAddress); +@end verbatim + +We provide an IP address generator class to allow us to programatically +allocate IP addresses. The first call to @code{SeedNetwork} gives the +address generator a starting network number to use when generating addresses. +The second call to @code{SeedAddress} gives the address generator a starting +IP address to use. There is a starting network and starting address for each +of the 32 possible network masks. Later in the for loop, you will see a +call to @code{AllocateAddress} in which the IP address for each node created +in the loop is actually generated. + +The only unfamiliar call in the reset of the constructor will be: + +@verbatim + m_nodes.push_back (node); +@end verbatim + +This is the STL code to add the newly created node to the vector of nodes +attached to the bus. + +For your convenience, we reproduce the entire bus network implementation below: + +@verbatim + /* -*- 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; + * + * 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/mac48-address.h" + #include "ns3/csma-net-device.h" + #include "ns3/csma-topology.h" + #include "ns3/csma-ipv4-topology.h" + + #include "ipv4-bus-network.h" + #include "ipv4-address-generator.h" + + namespace ns3 { + + Ipv4Network::Ipv4Network ( + Ipv4Address network, + Ipv4Mask mask, + Ipv4Address address) + : + m_network (network), m_mask (mask), m_baseAddress (address) + { + } + + Ipv4Network::~Ipv4Network () + { + } + + Ipv4BusNetwork::Ipv4BusNetwork ( + Ipv4Address network, + Ipv4Mask mask, + Ipv4Address baseAddress, + DataRate bps, + Time delay, + uint32_t n) + : + Ipv4Network (network, mask, baseAddress) + { + Ipv4AddressGenerator::SeedNetwork (mask, network); + Ipv4AddressGenerator::SeedAddress (mask, baseAddress); + + m_channel = CsmaTopology::CreateCsmaChannel (bps, delay); + + for (uint32_t i = 0; i < n; ++i) + { + Ptr node = CreateObject (); + uint32_t nd = CsmaIpv4Topology::AddIpv4CsmaNetDevice (node, m_channel, + Mac48Address::Allocate ()); + Ipv4Address address = Ipv4AddressGenerator::AllocateAddress (mask, + network); + CsmaIpv4Topology::AddIpv4Address (node, nd, address, mask); + m_nodes.push_back (node); + } + } + + Ipv4BusNetwork::~Ipv4BusNetwork () + { + } + + Ptr + Ipv4BusNetwork::GetNode (uint32_t n) + { + return m_nodes[n]; + } + + }; // namespace ns3 +@end verbatim + +@section Using Ipv4BusNetwork +If all you ever want to do with a bus network can be captured in a topology +with four nodes on the bus, the preceeding section may seem like a colossal +waste of time. This is probably not the case, though. Now that we have a +relatively abstract bus class, we can create bus networks with 4, 40 or 4000 +nodes with no additional effort. + +A use of the bus network class is shown in the file +@code{bus-netowrk.cc} located in the @code{tutorial} directory. The +interesting code is, + +@verbatim + Ipv4BusNetwork bus ("10.1.0.0", "255.255.0.0", "0.0.0.3", + DataRate(10000000), MilliSeconds(20), 10); +@end verbatim + +Here we create a bus network with the network number ``10.1.0.0'' and the +network mask ``255.255.0.0'' that completes the IP network definition. You +can consider these together as ``10.1.0.0/16'' if you prefer. The next +parameter tells the bus to start numbering IP addresses of contained nodes at +``10.1.0.3'' (remember the network number will be combined). We provided a +data rate of 10 megabits per second and a latency of 20 milliseconds. +Finally, we ask the @code{Ipv4BusNetwork} object to create ten nodes in the +network. + +If you are feeling brave, go ahead and change the number of nodes to be 100, +1000, 10,000 or more to generate larger and larger networks. Before you go +too far, remember that a trace file will be generated when you run your +resulting program and ee asked the trace facility to trace all net device +receive events. This will include the reception of the broadcast ARP request +by all of the nodes in the simulation, so this can add up quickly. + +@c ======================================================================== +@c Summary +@c ======================================================================== + +@node Summary +@chapter Summary + +This concludes the first part of the tutorial. We have focused on +using the @command{ns-3} system to construct various network topologies and to +simulate sendng data across the networks; and we've shown you how to use the +trace facility to get access to simulation results. + +We now encourage you to play with the system a little. Experiment with what +we have provided. Build a hierarchical network simulation. Perhaps exercise +your object design skills and create a new @code{Ipv4DumbbellNetwork} class +to create dumbbell networks using the Ipv4BusNetwork class we just created. +Hint: An Ipv4DumbbellNetwork @emph{has} two @code{Ipv4BusNetwork} objects; +a left side and a right side. + +In the next part of the tutorial we are going to drop down a level and begin +examining the lower levels of the system in more detail. We are going to +explain how to change the behavior of the system and eventually how to write +new models and applications. This is a good time to make sure that you +thorougly understand what we've gone over so far. + +@c ======================================================================== +@c Object Model +@c ======================================================================== + +@node Object-Model +@chapter Object Model + +@cindex Object Model +There are two distinctly different meanings associated with the term Object +Model. The first speaks to the implementation of an object system --- a system +view; and the second speaks to the application programming interface (classes +or objects) one uses to access some service or system --- an application view. + +As an example of the system view sense of the term, the C++ language has an +associated object model that describes how objects are laid out in memory, +how virtual functions work, how inheritance is implemented, constructor and +destructor execution ordering, template instantiation, etc. + +@cindex API +@cindex DOM +@cindex Document Object Model +In the case of the application view, the Document Object Model is a good +example. In the words of W3C, the Document Object Model (DOM) is an +application programming interface (API) for HTML and XML documents. It defines +the logical structure of documents and the way a document is accessed and +manipulated. + +@cindex API +@cindex COM +@cindex Component Object Model +The Component Object Model (COM) from Microsoft actually spans both meanings +of the term and extends further into policy statements. From a system +perspective, COM specifies an interface definition language, the layout of +objects virtual function tables, the formats of Globally Unique Identifiers +and also specifies lifetime management mechanisms for objects via reference +counting. From the point of view of the API, COM specifies a number of +Interfaces as well as functions such as CoCreateInstance and various +threading models. The COM specification extends to policy by disallowing +implementation inheritance. + +@cindex Feynman +The @command{ns-3} object model takes the C++ language (system level) object +model as its basis, and extends that model by providing an API for software +componentry. You may find terms like Component, Interface and QueryInterface +in the following discussion, or used informally in other discussions about +@command{ns-3}. It is important to understand from the outset that this is +the @command{ns-3} object model, and not any other object model. +Richard Feynman (an American physicist) once described the behavior of matter +and light on a very small scale in the following way, + +@quotation +``They do not behave like waves, they do not behave like particles, they do +not behave like clouds, or billiard balls, or weights on springs, or like +anything that you have ever seen.'' +@end quotation + +Just as students of quantum mechanics must rid themselves of preconceptions +regarding the behavior of matter at small scales, you should rid yourself of +any preconceptions you may have about components, interfaces and APIs for +software componentry before continuing. To paraphrase Feynman, @command{ns-3} +components do not behave like COM Components, or Java Beans, or CORBA +objects, or clouds or weights on springs, or like anything that you have +ever seen --- they are @command{ns-3} components. + +@section The C++ Object Model is the Root of all Things +@command{Ns-3} is primarily a C++ system. The system is written in C++ and +one can use standard C++ mechanisms for creating and using ns-3 objects. We +do not change this at all, nor do we make any pronouncements about the +superiority of one mechanism or another. What we will do is provide +convenience functions that we think will make creating and managing simulation +objects easier. + +@cindex CreateObject +Previously, you have seen objects created using the template function +@code{CreateObject} as in the following example: + +@verbatim + Ptr n0 = CreateObject (); +@end verbatim + +This line of code, while it may be unfamiliar to some, is pure C++. If you +were to look in the header file ptr.h, you would find the following definition +of the @code{CreateObject} template. + +@verbatim + template + Ptr CreateObject (void) + { + Ptr p = Ptr (new T (), false); + p->SetTypeId (T::GetTypeId ()); + return p; + } +@end verbatim + +@cindex template +As you can see, this template creates objects of type @code{T} using the +operator @code{new}. Its a little harder to find the corresponding delete --- +it's in the file @code{object.cc} inside the method @code{Object::MaybeDelete}, +but when that @code{Ptr} which you see above goes out of scope it will call +@code{Unref} and ultimately the C++ @code{delete} operator will be called. + +@cindex new +@cindex delete +The ns-3 system uses the C++ @code{new} and @code{delete} operators, so there +is really no reason that you as a user of the ns-3 system are forbidden from +using these or any other C++ mechanism. If you so desire, you can take on +the responsibility for managing object lifetime (i.e., do not use the +@code{Ptr} smart pointer), work directly with the @code{new} and @code{delete} +operators and call methods like any C++ object as in the following example: + +@verbatim + MyClass *obj = new MyClass (); + obj->Method(); + delete obj; +@end verbatim + +@cindex model +You, as a competent model author, are encouraged to use whatever methods you +think are appropriate in your private code. Remember, however, that the +public ns-3 APIs do use smart pointers to pass objects around in an effort to +reduce the burden of object lifetime management. If you do intend to export +an API publicly, you should use the same object lifetime management approaches +as those found in the ns-3 public API if only for consistency. + +These APIs are there for convenience and consistency, but do not change the +fact that in ns-3 all of the objects are really just C++ objects, ultimately +created using the C++ new operator with C++ constructor semantics and are +ultimately deleted using the C++ delete operator, following C++ destructor +semantics. Although it may sometimes appear so, there is really no system- +level magic going on in ns-3. Ns-3 components and interfaces are C++ objects +just like any other object and our object model is simply a collection of APIs +built on the normal C++ object model. + +@cindex Interface +@cindex Abstract Data Type +@cindex ADT +@cindex Abstract Base Class +@cindex ABC +@section Interface +There are many different ideas floating around of what exactly the term +@emph{interface} means. Originally an interface just meant a communication +boundary between two entities. As the concepts of object oriented programming +(OOP) were surfacing in the 1980s, the term interface was applied to the +collection of access methods for the modular entities that were being defined. + +@cindex OOP +@cindex Object Oriented Programming +Two distinct approaches developed regarding specifying access mechanisms for +objects. The OOP purists were very concerned about object reuse and were led +to Abstract Data Types (ADT). These were eventually implemented in the case +of C++, as pure virtual methods in Abstract Base Classes (ABC). Another group +of folks was more interested in simply specifying object access methods in one +place and using inheritance as the primary reuse mechanism. + +Bjarne Stroustroup, the creator of C++, embraced both approaches. He makes +the following interesting observation: + +@quotation +``Many classes [@dots{}] are useful both as themselves and also as bases for +derived classes. [@dots{}] Some classes, such as class @strong{Shape}, +represent abstract concepts for which objects cannot exist.'' +@end quotation + +@cindex PIMPL +@command{Ns-3} does not pick and enforce a particular approach. In +@command{ns-3} an interface is determined completely by a class declaration +just as any C++ object interface is declared. If you think of an object as +an abstract concept that should be implemented by derived classes, by all +means, use the Abstract Base Class approach to interface declaration. If you +think that an object should be completely concrete and you foresee no need +to ever modify its behavior, feel free to avoid declaring any methods virtual. +If you think that an object could be useful as a base class, feel free to +declare its methods virtual. If you like to use the PIMPL idiom, again, feel +free. If you want to use any combination of these techniques, feel free. +We make no restrictions. + +@cindex API +When we speak of an ns-3 interface, we do not worry about interface definition +languages, or pure virtual classes, or registries we just think about C++ +object declarations and their associated methods. We tend to think of +interfaces to objects as simply a private or public API. When we instantiate +an @command{ns-3} interface, it is the C++ object model that dictates how that +object is brought into existence. When a method is called on an @command{ns-3} +Interface, it is the C++ object model that dictates how that method is +dispatched. + +We do, however, provide a base class that endows vanilla C++ objects with +capabilities that can be seen as conceptually similar to those provided by +Microsoft Component Model @emph{Interfaces}. + +@section The Ns-3 Object and GetObject +@cindex Component Object Model +One thing that Microsoft arguably got right in the Component Object Model was +the idea of Interface aggregation and discovery via QueryInterface. We have +embraced these ideas in @command{ns-3}. This was done primarily to address a +common problem in large software systems. A good example of this problem +happens in the @command{ns-3} Node class. + +@cindex OOP +@cindex weak base class +@cindex base class bloat +@cindex Swiss Army Knife class +@cindex Node +If one were to take the standard OOP view of specializing a @code{Node} into +an internet host, for example, one would typically inherit from the @code{Node} +base class and include functionality to implement such things as internet +routing and a TCP/IP protocol stack. Other types of @code{Node}s might +inherit from the node class and specialize in different ways, or further +specialize the internet host class, treating it as a base class. This can +result in a complicated inheritance tree in which some specializations are +simply not available to other branches of the tree which can make reuse +difficult or impossible. This is known as the @emph{weak base class} problem +and creates pressure to drive functionality up the inheritance tree into the +base classes. This, in turn, results in @emph{base class bloat} and the +resulting @emph{swiss army knife} base classes which end up trying to do +everything in one place. + +Even if one successfully avoided these swiss army knife base classes, one +would also want to be able to treat new specializations of @code{Node} +generically in the system. This means one would pass references to the base +class (@code{Node}) across public APIs. This introduces @emph{upcasts} prior +to passing across public APIs and corresponding @emph{downcasts} on the other +side in order to gain access to required specialized functions. As the +inheritance tree becomes more complicated, this approach can cause another +related problem known as the @emph{fragile base class} problem. This happens +when changes to the base class cause unexpected problems in the various and +sundry subclasses. + +These effects seem always to result in a positive feedback loop driving +everything into the base class and destroying much of the encapsulation which +is a hallmark of the object oriented approach. + +@subsection Interface Composition +@cindex Node +There is a completely different way to address the Node specialization +problem. Instead of approaching the situation using inheritance, one can +look at the problem as one of composition. We can look at the @code{Node} +class as a container of sorts that holds other objects. In this case, the +objects would be instances of the classes implementing the internetwork +routing code, or the TCP/IP protocol stack described above. This approach +preserves the encapsulation and solves the weak base class, base class bloat +and fragile base class problems; but the question of method dispatch +immediately comes to mind. + +@cindex delegation +In many systems, @emph{delegation} is used. The base class, @code{Node}, +in this approach would provide methods that simply forward to the objects +implementing the desired functionality. This situation clearly does not +address the base class bloat problem since dispatch methods must be added +to the base class. The situation is mitigated somewhat by pushing the +implementation of the dispatch methods to contained objects, but the +fundamental problems are still present. What is really needed is a way +to compose objects but at the same time keep the interfaces to those +objects separated. + +@cindex aggregation +Composition, usually called @emph{aggregation}, along with runtime Interface +discovery is the solution that Microsoft originally championed and that +@command{ns-3} has adopted --- albeit with many simplifications and a few name +changes. + +@subsection Objects and Interfaces +@cindex COM +@cindex QueryInterface +Now that we have mentioned Microsoft COM and are almost obligated to mention +the terms Interface and QueryInterface. For those familiar with COM, loosely +speaking, QueryInterface is to COM as GetObject is to @command{ns-3}. +The analogy, while good conceptually, is superficial from an implementation +point of view. + +@cindex Node +Addressing our current example of a @code{Node}, generically speaking, each +node needs to aggregate an object that will implement internetwork routing +and TCP/IP. The system will need to provide a mechanism for locating the +aggregated objects and allow a client to discover them. + +@cindex aggregation +@cindex Object +These aggregated objects have interfaces in the C++ sense of collections of +method signatures. In @command{ns-3}, when objects are capable of +participating in this aggregation process, they are called @command{ns-3} +@code{Objects}. @code{Objects} receive the functionality required for this + participation by inheriting from the @command{ns-3} base class @code{Object}. + +Note well that when we write the word @code{Object} (note the uppercase 'O' in +the spelling and the change of font) we are referring to a kind of C++ object +that has inherited the capability of participating in an aggregation. The +@command{ns-3}-specific word @code{Object} can have a significantly different +meaning than that of a vanilla C++ object outside the aforementioned +inheritance tree, and the difference is only readily apparent via context. +In this tutorial we will always write the @command{ns-3}-specific kind of +@code{Object} in a fixed font; and will write the vanilla C++ term object in +normal font. In conversation, you will need to be careful to understand which +term is meant: object or @code{Object}. + +Once an object has inherited from class @code{Object} it has the ability to +@emph{host} an aggregation. This means that it has the ability to add other +@code{Objects} to its aggregation via the method @code{AggregateObject}. It +also means that it can provide a service to @emph{discover} other objects in +its aggregation via the method @code{GetObject}. + +@cindex base class +Technically, the class named @code{Object} is simply a base class that you +will inherit from if you want your @code{Objects} to support aggregation and +discovery. Many systems have a base class that implements common +functionality and these base classes are typically called somthing like +Object. The @command{ns-3} version of this base class relates primarily to +@code{Object} aggregation and discovery, although it does also provide methods +to help with intrusive reference counting and tracing as well. + +When a C++ object inherits from the ns-3 Object base class, it is conceptually +promoted to an ns-3 @code{Object} irrespective of how the object was declared +(e.g., as an abstract base class, concrete class, with virtual methods, etc.). +In ns-3, you should associate inheritance from the class named @code{Object} +with promotion of an object to the status of some locatable @code{Object} +rather than with the form of the class declaration. + +@cindex COM +@cindex CORBA +@cindex ORBit +For those of you unfamiliar with Microsoft COM, CORBA or ORBit, this might +sound obvious. For those of with such a background, the point we are making +is that there is no such thing in @command{ns-3} as a separate Interface +declaration, no such thing as an Interface Definiition Language, no such thing +as a UUID or GUID, etc. In @command{ns-3} we just work with C++ objects that +may be given some very useful abilities by inheriting from the @command{ns-3} +base class @code{Object}. @command{Ns-3} @code{Objects} are not required to +inherit from classes composed of pure virtual methods in order to define an +Interface. It's all really just ``plain old C++.'' + +To summarize, when you instantiate an object that inherits from the +@code{Object} class, you will have a C++ object that has four important +properties: + +@cindex AggregateObject +@cindex GetObject +@itemize @bullet +@item The @code{Object} has a C++ interface defined by the collection of method signatures in its inheritance tree; +@item The @code{Object} has some way to identify its underlying class uniquely; +@item The @code{Object} is a kind of container that has the ability to aggregate other @code{Objects} using the method @code{AggregateObject}; +@item The @code{Object} exports a method called @code{GetObject} that allows for discovery of other aggregated @code{Objects}. +@end itemize + +@cindex base class +@cindex Object +It is crucially important to understand what we have described here +(especially for those coming from other systems that provide similar +functionality). A given C++ class has an object access interface that is +essentially the collection of method signatures specified in its inheritance +tree. This is a C++ object model thing. Ns-3 provides a base class from +which the class in question can inherit and be promoted to the status of +@code{Object}. Once a class becomes an @code{Object} it has inherited the +ability to aggregate and search for other @code{Objects} that are added to +its aggregation. + +That last detail is important. In @command{ns-3} @code{Objects} are both +containers and specifications for a object method access. We have previously +mentioned that the @code{Node} class acts as a container. In fact, the +@code{Node} class inherits from @code{Object} and is itself an @command{ns-3} +@code{Object}. So, when the @code{Node} object is created it is really an +aggregation of one @code{Object} and you can call @code{AggregateObject} or +@code{GetObject} on the resulting @code{Node} object. Along with being an +aggregation, the @code{Node} class also describes a public interface. THis +public interface (API) is declared just as any C++ object is declared, via its +class methods as specified in the inheritance tree. For those steeped in +COM or CORBA, this is where the concept of Interface works in @command{ns-3}. +Remember that it is generally true that @code{Objects} are both aggregations +and APIs. + +@subsection Aggregations +@cindex aggregate +The figure below shows how an @code{Object} could be illustrated in detail. +The line with the circle at the top of the diagram represents the appearance +of the @code{Object} API to the external world. This circle and line are +together called a lollipop because of its superficial similarity to a kind of +childs candy. + +@sp 1 +@center @image{oneobj,,,,png} + +@cindex API +You could declare this API and associated @code{Object} quite simply using a +non-virtual class as follows, + +@verbatim + class A : public Object { + public: + static ns3::TypeId GetTypeId (void) + { + static ns3::TypeId tid = ns3::TypeId ("A") + .SetParent (Object::GetTypeId ()) + .AddConstructor (); + return tid; + } + + A () + { + } + + void MethodA (void); + }; +@end verbatim + +The methods that are then available via the API labeled @code{A} in the +figure above are the methods inherited from the @code{Object} base class +(@code{GetObject}, @code{Ref}, and @code{Unref}) and those from class +@code{A} (@code{MethodA}). + +Note that you must declare a @code{TypeId} in your @code{Object} class, and +it must be declared static to make it class-wide in scope. This @code{TypeId} +is a unifying element in the @command{ns-3} object model and uniquely +identifies @code{Objects} at run-time as being instantiated from a particular +class. We'll have much more to say about @code{TypiId} shortly. + +You can think of the arc and arrow device coming off each side of the +illustrated @code{Objects} as part of a connector. These connectors allow +@code{GetObject} to search aggregations for an instance of a class type. +The figure below shows an aggregation of three @code{Objects}: A, B and C. +The class declarations for classes @code{B} and @code{C} are substantially +similar to that of class @code{A}. + +@sp 1 +@center @image{threeobj,,,,png} + +You can visualize these @code{Objects} as being snapped together like Lego +building blocks if you like. When @code{Objects} are aggregated, a +@code{GetObject} search path is formed through the connectors. In order +to create this aggregation you will first need to create the @code{Objects}. +These are just normal, everyday C++ objects that we can create using the +@code{CreateObject} template function and manage using smart pointers. The +following code should be obvious to you by now: + +@verbatim + Ptr a = CreateObject (); + Ptr b = CreateObject (); + Ptr c = CreateObject (); +@end verbatim + +@cindex aggregation +When you create an aggregation, you pick one of the @code{Objects} of the +aggregation to think of as the container. In this case well pick @code{Object} +A. In order to aggregate an @code{Object}, you simply call the method +@code{AggregateObject} that your class has inherited from class @code{Object}. +The following code will aggregate @code{Object B} and @code{Object C} onto +the @code{Object} (and container/aggregation) @code{A}. + +@cindex AggregateObject +@cindex GetObject +@cindex Object +@verbatim + a->AggregateObject (b); + a->AggregateObject (c); +@end verbatim + +Thats all there is to it. Now that you have those connectors snapped +together, you can ask each of the @code{Objects} in the aggregation for any of +the other @code{Objects} in the aggregation. Lets look at a simple example: + +@verbatim + Ptr newB = a->GetObject (); +@end verbatim + +Now, the explanation of what this snippet does is not as simple as writing it. +The left hand side of this assignment declares a smart pointer to the class +@code{B} to help with memory management of the returned @code{Object} pointer. +You should be very familiar with smart pointers at this stage of the tutorial. + +The right hand side illustrates how @code{GetObject} is acutally used. +The method @code{GetObject} is templated. The assocated template parameter +(between the brackets) specifies the @emph{class} that is being requested. +This is important. Since it is the class type that specifies the search +criteron, there can be only one instance of a particular class present in an +aggregation. Looking back a little, although the parameter to +@code{AggregateObject} appears to be a vanilla C++ object (@code{b} or @code{c} +above), it actually represents (is an instance of) a class that has an +associated @code{TypeId} and inherits from @code{Object}. When you call +@code{GetObject} you specify the search criterion (using the template +parameter) as a class name. This referenced class must also have an +associated @code{TypeId} and must also have inherited from @code{Object}. + +This may be summarized by saying that @code{AggregateObject} takes an +@emph{instance} of an object of a particular class that inherits from +@code{Object}. GetObject looks for a @emph{class} of a particular type +(that again inherits from @code{Object}) and possibly returns an aggregated +object instance of that type. + +Now that you have those conceptual connectors snapped together, you can ask +each of the @code{Objects} in the aggregation for any of the @code{Objects} +in the aggregation. For example we could walk the @code{Objects} asking each +for the next in the aggregation. First we would ask the @code{Object} pointed +to by the smart pointer @code{a} to look for the @code{Object} @code{class B}: + +@verbatim + Ptr newB = a->GetObject (); +@end verbatim + +Next, we can ask the @code{Object} pointed to by the smart pointer @code{newB} +to look for the @code{Object} representing @code{class C}: + +@verbatim + Ptr newC = newB->GetObject (); +@end verbatim + +@cindex Object +Then, we can ask the @code{Object} pointed to by the smart pointer @code{newC} +to look for the @code{Object} representing @code{class A} and complete our +circuit of the aggregation: + +@verbatim + Ptr newA = newC->GetObject (); +@end verbatim + +@cindex GetObject +@code{GetObject} has some important properties that we need to go over. +Technically, @code{GetObject} is a @emph{symmetric}, @emph{reflexive} and +@emph{transitive} operation with respect to the set of aggregated +@code{Objects}. + +@subsubsection Symmetry +@cindex symmetry +The symmetric nature of @code{GetObject} guarantees that if one performs a +@code{GetObject} on a given @code{Object} for the class of that same +@code{Object}, that @code{GetObject} must succeed. In other words, the +fact that you accessed the aggregation via an instance of an @code{Object A} +in the aggregation implies the reachability of that @code{Object} in the +aggregation. This is usually written (by Microsoft) as, + +@center must succeed (A >> A) + +We can illustrate this property with the code snippet, + +@verbatim + Ptr symmetricA = a->GetObject (); + NS_ASSERT (symmetricA); +@end verbatim + +Here we take as given an interface (smart) pointer --- named @code{a} --- on +which we perform a @code{GetObject} looking for the class that represents that +same @code{Object}. This call must always succeed and a smart pointer to the +aggregated instance of that class is returned. + +@subsubsection Reflexivity +@cindex reflexivity +Calls to @code{GetObject} must also be reflexive. This means that if you +successfully @code{GetObject} for @code{Object B} from @code{Object A}, then +you must always be able to @code{GetObject} for @code{A} from @code{B}. This +is usually written as, + +@center must succeed (A >> B, then B >> A) + +This property can be illustrated with the code snippet, + +@verbatim + Ptr b = a->GetObject (); + Ptr reflexiveA = b->GetObject (); + NS_ASSERT (reflexiveA); +@end verbatim + +If the first @code{GetObject} on @code{Object A} looking for @code{Object B} +succeeds, then a @code{GetObject} on @code{Object B} looking @code{Object A} +must succeed. + +@subsubsection Transitivity +@cindex transitivity +@code{GetObject} must also be transitive. This means that if one can +find @code{Object B} from @code{Object A}, and @code{Object C} from +@code{Object B}, then one must also be able to find @code{Object C} from +@code{Object A}. This is usually written as, + +@center must succeed (A >> B, and B >> C, then A >> C) + +This property can be illustrated with the code snippet, + +@verbatim + Ptr b = a->GetObject (); + Ptr c = b->GetObject (); + Ptr transitiveC = a->GetObject (); + NS_ASSERT (transitiveC); +@end verbatim + +If you can get to @code{Object B} from @code{Object A}, and you can get to +@code{Object C} from @code{Object B}, then a @code{GetObject} on +@code{Object A} looking for @code{Object C} must also succeed. + +@subsection Creating the TypeId +@cindex TypeId +@cindex GetTypeId +The final piece of this puzzle is the @code{TypeId}. Recall that the +declaration our eample object above included the following code + +@verbatim + static ns3::TypeId GetTypeId (void) + { + static ns3::TypeId tid = ns3::TypeId ("A") + .SetParent (Object::GetTypeId ()) + .AddConstructor (); + return tid; + } +@end verbatim + +This is the bit of code that ties this all together. For those unfamiliar +with the idioms involved, this declaration can be rather dense. First, let's +examine the function declaration itself. The following code, + +@verbatim + static ns3::TypeId GetTypeId (void) ... +@end verbatim + +declares a function that will be associated with all of the instances of the +given class. This is a function, not a method, in that it can be accessed +without a @emph{this} pointer; but it is associated with the class in a +namespace sense. The use of this kind of declaration allows one to write, + +@verbatim + return A::GetTypeId (void); +@end verbatim + +if the @code{TypeId} is needed for our @code{class A}. More generically the +class name can be substituted in a template, as is done deep in the +@command{ns-3} object system. + +From this perspective, if you leave out the middle of the function definition, +the boundaries should make sense to you. + +@verbatim + static ns3::TypeId GetTypeId (void) + { + return tid; + } +@end verbatim + +@cindex function-local variable +You are obviously looking at a global function associated with your class +that simply returns a @code{TypeId}. Now, what about the rest. The code + +@verbatim + static ns3::TypeId tid = ns3::TypeId ("A") + .SetParent (Object::GetTypeId ()) + .AddConstructor (); +@end verbatim + +when found inside the function declaration is called a function-local variable +with associated initialization. It'll be easier to pick this statement apart +piece by piece as well. The first line, + +@verbatim + static ns3::TypeId tid = ... +@end verbatim + +is the declaration of the function-local variable tid. This is essentially +an initialized global variable, the scope of which has been reduced to within +the enclosing method. You can think of this as a kind of global variable +that can only be accessed right there where it is created. If the variable +is initialized, this amounts to the same behavior as if a global static +initializer was declared in a namespace of the same name as your class. +Global static initializers are guaranteed by the C++ language definition to +be executed before your main procedure is entered. So are function-local +variables. + +The variable that is being initialized is of type @code{ns3::TypeId}, is +named @code{A::tid} since it is inside the class declaration for +@code{class A}, and is initialized by a call to the constructor for the class +@code{TypeId}. The constructor for @code{TypeId} takes a @code{std::string} +that can be used to locate the type information for your class. We usually +privide the class name as the string. + +Hopefully, this much of the declaration is now clear: + +@verbatim + static ns3::TypeId GetTypeId (void) + { + static ns3::TypeId tid = ns3::TypeId ("A") + ... + return tid; + } +@end verbatim + +All that is left now are the lines including @code{SetParent} and +@code{AddConstructor}. + +@verbatim + static ns3::TypeId tid = ns3::TypeId ("A") + .SetParent (Object::GetTypeId ()) + .AddConstructor (); +@end verbatim + +The last bit may seem quite odd at first glance, but don't let the way the +code is broken up over several lines throw you. If you saw something like, + +@verbatim + pointer->TypeId()->SetParent()->AddConstructor(); +@end verbatim + +you probably wouldn't hesitate at all. Clearly, you would think, a method +called @code{TypeId} is called using the pointer called @code{pointer} as +shown below. + +@verbatim + pointer->TypeId() +@end verbatim + +The method @code{TypeId} must further return a pointer to an object that has +a method called @code{SetParent}. Just as clearly, @code{SetParent} must +return a pointer to an object that has a method called @code{AddConstructor}. +The same sort of thing is happening in our code snipped, except we are using +references instead of pointers. Perhaps if we rearrange this code to live on +one line it will be clearer. + +@verbatim + ns3::TypeId ("A").SetParent (Object::GetTypeId ()).AddConstructor (); +@end verbatim + +It's just a string of method calls. The remaining question is then, what do +those three methods do. + +The first, @code{ns3::TypeId ("A")}, simply allocates a new type in the system +and allows you to refer to it in the future by a string. We have mentioned +inheritance trees often in the previous discussion. The second method, +@code{SetParent} associates the class being defined with its parents in the +tree. Finally, the @code{AddConstructor} method allows you to specify a +constructor to be used when an instance of your class is created using +@code{CreateObject}. + +@verbatim + AddConstructor (); +@end verbatim + +You can interpret this as explaining to the @command{ns-3} object ssytem that +you have a constructor named @code{A::A} which takes no parameters. You are +saying that this constructor should be used when @code{CreateObject} is called +with no parameters. + +By including the structure of the inheritance tree, in @command{ns-3} we can +use implementation inheritance to easily create new @code{Objects}. You are +prevented from doing so in Microsoft COM, but this was almost universally +identified as a problem. + +So, looking at the entire @code{GetTypeId} declaration again, + +@verbatim + static ns3::TypeId GetTypeId (void) + { + static ns3::TypeId tid = ns3::TypeId ("A") + .SetParent (Object::GetTypeId ()) + .AddConstructor (); + return tid; + } +@end verbatim + +it should be clear what is happening. + +@subsection A Very Real Example +@cindex Node +@cindex AggregateObject +@cindex GetObject +@cindex Object +At this point you may be asking yourself what the point of all of this is, +since you already had those pointers laying around when you created the +objects. The typical case is that one will create and aggregate some number +of @code{Objects} in a constructor and return only a pointer to a single +@code{Object} as in our canonical example with @code{class Node}. In this +case, the @code{Node} would be created and the @code{Node} constructor might +create and call @code{AggregateObject} to aggregate the @code{Objects} for +internetwork routing and TCP/IP. From an external point of view, these +aggregated objects may be discovered at run-time using @code{GetObject}. + +Generally one tends to think of one of the @code{Objects} in the aggregation +as being the container and other @code{Objects} being aggregated to that +container. In the case of a Node, for example, it is quite natural to think +of the Node as being the container which contains protocol stacks, internet +routing, etc. So, lets start thinking about a real example by calling the +container @code{Object Node} instead of @code{A} as we have been. The +creation of this @code{Object} is found all over our example programs. For +example, you will find code like the following in +@code{samples/simple-point-to-point.cc}: + +@verbatim + Ptr n = CreateObject (); +@end verbatim + +It may appear obvious to you now that the @code{InternetNode} class name +provided to the template function @code{CreateObject} means that +@code{InternetNode} is an @command{ns-3} @code{Object} and you will be able to +call @code{GetObject} on the resulting smart pointer. Well, I'm afraid that's +not entirely true. It's slightly more complicated. + +Take a look at @code{src/internet-stack/internet-stack.h} and find the class +declaration for @code{InternetNode}. + +@verbatim + class InternetNode : public Node + { + public: + InternetNode(); + ... + }; +@end verbatim + +@cindex GetTypeId +@cindex TypeId +@cindex Object +There is no declaration of a @code{static TypeId GetTypeId (void)} in this +class. This means that the @code{InternetNode} is really not an @code{Object} +for which you can @code{GetObject}. It turns out that the @code{InternetNode} +is an @emph{implementation class} of the @code{Node Object}. + +You may recall that there can be an implicit cast in a smart pointer +assignment if the cast is to a visible, unambiguous base class. That is, in +fact, what is happening here. Now, take a look at @code{src/node/node.h} and +find the class declaration for @code{class Node}. There you will find, + +@verbatim + class Node : public Object + { + public: + static TypeId GetTypeId (void); + ... + }; +@end verbatim + +Class @code{InternetNode} inherits from class @code{Node} that, in turn, +inherits from class @code{Object}. It is @code{Node} that provides a +@code{GetTypeId} method. Therefore it is @code{Node} that is an +@command{ns-3} @code{Object}. Note well that @code{InternetNode} is not an +@code{Object} in the sense that one should call @code{GetObject} on an +aggregation looking for an @code{InternetNode} class. That is, you should not +do, + +@verbatim + Ptr i = node->GetObject (); +@end verbatim + +since there really is not InternetNode::GetTypeId. It is @code{Node} that is +the @emph{proper} @code{Object} in this case and you should view +@code{InternetNode} as an implementation of the @code{Node Object}. This may +become clearer as we look a little deeper. + +We spoke of a protocol stack that is aggregated to a @code{Node} in our +discussions above, what we see in the real @command{ns-3} code is that this +is represented by the @code{Ipv4 Object}. If you look in +@code{src/node/ipv4.h} you will find, + +@verbatim + class Ipv4 : public Object + { + public: + static TypeId GetTypeId (void); + ... + }; +@end verbatim + +Since class @code{Ipv4} inherits from class @code{Object} and has a +@code{GetTypeId}, it is an @command{ns-3} @code{Object}. If you look in +@code{src/node/ipv4.cc} you will find, + +@verbatim +TypeId +Ipv4::GetTypeId (void) +{ + static TypeId tid = TypeId ("Ipv4") + .SetParent (); + return tid; +} +@end verbatim + +After all of this reading you know that this code snippet is asking the +system to create a unique @code{TypeId} for the @code{Ipv4} class and +declares that @code{Ipv4} inherits from class @code{Object}. This is what +makes an @code{Ipv4} an @code{Object}. + +@cindex Ipv4 +It turns out that the Ipv4 class is an abstract base class (ABC). There are +a number of pure virtual methods declared in that class. This means that +an @code{Ipv4} object may not be instantiated. This is reflected by the fact +that there are no constructors registered in the @code{GetTypeId} method above. +What is instantiated in the real system is an implementation class, called +@code{Ipv4Impl}. This class inherits from @code{Ipv4} and provides the +required virtual methods. This is where understanding what is an +@code{Object} and what is not can get tricky. The @code{Object} is the +@code{Ipv4} class since that is where the @code{GetTypeId} is found. The fact +that you see @code{GetTypeId} there tells you that the @code{Ipv4} class is +the class for which you can @code{GetObject}. + +@cindex implementation class +The class @code{Ipv4Impl} provides an implementation for the pure virtual +methods in @code{Ipv4}. Since class @code{Ipv4} cannot be instantiated, one +instantiates the @code{Ipv4Impl} class to create an @code{Ipv4} @code{Object}. +You will use the @code{CreateObject} template function to create an object that +implements the methods of an @code{Object}. You can probably see how this +gets even more tricky in conversation. + +Once the @code{Ipv4Impl} object is instantiated, the resulting pointer is +immediately cast to an @code{Ipv4} pointer. Clients will then use the +methods specified in the @code{Ipv4} class to access the @code{Ipv4 Object} +methods which are, in turn, implemented in the @code{Ipv4Impl} object. + +If you now look in the file, @code{src/internet-stack/internet-stack.cc} you +will see the following code in @code{InternetNode::Construct} that creates the +@code{Ipv4} Interface and aggregates it. + +@verbatim + Ptr ipv4Impl = CreateObject (ipv4); + ... + Object::AggregateObject (ipv4Impl); +@end verbatim + +Note that the parameter @code{ipv4} passed to the @code{CreateObject} template +function is actually a pointer to an @code{Ipv4L3Protocol} which you can +ignore at this point --- it doesn't really have anything to do with the +@code{Ipv4} Interface. + +This is exactly the same thing that is happening in the case of the +@code{InternetNode}. + +@verbatim + Ptr n = CreateObject (); +@end verbatim + +@cindex implementation object +@code{CreateObject} is being called to create an implementation object, +in this case @code{InternetNode}, which implements the methods of the +@code{Node Object}. It is the resulting @code{Node Object} which you would +use as the container and it is the @code{Node} class that you would use as +the template parameter when calling @code{GetObject}. In the same way, you +would @emph{not} want to do, + +@verbatim + Ptr ipv4 = node->GetObject (); +@end verbatim + +Rather you should understand that the @emph{proper} @code{Object} is the +@code{Ipv4} not the @code{Ipv4Impl} and do the following, + +@verbatim + Ptr ipv4 = node->GetObject (); +@end verbatim + +@cindex CreateObject +This does illustrate that the fact that whether an object created by +@code{CreateObject} is or is not an @code{Object} in the usual sense can be +quite well hidden if you are casually looking at the object creation code. +The designers of the system had long and involved discussions on this issue +and in the end decided that mnemonic aids such as Hungarian notation were a +stylistic thing and you should just refer to the system documentation to +determine what objects are @command{ns-3} @code{Objects} and what the APIs +of those @code{Objects} actually are (RTFM --- as in Read the Fine Manual, +of course). + +@cindex AggregateObject +@cindex Object +In the case of @code{Ipv4Impl}, you know that the class inherits somehow +from @code{Object} since there is a call to @code{AggregateObject} that +refers to an instance of an @code{Ipv4Impl}. You will have to go to +the header file @code{src/internet-stack/ipv4-impl.h} and find that +@code{Ipv4Impl} inherits from class @code{Ipv4}. You will then have go to +the file @code{src/node/ipv4.h} and see that it inherits from @code{Object} and +defines a @code{GetTypeId}. Thus the @code{Object} for which you can +@code{GetObject} is really the @code{Ipv4 Object}. + +Returning to some real @command{ns-3} example code, lets take a look at +@code{examples/simple-point-to-point.cc}. You will find the following +code in this file: + +@verbatim + Ptr n0 = CreateObject (); + ... + Ptr ipv4; + ipv4 = n0->GetObject (); + ipv4->SetDefaultRoute (Ipv4Address (``10.1.1.2''), 1); +@end verbatim + +@cindex InternetNode +@cindex Node +@cindex Object +@cindex GetObject +The first line creates an @code{InternetNode} implementation object and casts +the resulting smart pointer to a @code{Node} as we have discussed extensively. +The next line shown declares a smart pointer to an @code{Ipv4 Object}. We +then do a @code{GetObject} on the @code{Node} looking for the +@code{Ipv4 Object}. You know since you've read every line of this tutorial +in detail exactly how that @code{Ipv4 Object} got into every @code{Node}. You +know that the @code{GetObject} will return a smart pointer to its aggregated +@code{Ipv4} Interface. Once we have the @code{Ipv4} smart pointer, we simply +use it as if it were any other C++ object. The last line shows this by +setting the default route for the node. + +@section Caveats +There are a few things that you should remember but which may not be +immediately obvious. + +@subsection Ns-3 Objects are Associated with Classes not C++ objects +@cindex Object +@cindex GetObject +@cindex iterate +@cindex aggregation +@cindex GetNDevices +Okay, you can see some of the problems with the terminology popping up again. +We are reminding you that when you do a GetObject you are providing the key +to the lookup by giving a class name and not anything that is unique to a +C++ object. + +You cannot add more than one @code{Object} of a given type (class name) to an +aggregation. If you need to contain a number of @code{Objects} of the same +type in the same aggregation, you will need to provide a separate container +over which you can iterate. For example, the @code{Node} class provides +methods, + +@verbatim + uint32_t GetNDevices (void) const; + Ptr GetDevice (uint32_t index) const; +@end verbatim + +that are used iterate over the multiple @code{NetDevice} @code{Objects} +associated with it. + +@emph{Remember: Object types do not identify objects.} + +@subsection Dont use GetObject to Check Your Own Type. +@cindex GetObject +It is tempting to use @code{GetObject} as a form of runtime type +information. Dont do it. You have no control over what @emph{other} +object may be added to your aggregation. Someone else may have +appropriated (reimplemented) your type and aggregated themselves onto the +aggregation. + +Consider a socket factory implementation. Sockets can be either UDP sockets +or TCP sockets. A socket factory will have a generic @code{SocketFactory} +Object and either a UDP specific interface for setting UDP parameters or a +similar TCP-specific interface. + +Consider what might happen if you declared your socket factory as a partially +abstract base class, and then provided separate implementations for UDP and +TCP specific methods of this factory in separate concrete classes. Now +consider what might happen if you used @code{GetObject} in your base class +to determine if you were a UDP or a TCP factory. + +If a factory, say the UDP version, were not aggregated to any other +@code{Object}, the base class could @code{GetObject} on itself for the +UDP-specific class name. If the @code{GetObject} succeeded, it could then +infer that it was a UDP implementation and would then do any UDP-specific +tasks it could. [Experienced C++ folks are cringing about how +horrible this design is, but bear with me --- its a simple illustration of +a specific and perhaps not-too-obvious problem.] + +If another factory, say the TCP version, were not aggregated to any other +Interface, the base class could @code{GetObject} on itself for the UDP-specific +interface. If this failed, it could then infer that it had a TCP +implementation and would then do any TCP-specific tasks it could. + +Now, what happens when these two working objects are aggregated together by +some innocent end-user. Since the @code{Objects} are conceptually snapped +together, the TCP implementation would suddenly begin finding the UDP +Interface from the other class factory and think it was the UPD implementation. + +@emph{Objects should not be used as run-time type information.} + +@section Connecting the Dots +@cindex Object +@cindex GetObject +@cindex AggregateObject +@cindex GetTypeId +@cindex API +This may all sound very complicated to you if this is your first exposure to +these concepts. It may be annoying if I tell you that its really not as hard +as it sounds. Rest assured that if you take some time, look at and understand +the examples and write a little test code it will all come together for you. +Grep around the system for @code{AggregateObject} and @code{GetObject} and +take a look at how we have used them. This will also give you a good idea of +what our core @code{Objects} and associated APIs are. If you grep for +@code{GetTypeId} you will find most, if not all of the @code{Object} API +interface declarations in the system. The more you see this idiom in +use, the more comfortable you will be with the idea and the more you will see +how this addresses the weak base class, swiss army knife base class, and +fragile base class problems I explained at the beginning. + +As I alluded to earlier, the developers had long discussions regarding how to +make navigating the @code{Object} environment easier. The primary issue was +how we could make it easier to convey to you, the model writer, that an object +was an @code{Object}. We originally used similar terminology as Microsoft +COM and used QueryInterface instead of @code{GetObject}. One suggestion was +to adopt the convention that classes that implemented Interfaces must begin +with the letter I. Microsoft does this, as exemplified by the class IUnknown. +We also toyed with the idea of beginning our header files with ``i-'' as in +``i-ipv4.h.'' We considered forcing some structure on Interfaces with a pure +virtual class specification, the names of which begin with an I; and +corresponding implementations, the names of which begin with a C. This all +got out of hand fairly quickly. + +In the end we decided that we were really discussing issues of programming +style, and we really could not come up with a strong reason to impose any +particular solution. No matter what direction we took, we ended up with some +form of extra confusion or extra complexity somewhere in the system. The +resulting system is extremely flexible and easy to use. It is, unfortunately, +sometimes hard to document and talk about. + +@cindex Feynman +If it helps you to think in terms of Microsoft COM and Interfaces, by all means +do so, just be aware that even though @command{ns-3} @code{Objects} descend +from COM in some sense, there are subtle differences that may get you lost or +into trouble. So to paraphrase Feynman one more time, + +@quotation +``@command{Ns-3} @code{Objects} do not behave like COM Components, or Java +Beans, or CORBA objects, or clouds or weights on springs, or like anything +that you have ever seen --- they are @command{ns-3} components.'' +@end quotation + +Just get very familiar with the @command{ns-3} object model. It is the heart +of the system and if you do not understand it you will not understand how to +write an @command{ns-3} model properly. + +@c ======================================================================== +@c Doxygen +@c ======================================================================== + +@node The-Doxygen-Documentation-System +@chapter The Doxygen Documentation System + +@node How-To-Change-Things +@chapter How to Change Things + +@node How-To-Set-Default-Values +@chapter How to Set Default Values + +@node How-To-Write-A-New-Application +@chapter How to Write a New Application + diff --git a/doc/tutorial/in-process/output.texi b/doc/tutorial/in-process/output.texi new file mode 100644 index 000000000..185608b42 --- /dev/null +++ b/doc/tutorial/in-process/output.texi @@ -0,0 +1,462 @@ + +@c ======================================================================== +@c Simulation Output +@c ======================================================================== + +@node Simulation Output +@chapter Simulation Output + +At this point, you should be able to execute any of the built-in +programs distributed with @command{ns-3}. Next, we will look at +how to generate and tailor the simulation output, before turning +to how to modify simulation scripts to do different things. + +@node Tracing Basics +@section Tracing Basics + +The whole point of simulation is to generate output for further +study, and the @command{ns-3} tracing system is a primary +mechanism for this. +Since @command{ns-3} is a C++ program, standard facilities for +generating output from C++ programs apply: + +@verbatim +#include +... +int main () +{ + ... + std::cout << "The value of x is " << x << std::endl; + ... +} +@end verbatim + +The goal of the @command{ns-3} tracing system is to +provide a structured way to configure the simulator to output results +in standard or modifiable formats. +@itemize @bullet +@item For basic tasks, the tracing system should allow the user to +generate standard tracing for popular tracing sources, and to customize +which objects generate the tracing. +@item Intermediate users will be able to extend the tracing system to +modify the output format generated, or to insert new tracing sources, +without modifying the core of the simulator. +@item Advanced users can modify the simulator core to add new +tracing sources and sinks. +@end itemize + +The @command{ns-3} tracing system is fundamentally built on the +concept of separating tracing sources from sinks. +@enumerate +@item Trace sources (e.g., provide access to every packet received) +@item Trace sinks (e.g., print out the packet) +@item A mechanism to tie together sources and sinks +@end enumerate +The rationale for this division is to allow users to attach new +types of sinks to existing tracing sources, without requiring +users to edit and recompile the core of the simulator. +Thus, in the example above, a user could write a new tracing sink +and attach it to an existing tracing source. What remains to +be defined is a way for users to find these hooks (tracing sources) +and attach sinks to them. A new tracing namespace is defined for +this purpose. + +We will first walk through how some pre-defined sources and sinks +are provided and may be customized with little user effort. We +return later in this chapter to advanced tracing configuration including +extending the tracing namespace and creating new tracing sources. + +@subsection ASCII tracing +@cindex ASCII +For Internet nodes, the ASCII trace wrapper is a wrapper around +the @command{ns-3} low-level +tracing system that lets you get access to underlying trace events easily. +The output of a trace of a simulation run is an ASCII file --- thus the name. +In the spririt of keeping things simple, you won't be able to control or +configure the output at this stage. + +For those familiar with @command{ns-2} output, this type of trace is +analogous to the @command{out.tr} generated by many scripts. + +@cindex tracing packets +Let's just jump right in. As usual, we need to include the definitions +related to using ASCII tracing (don't edit any files quite yet): + +@verbatim + #include "ns3/ascii-trace.h" +@end verbatim + +We then need to add the code to the script to actually enable the ASCII tracing +code. The following code must be inserted before the call to +@code{Simulator::Run ();}: + +@verbatim + AsciiTrace asciitrace ("tutorial.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); +@end verbatim + +The first line declares an object of type @code{AsciiTrace} named +@code{asciitrace} and passes a string parameter to its constructor. This +parameter is a file name to which all of the trace information will be written. +The second line, @code{asciitrace.TraceAllQueues ();} asks the trace object to +arrange that all queue operations (enqueue, dequeue, drop) on the queues +in all of the nodes of the system be traced. On the receive side, +@code{asciitrace.TraceAlllNetDeviceRx ()} traces packets received by +a NetDevice. For those familiar with @command{ns-2}, these are equivalent +to the popular trace points that log "+", "-", "d", and "r" events. + +Try running the following program from the command line: +@verbatim + ./waf --run tutorial-csma-echo-ascii-trace +@end verbatim + +@cindex tutorial.tr +Just as you have seen previously, you will see some messages from @emph{Waf} +and then the ``Compilation finished successfully'' message. The +next message, @code{UDP Echo Simulation} is from the running program. When +it ran, the program will have created a file named @code{tutorial.tr}. +Because of the way that Waf works, the file is not created in the local +directory, it is created at the top-level directory of the repository. So, +change into the top level directory and take a look at the file +@code{tutorial.tr} in your favorite editor. + +@subsubsection Parsing Ascii Traces +@cindex parsing ascii traces + +This section parses in detail the structure of the ascii tracing +output. If you find this output format self explanatory (it +resembles tcpdump output), you may skip to the next +section on pcap tracing. + +@cindex trace event +There's a lot of information there in a pretty dense form, but the first thing +to notice is that there are a number of distinct lines in this file. It may +be difficult to see this clearly unless you widen your windows considerably. +Each line in the file corresponds to a @emph{trace event}. A trace event +happens whenever specific conditions happen in the simulation. In this case +we are tracing events on the @emph{device queue} present in every net device +on every node in the simulation. The device queue is a queue through which +every packet destined for a channel must pass --- it is the device +@emph{transmit} queue. Note that each line in the trace file begins with a +lone character (has a space after it). This character will have the following +meaning: + +@cindex enqueue +@cindex dequeue +@cindex drop +@itemize @bullet +@item @code{+}: An enqueue operation occurred on the device queue; +@item @code{-}: A dequeue operation occurred on the device queue; +@item @code{d}: A packet was dropped, typically because the queue was full. +@end itemize + +Let's take a more detailed view of the first line. I'll break it down into +sections (indented for clarity) with a two digit reference number on the +left side: + +@verbatim + 00 + + 01 2 + 02 nodeid=0 + 03 device=0 + 04 queue-enqueue + 05 pkt-uid=9 + 06 ETHERNET + 07 length/type=0x806, + 08 source=08:00:2e:00:00:00, + 09 destination=ff:ff:ff:ff:ff:ff + 10 ARP(request + 11 source mac: 08:00:2e:00:00:00 + 12 source ipv4: 10.1.1.1 + 13 dest ipv4: 10.1.1.2) + 14 ETHERNET fcs=0 +@end verbatim + +@cindex trace event +@cindex simulation time +The first line of this expanded trace event (reference number 00) is the +queue operation. We have a @code{+} character, so this corresponds to an +@emph{enqueue} operation. The second line (reference 01) is the simulation +time expressed in seconds. You may recall that we asked the +@code{UdpEchoClient} to start sending packets at two seconds. Here we see +confirmation that this is, indeed, happening. + +@cindex node number +@cindex net device number +@cindex smart pointer +The next lines of the example listing (references 02 and 03) tell us that +this trace event originated in a given node and net device. Each time a node +is created it is given an identifying number that monotonically increases from +zero. Therefore, @code{nodeid=0} means that the node in which the given trace +event originated is the first node we created. In the case of our script, +this first node is is the node pointed to by the smart pointer @code{n0}. Not +too surpsisingly, this is also the node to which we attached the +@code{UdpEchoClient}. The device number is local to each node, and so the +device given by @code{device=0} is the first net device that we added to the +node in question. In our simulation, this corresponds to the +@code{CsmaNetDevice} we added to node zero (@code{n0}). + +@cindex uid +@cindex unique ID +@cindex packet +The next line (reference 04) is a more readable form of the operation code +seen in the first line --- i.e., the character @code{+} means +@code{queue-enqueue}. Reference number 05 indicates that the @emph{unique id} +of the packet being enqueued is @code{9}. The fact that the first packet we +see has a unique ID of 9 should indicates to you that other things have +happened in the protocol stack before we got to this point. This will become +clear momentarily. + +@cindex Ethernet +@cindex MAC address +Reference items 06 and 14 indicate that this is an Ethernet packet with +a zero (not computed) checksum (note the indentation to make parsing this +trace event a little easier). Reference 08 and 09 are the source and +destination addresses of this packet. The packet is from the MAC address we +assigned to the node zero net device in the script, and is destined for the +broadcast address --- this is a broadcast packet. + +@cindex Address Resolution Protocol +@cindex ARP +@cindex ARP|request +Reference items 10 through 13 make clear what is happening. This is an ARP +(Address Resolution Protocol) request for the MAC address of the node on +which the @code{UdpEchoServer} resides. The protocol stack can't send a UDP +packet to be echoed until it knows (resolves) the MAC address; and this trace +event corresponds to an ARP request being queued for transmission to the local +network. The next line in the trace file (partially expanded), + +@verbatim + 00 - + 01 2 + 02 nodeid=0 + 03 device=0 + 04 queue-dequeue + 05 pkt-uid=9 + ... +@end verbatim + +shows the (same) ARP request packet being dequeued from the device queue by +the net device and (implicitly) being sent down the channel to the broadcast +MAC address. We are not tracing net device reception events so we don't +actually see all of the net devices receiving the broadcast packet. We do, +however see the following in the third line of the trace file: + +@verbatim + 00 + + 01 2.00207 + 02 nodeid=1 + 03 device=0 + 04 queue-enqueue + 05 pkt-uid=10 + 06 ETHERNET + 07 length/type=0x806, + 08 source=08:00:2e:00:00:01, + 09 destination=08:00:2e:00:00:00, + 10 ARP(reply + 11 source mac: 08:00:2e:00:00:01 + 12 source ipv4: 10.1.1.2 + 13 dest mac: 08:00:2e:00:00:00 + 14 dest ipv4: 10.1.1.1) + 15 ETHERNET fcs=0 +@end verbatim + +@cindex simulation time +@cindex ARP|response +Notice that this is a queue-enqueue operation (references 00 and 04) happening +on node one (reference 02) at simulation time 2.00207 seconds (reference 01). +Looking at the packet payload (references 10-14) we see that this is an ARP +reply to the request sent by node one. Note that the simulation time +(reference 01) is now 2.00207 seconds. This is direct result of the data rate +(5 mb/s) and latency (2 ms) parameters that we passed to the +@code{CsmaChannel} when we created it. Clearly the ARP request packet was +sent over the channel and received approximately 2 ms later by node one. A +corresponding ARP response packet was created and enqueued on node one's net +device. It is this enqueue trace event that has being logged. + +@cindex queue +@cindex queue|transmit +@cindex echo +Given the current state of affairs, the next thing you may expect to see is +this ARP request being received by node zero, but remember we are only looking +at trace events on the device @emph{transmit} queue. The reception of the ARP +response by node zero will not directly trigger any trace event in this case, +but it will enable the protocol stack to continue what it was originally doing +(trying to send an echo packet). Thus, the next line we see in the trace file +(@code{tutorial.tr}) is the first UDP echo packet being sent to the net device. + +@verbatim + 00 + + 01 2.00415 + 02 nodeid=0 + 03 device=0 + 04 queue-enqueue + 05 pkt-uid=7 + 06 ETHERNET + 07 length/type=0x800, + 08 source=08:00:2e:00:00:00, + 09 destination=08:00:2e:00:00:01 + 10 IPV4( + 11 tos 0x0 + 12 ttl 64 + 13 id 0 + 14 offset 0 + 15 flags [none] + 16 length: 1052) 10.1.1.1 > 10.1.1.2 + 17 UDP(length: 1032) + 18 49153 > 7 + 19 DATA (length 1024) + 20 ETHERNET fcs=0 +@end verbatim + +@cindex simulation time +@cindex echo +@cindex ARP +@cindex ARP|request +@cindex ARP|response +@cindex IP +@cindex Ipv4 +I won't go into too much detail about this packet, but I will point out a +few key items in the trace. First, the packet was enqueued at simulation time +of 2.00415 seconds. This time reflects the fact that the echo client +application started at 2. seconds and there were two ARP packets transmitted +across the network (two milliseconds + data transmission time each way). The +packet unique identifier (reference 05) is 7. Notice that this is a lower +number than the ARP request packet, which had a unique ID of 9. This tells +us that the UDP packet was actually created before the ARP request packet --- +which makes perfect sense since it was the attempt to send packet 7 that +triggered sending the ARP request packet 9. Note that this an Ethernet +packet (reference 06) like all other packets in this simulation, however this +particular packet carries an IPV4 payload and therefore has an IP version 4 +header (indicated by references 10-16). This Ipv4 in turn contains a UDP +header (references 17, 18) and finally 1024 bytes of data (reference 20). +Clearly, this is the UDP echo packet emitted by the +@code{UdpEchoClient Application}. + +The next trace event is an ARP request from node one. We can infer that node +one has received the UDP echo packet and the @code{UdpEchoServer Application} +on that node has turned the packet around. Just as node zero needed to ARP +for the MAC address of node one, now node one must ARP for the MAC address of +node zero. We see the ARP request enqueued on the transmit queue of node one; +then we see the ARP request dequeued from the tranmit queue of node one (and +implicitly transmitted to node zero). Then we see an ARP response enqueued +on the transmit queue of node zero; and finally the ARP response dequeued (and +implicitly transmitted back to node one). + +This exchange is summarized in the following trace event excerpts, + +@verbatim + + 2.00786 nodeid=1 ... ARP(request ... + - 2.00786 nodeid=1 ... ARP(request ... + + 2.00994 nodeid=0 ... ARP(reply ... + - 2.00994 nodeid=0 ... ARP(reply ... +@end verbatim + +The final two trace events in the @code{tutorial.tr} file correspond to the +echoed packet being enqueued for transmission on the net device for node one, +and that packet being dequeued (and implicitly transmitted back to node zero). + +@cindex AsciiTrace!TraceAllNetDeviceRx +@cindex ARP!request +If you look at the trace file (@code{tutorial.tr}) you will also see some +entries with an @code{r} event, indicating a +@emph{receive} trace event. Recall that the first packet sent on the network +was a broadcast ARP request. We should then see all four nodes receive a +copy of this request. This is the case, as the first four receive trace +events are, + +@verbatim + r 2.00207 nodeid=0 device=0 dev-rx pkt-uid=9 ARP(request ... + r 2.00207 nodeid=1 device=0 dev-rx pkt-uid=9 ARP(request ... + r 2.00207 nodeid=2 device=0 dev-rx pkt-uid=9 ARP(request ... + r 2.00207 nodeid=3 device=0 dev-rx pkt-uid=9 ARP(request ... +@end verbatim + +@cindex unique ID +You can see that a copy of the broadcast packet with unique ID 9 was received +by the net devices on nodes 0, 1, 2 and 3. We leave it up to you to parse the +rest of the trace file and understand the remaining reception events. + +@subsection PCAP Trace Wrapper +@cindex pcap +@cindex Wireshark +The @command{ns-3} @emph{pcap trace wrapper} is used to create trace files in +@code{.pcap} format. The acronym pcap (usually written in lower case) stands +for @emph{p}acket @emph{cap}ture, and is actually an API that includes the +definition of a @code{.pcap} file format. The most popular program that can +read and display this format is Wireshark (formerly called Ethereal). +However, there are many traffic trace analyzers that use this packet +format, including X, Y, and Z. We encourage users to exploit the +many tools available for analyzing pcap traces; below, we show how +tcpdump and Wireshark can be used.. + +@cindex tutorial-csma-echo-ascii-trace.cc +@cindex tutorial-csma-echo-pcap-trace.cc +The code used to enable pcap tracing is similar to that for ASCII tracing. +We have provided another file, @code{tutorial-csma-echo-pcap-trace.cc} that +uses the pcap trace wrapper. We have added the code to include the pcap +trace wrapper defintions: + +@verbatim + #include "ns3/pcap-trace.h" +@end verbatim + +And then added the following code below the AsciiTrace methods: + +@cindex PcapTrace +@cindex PcapTrace!TraceAllIp +@verbatim + PcapTrace pcaptrace ("tutorial.pcap"); + pcaptrace.TraceAllIp (); +@end verbatim + +The first line of the code immediately above declares an object of type +@code{PcapTrace} named @code{pcaptrace} and passes a string parameter to its +constructor. This object is used to hide the details of the actual tracing +subsystem. The parameter is a base file name from which the actual trace file +names will be built. The second line of code tells the @code{PcamTrace} +object to trace all IP activity in all of the nodes present in the simulation. + +@cindex interface index +Trace files are not created until trace activity is detected. Each file name +is composed of the base file name, followed by a @code{'-'}, a node id followed +by a @code{'-}', and an IP interface index. You will soon see a file named +@code{tutorial.pcap-0-1}, for example. This will be the trace file generated +as events are detected on node zero, interface index one. N.B. Interface +indices are different that net device indices --- interface index zero +corresponds to the loopback interface and interface index one corresponds to +the first net device you added to a node. + +You may run the new program just like all of the others so far: + +@cindex Waf +@verbatim + ./waf --run tutorial-csma-echo-pcap-trace +@end verbatim + +If you look at the top level directory of your distribution, you should now +see three log files: @code{tutorial.tr} is the ASCII trace file we have +previously examined. @code{tutorial.pcap-0-1} and @code{tutorial.pcap-1-1} +are the new pcap files we just generated. There will not be files +corresponding to nodes two and three since we have not sent any IP packets to +those nodes. + +@subsubsection Reading output with tcpdump +@cindex tcpdump + +@subsubsection Reading output with Wireshark +@cindex Wireshark +If you are unfamilar with Wireshark, there is a web site available from which +you can download programs and documentation: @uref{http://www.wireshark.org/}. + +If you have Wireshark available, you can open each of the trace files and +display the contents as if you had captured the packets using a +@emph{packet sniffer}. Note that only IP packets are traced using this +wrapper, so you will not see the ARP exchanges that were logged when using +the ASCII trace wrapper. You are encouraged to take a look at the contents +of these pcap files using your favorite pcap software (or Wireshark). + +@node Advanced Tracing +@section Advanced Tracing + diff --git a/doc/tutorial/in-process/statistics.texi b/doc/tutorial/in-process/statistics.texi new file mode 100644 index 000000000..094e91a4b --- /dev/null +++ b/doc/tutorial/in-process/statistics.texi @@ -0,0 +1,9 @@ +@node Statistics +@chapter Statistics +@anchor{chap:Statistics} + +ns-3 does not presently have support for statistics (automatically generated +statistical output). This is planned +for development later in 2008. If you are interested in contributing, +please see @uref{http://www.nsnam.org/wiki/index.php/Suggested_Projects,,our suggested projects page} or contact the ns-developers +list. diff --git a/doc/tutorial/in-process/troubleshoot.texi b/doc/tutorial/in-process/troubleshoot.texi new file mode 100644 index 000000000..6ac901d15 --- /dev/null +++ b/doc/tutorial/in-process/troubleshoot.texi @@ -0,0 +1,82 @@ +@node Troubleshooting +@chapter Troubleshooting + +This chapter posts some information about possibly common errors in building +or running ns-3 programs. + +Please note that the wiki (@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting}) may have contributed items. + +@node Build errors +@section Build errors + +@node Run-time errors +@section Run-time errors + +Sometimes, errors can occur with a program after a successful build. These +are run-time errors, and can commonly occur when memory is corrupted or +pointer values are unexpectedly null. + +Here is an example of what might occur: + +@verbatim +ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point +Entering directory `/home/tomh/ns-3-nsc/build' +Compilation finished successfully +Command ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] exited with code -11 +@end verbatim + +The error message says that the program terminated unsuccessfully, but it is +not clear from this information what might be wrong. To examine more +closely, try running it under the @uref{http://sources.redhat.com/gdb/,,gdb debugger}: + +@verbatim +ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="gdb %s" +Entering directory `/home/tomh/ns-3-nsc/build' +Compilation finished successfully +GNU gdb Red Hat Linux (6.3.0.0-1.134.fc5rh) +Copyright 2004 Free Software Foundation, Inc. +GDB is free software, covered by the GNU General Public License, and you are +welcome to change it and/or distribute copies of it under certain conditions. +Type "show copying" to see the conditions. +There is absolutely no warranty for GDB. Type "show warranty" for details. +This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1". + +(gdb) run +Starting program: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point +Reading symbols from shared object read from target memory...done. +Loaded system supplied DSO at 0xf5c000 + +Program received signal SIGSEGV, Segmentation fault. +0x0804aa12 in main (argc=1, argv=0xbfdfefa4) + at ../examples/tcp-point-to-point.cc:136 +136 Ptr localSocket = socketFactory->CreateSocket (); +(gdb) p localSocket +$1 = {m_ptr = 0x3c5d65} +(gdb) p socketFactory +$2 = {m_ptr = 0x0} +(gdb) quit +The program is running. Exit anyway? (y or n) y +@end verbatim + +Note first the way the program was invoked-- pass the command to run as +an argument to the command template "gdb %s". + +This tells us that there was an attempt to dereference a null pointer +socketFactory. + +Let's look around line 136 of tcp-point-to-point, as gdb suggests: +@verbatim + Ptr socketFactory = n2->GetObject (Tcp::iid); + Ptr localSocket = socketFactory->CreateSocket (); + localSocket->Bind (); +@end verbatim + +The culprit here is that the return value of GetObject is not being +checked and may be null. + +Sometimes you may need to use the @uref{http://valgrind.org,,valgrind memory +checker} for more subtle errors. Again, you invoke the use of valgrind +similarly: +@verbatim +ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="valgrind %s" +@end verbatim diff --git a/doc/tutorial/in-process/tutorial.css b/doc/tutorial/in-process/tutorial.css new file mode 100644 index 000000000..a7586ac83 --- /dev/null +++ b/doc/tutorial/in-process/tutorial.css @@ -0,0 +1,156 @@ +body { + font-family: "Trebuchet MS", "Bitstream Vera Sans", verdana, lucida, arial, helvetica, sans-serif; + background: white; + color: black; + font-size: 11pt; +} + +h1, h2, h3, h4, h5, h6 { +# color: #990000; + color: #009999; +} + +pre { + font-size: 10pt; + background: #e0e0e0; + color: black; +} + +a:link, a:visited { + font-weight: normal; + text-decoration: none; + color: #0047b9; +} + +a:hover { + font-weight: normal; + text-decoration: underline; + color: #0047b9; +} + +img { + border: 0px; +} + +#main th { + font-size: 12pt; + background: #b0b0b0; +} + +.odd { + font-size: 12pt; + background: white; +} + +.even { + font-size: 12pt; + background: #e0e0e0; +} + +.answer { + font-size: large; + font-weight: bold; +} + +.answer p { + font-size: 12pt; + font-weight: normal; +} + +.answer ul { + font-size: 12pt; + font-weight: normal; +} + +#container { + position: absolute; + width: 100%; + height: 100%; + top: 0px; +} + +#feedback { + color: #b0b0b0; + font-size: 9pt; + font-style: italic; +} + +#header { + position: absolute; + margin: 0px; + top: 10px; + height:96px; + left: 175px; + right: 10em; + bottom: auto; + background: white; + clear: both; +} + +#middle { + position: absolute; + left: 0; + height: auto; + width: 100%; +} + +#main { + position: absolute; + top: 50px; + left: 175px; + right: 100px; + background: white; + padding: 0em 0em 0em 0em; +} + +#navbar { + position: absolute; + top: 75px; + left: 0em; + width: 146px; + padding: 0px; + margin: 0px; + font-size: 10pt; +} + +#navbar a:link, #navbar a:visited { + font-weight: normal; + text-decoration: none; + color: #0047b9; +} + +#navbar a:hover { + font-weight: normal; + text-decoration: underline; + color: #0047b9; +} + +#navbar dl { + width: 146px; + padding: 0; + margin: 0 0 10px 0px; + background: #99ffff url(images/box_bottom2.gif) no-repeat bottom left; +} + +#navbar dt { + padding: 6px 10px; + font-size: 100%; + font-weight: bold; + background: #009999; + margin: 0px; + border-bottom: 1px solid #fff; + color: white; + background: #009999 url(images/box_top2.gif) no-repeat top left; +} + +#navbar dd { + font-size: 100%; + margin: 0 0 0 0px; + padding: 6px 10px; + color: #0047b9; +} + +dd#selected { + background: #99ffff url(images/arrow.gif) no-repeat; + background-position: 4px 10px; +} diff --git a/doc/tutorial/in-process/tutorial.texi b/doc/tutorial/in-process/tutorial.texi new file mode 100644 index 000000000..d2e7a4813 --- /dev/null +++ b/doc/tutorial/in-process/tutorial.texi @@ -0,0 +1,105 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename ns-3.info +@settitle ns-3 tutorial +@c @setchapternewpage odd +@c %**end of header + +@ifinfo +Primary documentation for the @command{ns-3} project is available in +three forms: +@itemize @bullet +@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator +@item Tutorial (this document) +@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} +@end itemize + +This document is written in GNU Texinfo and is to be maintained in +revision control on the @command{ns-3} code server. Both PDF and HTML versions +should be available on the server. Changes to +the document should be discussed on the ns-developers@@isi.edu mailing list. +@end ifinfo + +@copying + +This is an @command{ns-3} tutorial. +Primary documentation for the @command{ns-3} project is available in +three forms: +@itemize @bullet +@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator +@item Tutorial (this document) +@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} +@end itemize + +This document is written in GNU Texinfo and is to be maintained in +revision control on the @command{ns-3} code server. Both PDF and HTML +versions should be available on the server. Changes to +the document should be discussed on the ns-developers@@isi.edu mailing list. + +This software is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This software 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, see @uref{http://www.gnu.org/licenses/}. +@end copying + +@titlepage +@title ns-3 Tutorial +@author ns-3 project +@author feedback: ns-developers@@isi.edu +@today{} + +@c @page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + +@c So the toc is printed at the start. +@anchor{Full Table of Contents} +@contents + +@ifnottex +@node Top, Overview, Full Table of Contents +@top ns-3 Tutorial (html version) + +For a pdf version of this tutorial, +see @uref{http://www.nsnam.org/docs/tutorial.pdf}. + +@insertcopying +@end ifnottex + +@menu +* Tutorial Goals:: +Part 1: Getting Started with ns-3 +* Overview:: +* Browsing:: +* Resources:: +* Downloading and Compiling:: +* Some-Prerequisites:: +Part 2: Reading ns-3 Programs +* A-First-ns-3-Script:: +Part 3: Reconfiguring Existing ns-3 Scripts +* Logging:: +* ns-3 Attributes:: +* Tracing:: +* Statistics:: +Part 4: Creating New or Revised Topologies +* Helper Functions:: +@end menu + +@include introduction.texi +@include log.texi +@include attributes.texi +@include statistics.texi +@include helpers.texi + +@printindex cp + +@bye diff --git a/doc/tutorial/introduction.texi b/doc/tutorial/introduction.texi index 248120e3f..6580bcbb7 100644 --- a/doc/tutorial/introduction.texi +++ b/doc/tutorial/introduction.texi @@ -3,39 +3,6 @@ @c Begin document body here @c ======================================================================== -@c ======================================================================== -@c Tutorial Goals -@c ======================================================================== - -@node Tutorial Goals -@unnumbered Tutorial Goals - -@c This is an unnumbered section, like a preface. Numbering -@c starts with section 1 (Introduction) - -The goal of this ns-3 tutorial is to introduce new users of ns-3 to enough -of the system to enable them to author simple simulation scripts and extract -useful information from the simulations. We begin by introducing some of the -other important resources that are available to those interested in using or -writing scripts, models and even those interested in making contributions to -the core ns-3 system. We provide an overview of some of the -important abstractions, design patterns and idioms used when writing -ns-3 scripts, and then dig right in by begining to write simulation -scripts, run them and interpret results. - -After completing this tutorial, one should be able to: -@itemize @bullet -@item Find documentation resources in the distribution and on the web; -@item Download and compile the ns-3 system; -@item Understand the key software conventions of ns-3; -@item Modify configuration parameters of existing scripts; -@item Change the simulation output (tracing, logging, statistics); -@item Extend the simulator to use new objects -@item Write new ns-3 applications; -@item See how to port code from ns-2; -@item ... (more to follow) -@end itemize - @c ======================================================================== @c PART: Introduction @c ======================================================================== @@ -43,171 +10,133 @@ After completing this tutorial, one should be able to: @c This is similar to the Latex \part command @c @c ======================================================================== -@c Overview +@c Introduction @c ======================================================================== -@node Overview -@chapter Overview +@node Introduction +@chapter Introduction @menu -* For ns-2 users:: +* For ns-2 Users:: * Contributing:: -* Tutorial organization:: +* Tutorial Organization:: @end menu -The ns-3 simulator is a discrete-event network -simulator targeted primarily for research and educational use. -The @uref{http://www.nsnam.org,,ns-3 project}, started in -2006, is an open-source project. The goal of the project is to -build a new network simulator primarily for research and educational use. +The @command{ns-3} simulator is a discrete-event network simulator targeted +primarily for research and educational use. The +@uref{http://www.nsnam.org,,ns-3 project}, +started in 2006, is an open-source project developing ns-3. -Primary documentation for the ns-3 project is available in -three forms: +Primary documentation for the @command{ns-3} project is available in four +forms: @itemize @bullet -@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator +@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: +Documentation of the public APIs of the simulator @item Tutorial (this document) +@item @uref{http://www.nsnam.org/docs/manual.html,,Reference Manual}: Reference Manual @item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} @end itemize -The purpose of this tutorial is to introduce new ns-3 users to the +The purpose of this tutorial is to introduce new @command{ns-3} users to the system in a structured way. It is sometimes difficult for new users to glean essential information from detailed manuals and to convert this information into working simulations. In this tutorial, we will build several example simulations, introducing and explaining key concepts and features as we go. -As the tutorial unfolds, we will introduce the full ns-3 -documentation +As the tutorial unfolds, we will introduce the full ns-3 documentation and provide pointers to source code for those interested in delving deeper into the workings of the system. A few key points are worth noting at the onset: @itemize @bullet -@item ns-3 is not an extension of @uref{http://www.isi.edu/nsnam/ns,,ns-2}; -it is a new -simulator. The two simulators are both written in C++ but ns-3 -is a new simulator that does not support the ns-2 APIs. -Some models from ns-2 have already been ported from ns-2 -to ns-3. The project will continue to maintain ns-2 while -ns-3 is being built, and will study transition and -integration mechanisms. -@item ns-3 is open-source, and the project strives to maintain -an open environment for researchers to contribute and share their -software. +@item Ns-3 is not an extension of @uref{http://www.isi.edu/nsnam/ns,,ns-2}; +it is a new simulator. The two simulators are both written in C++ but +@command{ns-3} is a new simulator that does not support the ns-2 APIs. Some +models from ns-2 have already been ported from ns-2 to ns-3. The project will +continue to maintain ns-2 while ns-3 is being built, and will study transition +and integration mechanisms. +@item @command{Ns-3} is open-source, and the project strives to maintain an +open environment for researchers to contribute and share their software. @end itemize -@node For ns-2 users -@section For ns-2 users +@node For ns-2 Users +@section For ns-2 Users -For those familiar with ns-2, the most visible outward change -when moving to ns-3 is the choice of scripting language. -ns-2 is typically scripted in Tcl and results of simulations can -be visualized using the Network Animator @command{nam}. In -ns-3 there is currently no visualization module, and Python -bindings have been developed (Tcl bindings have been prototyped -using @uref{http://www.swig.org,,SWIG}, but are not supported by the -current development team). -In this tutorial, we will concentrate on -scripting directly in C++ and interpreting results via trace files. +For those familiar with ns-2, the most visible outward change when moving to +ns-3 is the choice of scripting language. Ns-2 is +scripted in OTcl and results of simulations can be visualized using the +Network Animator @command{nam}. It is not possible to run a simulation +in ns-2 purely from C++ (i.e., as a main() program without any OTcl). +Moreover, some components of ns-2 are written in C++ and others in OTcl. +In ns-3, the simulator is written entirely in C++, with optional +Python bindings. Simulation scripts can therefore be written in C++ +or in Python. The results of some simulations can be visualized by +@command{nam}, but new animators are under development. Since ns-3 +generates pcap packet trace files, other utilities can be used to +analyze traces as well. +In this tutorial, we will first concentrate on scripting +directly in C++ and interpreting results via ascii trace files. -But there are similarities as well (both, for example, are based -on C++ objects, and some code from ns-2 has already been ported -to ns-3). We will try to highlight differences between ns-2 and ns-3 +But there are similarities as well (both, for example, are based on C++ +objects, and some code from ns-2 has already been ported to ns-3). +We will try to highlight differences between ns-2 and ns-3 as we proceed in this tutorial. +A question that we often hear is "Should I still use ns-2 or move to +ns-3?" The answer is that it depends. ns-3 does not have all of the +models that ns-2 currently has, but on the other hand, ns-3 does have +new capabilities (such as handling multiple interfaces on nodes +correctly, use of IP addressing and more alignment with Internet +protocols and designs, more detailed 802.11 models, etc.). ns-2 +models can usually be ported to ns-3 (a porting guide is under +development). There is active development on multiple fronts for ns-3. +The ns-3 developers believe (and certain early users have proven) that +ns-3 is ready for active use, and should be an attractive alternative +for users looking to start new simulation projects. + @node Contributing @section Contributing -@cindex software configuration management -ns-3 is a research and educational simulator, by and for the -research community. It will rely on the ongoing contributions of -the community to develop new models, debug or maintain -existing ones, and share results. There are a few policies -that we hope will encourage people to contribute to ns-3 like they -have for ns-2: +@cindex contributing +@command{Ns-3} is a research and educational simulator, by and for the +research community. It will rely on the ongoing contributions of the +community to develop new models, debug or maintain existing ones, and share +results. There are a few policies that we hope will encourage people to +contribute to @command{ns-3} like they have for ns-2: @itemize @bullet -@item open source licensing based on GNU GPLv2 compatibility -@item @uref{http://www.nsnam.org/wiki/index.php,,wiki} +@item Open source licensing based on GNU GPLv2 compatibility; +@item @uref{http://www.nsnam.org/wiki/index.php,,wiki}; @item @uref{http://www.nsnam.org/wiki/index.php/Contributed_Code,,Contributed Code} page, similar to ns-2's popular @uref{http://nsnam.isi.edu/nsnam/index.php/Contributed_Code,,Contributed Code} -page -@item @code{src/contrib} directory (we will host your contributed code) -@item open @uref{http://www.nsnam.org/bugzilla,,bug tracker} -@item ns-3 developers will gladly help potential contributors to get -started with the simulator (please contact @uref{http://www.nsnam.org/people.html,,one of us}) +page; +@item @code{src/contrib} directory (we will host your contributed code); +@item Open @uref{http://www.nsnam.org/bugzilla,,bug tracker}; +@item @command{Ns-3} developers will gladly help potential contributors to get +started with the simulator (please contact @uref{http://www.nsnam.org/people.html,,one of us}). @end itemize -If you are an ns user, please consider to provide your feedback, -bug fixes, or code to the project. +We realize that if you are reading this document, contributing back to +the project is probably not your foremost concern at this point, but +we want you to be aware that contributing is in the spirit of the project and +that even the act of dropping us a note about your early experience +with ns-3 (e.g. "this tutorial section was not clear..."), +reports of stale documentation, etc. are much appreciated. -@node Tutorial organization -@section Tutorial organization +@node Tutorial Organization +@section Tutorial Organization -The tutorial assumes that new users might follow a path such as follows: +The tutorial assumes that new users might initially follow a path such as the +following: @itemize @bullet -@item browse the source code and documentation, to get a feel for -the simulator and what it might be like to handle; -@item try to download and build a copy; -@item try to run a few sample programs, and perhaps change some configurations; -@item look at simulation output, and try to adjust it -@item study the software architecture of the system, to consider hacking it or -extending it; -@item write new models or port existing code to ns-3, and eventually post those -models back to the community. +@item Try to download and build a copy; +@item Try to run a few sample programs; +@item Look at simulation output, and try to adjust it. @end itemize As a result, we have tried to organize the tutorial along the above broad sequences of events. -@c ======================================================================== -@c Browsing ns-3 -@c ======================================================================== - -@node Browsing -@chapter Browsing ns-3 - -@menu -* Source code:: -* Doxygen:: -* Other documentation:: -@end menu - -@node Source code -@section Source code - -The most recent code can be browsed on our web server at the following link: -@uref{http://code.nsnam.org/?sort=lastchange}. If you click on the bold -repository names on the left of the page, you will see changelogs for -these repositories, and links to the @emph{manifest}. From the manifest -links, one can browse the source tree. - -The top-level directory will look something like: -@verbatim - AUTHORS RELEASE_NOTES examples/ src/ waf* - LICENSE VERSION ns3/ tutorial/ waf.bat* - README doc/ samples/ utils/ wscript -@end verbatim -The source code is mainly in the @code{src} directory. Example -scripts are in the @code{examples} directory. Both are good directories -to start browsing some code. - -For ns-2 users, who may be familiar with the @code{simple.tcl} example script -in the ns-2 documentation, an analogous script is found in -@code{examples/simple-point-to-point.cc} with a Python equivalent found -in @emph{(pending Python merge)}. - -@node Doxygen -@section Doxygen - -We document all of APIs using @uref{http://www.stack.nl/~dimitri/doxygen/,,Doxygen}. Current builds of this documentation are available at: -@uref{http://www.nsnam.org/doxygen/index.html}, which are worth an initial -look. - -@node Other documentation -@section Other documentation - -See: @uref{http://www.nsnam.org/documents.html}. - @c ======================================================================== @c Resources @c ======================================================================== @@ -216,38 +145,35 @@ See: @uref{http://www.nsnam.org/documents.html}. @chapter Resources @menu -* The-Web:: +* The Web:: * Mercurial:: * Waf:: -* Environment-Idioms-Design-Patterns:: -* Socket-Programming:: +* Development Environment:: +* Socket Programming:: @end menu -@node The-Web +@node The Web @section The Web @cindex www.nsnam.org -There are several important resources of which any ns-3 user must be -aware. The main web site is located at @uref{http://www.nsnam.org} -and provides access to basic information about the ns-3 system. -Detailed documentation is available through the main web site at -@uref{http://www.nsnam.org/documents.html}. - @cindex documentation @cindex architecture -You can find documents relating to the system architecture from this page, -and also gain access to the detailed software documentation. The software -system is documented in great detail using -@uref{http://www.stack.nl/~dimitri/doxygen/,,Doxygen}. There is a Wiki that -complements the main ns-3 web site which you will find at -@uref{http://www.nsnam.org/wiki/}. +There are several important resources of which any @command{ns-3} user must be +aware. The main web site is located at @uref{http://www.nsnam.org} and +provides access to basic information about the ns-3 system. Detailed +documentation is available through the main web site at +@uref{http://www.nsnam.org/documents.html}. You can also find documents +relating to the system architecture from this page. -You will find user and developer FAQs there as well as troubleshooting guides, -third-party contributed code, papers, etc. The source code may be found -and browsed at @uref{http://code.nsnam.org/}. +There is a Wiki that complements the main ns-3 web site which you will find at +@uref{http://www.nsnam.org/wiki/}. You will find user and developer FAQs +there, as well as troubleshooting guides, third-party contributed code, +papers, etc. -@cindex repository!ns-3-dev -@cindex repository!releases +@cindex mercurial repository +@cindex ns-3-dev repository +@cindex release repository +The source code may be found and browsed at @uref{http://code.nsnam.org/}. There you will find the current development tree in the repository named @code{ns-3-dev}. Past releases and experimental repositories of the core developers may also be found there. @@ -263,7 +189,7 @@ the most well known. @cindex software configuration management @cindex Mercurial -The ns-3 project uses Mercurial as its source code management system. +The @command{ns-3} project uses Mercurial as its source code management system. Although you do not need to know much about Mercurial in order to complete this tutorial, we recommend becoming familiar with Mercurial and using it to access the source code. Mercurial has a web site at @@ -275,8 +201,8 @@ also provides a tutorial at and a QuickStart guide at @uref{http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/}. -You can also find vital information about using Mercurial and ns-3 -on the main ns-3 web site. +You can also find vital information about using Mercurial and @command{ns-3} +on the main @command{ns-3} web site. @node Waf @section Waf @@ -287,26 +213,29 @@ on the main ns-3 web site. Once you have source code downloaded to your local system, you will need to compile that source to produce usable programs. Just as in the case of source code management, there are many tools available to perform this -function. Probably the most famous of these tools is @code{make}. Along -with being the most famous, @code{make} is probably the most difficult to +function. Probably the most well known of these tools is @code{make}. Along +with being the most well known, @code{make} is probably the most difficult to use in a very large and highly configurable system. Because of this, many alternatives have been developed. Recently these systems have been developed using the Python language. -The build system @code{Waf} is used on the ns-3 project. It is one +The build system @code{Waf} is used on the @command{ns-3} project. It is one of the new generation of Python-based build systems. You will not need to understand any Python to build the existing ns-3 system, and will only have to understand a tiny and intuitively obvious subset of Python in order to extend the system in most cases. For those interested in the gory details of Waf, the main web site can be -found at @uref{http://freehackers.org/\~tnagy/waf.html}. +found at @uref{http://freehackers.org/~tnagy/waf.html}. -@node Environment-Idioms-Design-Patterns -@section Environment, Idioms, and Design Patterns +@node Development Environment +@section Development Environment @cindex C++ -As mentioned above, scripting in ns-3 is done in C++. A working +@cindex Python +As mentioned above, scripting in ns-3 is done in C++ or Python. +As of ns-3.2, most of the ns-3 API is available in Python, but the models +are written in C++ in either case. A working knowledge of C++ and object-oriented concepts is assumed in this document. We will take some time to review some of the more advanced concepts or possibly unfamiliar language features, idioms and design patterns as they @@ -317,28 +246,30 @@ in print. If you are new to C++, you may want to find a tutorial- or cookbook-based book or web site and work through at least the basic features of the language -before proceeding. - -@subsection Environment +before proceeding. For instance, +@uref{http://www.cplusplus.com/doc/tutorial/,,this tutorial}. @cindex toolchain @cindex GNU -The ns-3 system uses the GNU ``toolchain'' for development. -A software toolchain is the set of programming tools available in the given +The @command{ns-3} system uses several components of the GNU ``toolchain'' +for development. A +software toolchain is the set of programming tools available in the given environment. For a quick review of what is included in the GNU toolchain see, -@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. +@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. ns-3 uses gcc, +GNU binutils, and gdb. However, we do not use the GNU build system, +either make or autotools, using Waf instead. @cindex Linux -Typically an ns-3 author will work in Linux or a Linux-like +Typically an @command{ns-3} author will work in Linux or a Linux-like environment. For those running under Windows, there do exist environments -which simulate the Linux environment to various degrees. The ns-3 -project supports development in the Cygwin and the MinGW environments for -these users. See @uref{http://www.cygwin.com/} and -@uref{http://www.mingw.org/} for details on downloading and using these -systems. Cygwin provides many of the popular Linux system commands. -It can, however, sometimes be problematic due to the way it -actually does its emulation, and sometimes interactions with other Windows -software can cause problems. +which simulate the Linux environment to various degrees. The @command{ns-3} +project supports development in the Cygwin environment for +these users. See @uref{http://www.cygwin.com/} +for details on downloading (MinGW is presently not supported). +Cygwin provides many of the popular Linux system commands. +It can, however, sometimes be problematic due to the way it actually does its +emulation, and sometimes interactions with other Windows software can cause +problems. @cindex Cygwin @cindex MinGW @@ -352,62 +283,12 @@ crash creating a sh.exe.stackdump file when I try to compile my source code.'' Believe it or not, the @code{Logitech Process Monitor} insinuates itself into every DLL in the system when it is running. It can cause your Cygwin or MinGW DLLs to die in mysterious ways and often prevents debuggers from -running. Beware of Logitech. +running. Beware of Logitech software when using Cygwin. -@subsection Idioms and Design Patterns +Another alternative to Cygwin is to install a virtual machine environment +such as VMware server and install a Linux virtual machine. -@cindex idiom -In any system, there are a number of problems to be solved that happen -repeatedly. Often the solutions to these problems can be generalized and -applied in a similar way across the system. These solutions are called -Design Patterns. The ns-3 system relies on several classic design -patterns. - -@cindex design pattern -Also, in any language, there are constructs that, while they aren't part of the -language per se, are commonly found and useful. For example, at the lowest -level a C programmer should be able to immediately recognize the purpose and -intent of the following code without having to reflect on the details: - -@verbatim - for (;;) -@end verbatim - -These low-level constructs, or idioms, extend upward in complexity, eventually -becoming implementations of design patterns. As you are exposed to more -and more of the ns-3 system, you will begin to recognize and be -comfortable with the C++ implementations (idioms) of several important design -patterns. - -@cindex functor -@cindex callback -@cindex smart pointer -The ns-3 code relies heavily on -@emph{Generalized Functors, Callbacks, -Smart Pointers, Singletons, and Object Factories}. Although we will -not assume any detailed knowledge of the idioms and design patterns used -in the ns-3 -system, it will be useful for readers who intend to delve deeply into the -system to understand some important related concepts. We recommend two -resources: @uref{http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612/,,Design Patterns: Elements of Reusable Object-Oriented Software, Gamma et. al.} and -@uref{http://www.amazon.com/exec/obidos/ASIN/0201704315,,Modern C++ Design: Generic Programming and Design Patterns Applied, Alexandrescu}. - -Gamma addresses the abstract design patterns, and Alexandrescu addresses the -C++ idioms you will often see throughout the ns-3 code. - -@cindex template -Almost any use of ns-3 will require some basic knowledge of C++ -templates. -We will discuss the high-level uses in this tutorial. However, if you venture -deeply into the source code, you will see fairly heavy use of relatively -sophisticated C++ templates in some of low-level modules of the system. The -You don't have to be a template guru to complete this tutorial but if you -expect to work in ns-3 within the simulation core, you will have to be -somewhat fluent -with templates. If you want to truly grok C++ templates we recommend, -@uref{http://www.amazon.com/Templates-Complete-Guide-David-Vandevoorde/dp/0201734842/,,C++ Templates: The Complete Guide, Vandevoorde and Josuttis}. - -@node Socket-Programming +@node Socket Programming @section Socket Programming @cindex sockets @@ -425,1610 +306,5 @@ not have access to a copy of the book, the echo clients and servers shown in the website above) you will be in good shape to understand the tutorial. There is a similar book on Multicast Sockets, @uref{http://www.elsevier.com/wps/product/cws_home/700736,,Multicast Sockets, Makofske and Almeroth}. -that covers material you may need to understand for the multicast examples. - -@c ======================================================================== -@c Downloading and Compiling -@c ======================================================================== - -@node Downloading and Compiling -@chapter Downloading and Compiling - -@cindex Linux -@cindex Cygwin -@cindex GNU -@cindex toolchain -From this point forward, we are going to assume that the reader is working in -Linux or a Linux emulation environment (Linux, Cygwin, etc.) and has the GNU -toolchain installed and verified. - -@cindex Mercurial -@cindex Waf -We are going to assume that you have Mercurial and Waf installed and running -on the target system as described in the Getting Started section of the -ns-3 web site: @uref{http://www.nsnam.org/getting_started.html}. - -@section Downloading -@cindex tarball -The ns-3 code is available in Mercurial repositories on the server -code.nsnam.org. You can download a tarball, but we recommend working with -Mercurial --- it will make your life easier in the long run. - -@cindex repository -If you go to the following link: @uref{http://code.nsnam.org/}, -you will see a number of repositories. Many are the private repositories of -the ns-3 development team. The repositories of interest to you -will be -prefixed with ``ns-3''. The current development snapshot (unreleased) of -ns-3 may be found at: @uref{http://code.nsnam.org/ns-3-dev/}. - -The developers attempt to keep this repository in a consistent, working state -but it is a development area with unreleased code present, so you may want to -consider downloading an official release. - -There will be a number of released repositories present at code.nsnam.org. -These repos will have names like ns-3.0.1 --- which referes to release 3.0.1 -of the network simulator (or if you like, release 0.1 of ns-3). -Since the releases are changing at a rate of one per month, I will stick with -the more constant ns-3-dev here, but you can replace the string ns-3-dev with -your choice of release (e.g., ns-3.0.5) below. You can find the latest -version of the code either by inspection of the repository list or by going -to the ``Getting Started'' web page and looking for the latest release -identifier. - -One practice is to create a directory called @code{repos} in one's home -directory under which one can keep local Mercurial repositories. -@emph{Hint: we will -assume you do this later in the tutorial.} If you adopt that approach, you -can get a copy of any of the development versions of ns-3 by typing -the following into your Linux shell (assuming you have installed Mercurial): - -@verbatim - cd - mkdir repos - cd !$ - hg clone http://code.nanam.org/ns-3-dev -@end verbatim - -As the hg command executes, you should see something like the following, - -@verbatim - destination directory: ns-3-dev - requesting all changes - adding changesets - adding manifests - adding file changes - added 1513 changesets with 5687 changes to 733 files - 358 files updated, 0 files merged, 0 files removed, 0 files unresolved -@end verbatim - -After the clone command completes, you should have a directory called -ns-3-dev under your @code{~/repos} directory, the contents of which should -look something like the following: - -@verbatim - AUTHORS RELEASE_NOTES examples/ src/ waf* - LICENSE VERSION ns3/ tutorial/ waf.bat* - README doc/ samples/ utils/ wscript -@end verbatim - -You are now ready to build the ns-3 distribution. - -@section Building -@cindex Waf!build -@cindex Waf!configure -@cindex Waf!debug -@cindex Waf!compile -We use Waf to build the ns-3 project. The first thing you -will need to do is to configure the build. For reasons that will become clear -later, we are going to work with debug builds in the tutorial. To explain to -Waf that it should do debug builds you will need to execute the following -command, - -@verbatim - ./waf -d debug configure -@end verbatim - -This runs the copy of Waf in the local directory (which is provided as a -convenience for you). As the build system checks for various dependencies -you should see output that looks similar to the following, - -@verbatim - ~/repos/ns-3-dev >./waf -d debug configure - Checking for program g++ : ok /usr/bin/g++ - Checking for program cpp : ok /usr/bin/cpp - Checking for program ar : ok /usr/bin/ar - Checking for program ranlib : ok /usr/bin/ranlib - Checking for compiler could create programs : ok - Checking for compiler could create shared libs : ok - Checking for compiler could create static libs : ok - Checking for flags -Wall : ok - Checking for flags -O2 : ok - Checking for flags -g -DDEBUG : ok - Checking for flags -g3 -O0 -DDEBUG : ok - Checking for g++ : ok - Checking for header stdlib.h : ok - Checking for header stdlib.h : ok - Checking for header signal.h : ok - Checking for high precision time implementation: 128-bit integer - Checking for header stdint.h : ok - Checking for header inttypes.h : ok - Checking for header sys/inttypes.h : not found - Configuration finished successfully; project is now ready to build. - ~/repos/ns-3-dev > -@end verbatim - -The build system is now configured and you can build the debug versions of -the ns-3 programs by simply typing, - -@verbatim - ./waf check -@end verbatim - -You will see many Waf status messages displayed as the system compiles. The -most important is the last one, - -@verbatim - Compilation finished successfully -@end verbatim - -and you will see a number of software unit tests subsequently execute. - -@section Running a Script -@cindex Waf!run -We typically run scripts under the control of Waf. This allows the build -system to ensure that the shared library paths are set correctly and that -the libraries are available at run time. To run a program, simply use the -@code{run} option in Waf. Let's run the ns-3 equivalent of the hello -world program by typing the following: - -@verbatim - ./waf --run hello-simulator -@end verbatim - -Waf first checks to make sure that the program is built correctly and -executes a build if required. Waf then then executes the program, which -produces the following output. - -@verbatim - Hello Simulator -@end verbatim - -If you want to run programs under another tool such as gdb or valgrind, -see this @uref{http://www.nsnam.org/wiki/index.php/User_FAQ#How_to_run_NS-3_programs_under_another_tool,,wiki entry}. - -@emph{Congratulations. You are now an ns-3 user.} - -@c ======================================================================== -@c Some Prerequisites -@c ======================================================================== - -@node Some-Prerequisites -@chapter Some Prerequisites - -The first thing we need to do before actually starting to code is to explain -a few core concepts, abstractions and idioms in the system. Much of this may -appear transparently obvious to some, but we recommend taking the time to read -through this chapter just to ensure you are starting on a firm foundation. - -@section Abstractions - -In this section, we'll review some terms that are commonly used in -networking, but have a specific meaning in ns-3. - -@subsection Node -@cindex Node -In Internet jargon, a computing device that connects to a network is called -a @emph{host} or sometimes an @emph{end system}. Because ns-3 is a -@emph{network} simulator, not specifically an @emph{Internet} simulator, we -intentionally do not use the term host since it is closely associated with -the Internet and its protocols. Instead, we use a more generic term also -used by other simulators that originates in Graph Theory --- the @emph{node}. - -@cindex Node!class -In ns-3 the basic computing device abstraction is called the -node. This abstraction is represented in C++ by the class @code{Node}. The -@code{Node} class provides methods for managing the representations of -computing devices in simulations. Developers are expected to specialize the -@code{Node} in the object-oriented programming sense to create new computing -device models. In this tutorial, we will use a specialization of class -@code{Node} called @code{InternetNode}. As you might expect, the -@code{InternetNode} is a class that represents a host in the Internet sense, -and automatically provides core IPv4 networking protocols. - -You should think of a @code{Node} as a computer to which you will add -functionality. One adds things like applications, protocol stacks and -peripheral cards with their associated drivers to enable the computer to do -useful work. We use the same basic model in ns-3. - -@subsection Application -@cindex Application -Typically, computer software is divided into two broad classes. @emph{System -Software} organizes various computer resources such as memory, processor -cycles, disk, network, etc., according to some computing model. System -software usually does not use those resources to complete tasks that directly -benefit a user. A user would typically run an @emph{application} that acquires -and uses the resources controlled by the system software to accomplish some -goal. - -@cindex system call -Often, the line of separation between system and application software is made -at the privilege level change that happens in operating system traps. -In ns-3 there is no real concept of operating system and especially -no concept of privilege levels or system calls. We do, however, have the -idea of an application. Just as software applications run on computers to -perform tasks in the ``real world,'' ns-3 applications run on -ns-3 @code{Node}s to drive simulations in the simulated world. - -@cindex Application!class -In ns-3 the basic abstraction for a user program that generates some -activity to be simulated is the application. This abstraction is represented -in C++ by the class @code{Application}. The @code{Application} class provides -methods for managing the representations of our version of user-level -applications in simulations. Developers are expected to specialize the -@code{Application} in the object-oriented programming sense to create new -applications. In this tutorial, we will use specializations of class -@code{Application} called @code{UdpEchoClient} and @code{UdpEchoServer}. -As you might expect, these applications compose a client/server application set -used to generate and echo simulated network packets - -@subsection Channel -@cindex Channel - -In the real world, one can connect a computer to a network. Often the media -over which data flows in these netowrks are called @emph{channels}. When -you connect your Ethernet cable to the plug in the wall, you are connecting -your computer to an Ethernet communication channel. In the simulated world -of ns-3 one connects a @code{Node} to an object representing a -communication channel. Here the basic communication subnetwork abstraction -is called the channel and is represented in C++ by the class @code{Channel}. - -The @code{Channel} class provides methods for managing communication -subnetwork objects and connecting nodes to them. They may also be specialized -by developers in the object oriented programming sense. A @code{Channel} -specialization may model something as simple as a wire. The specialized -@code{Channel} can also model things as complicated as a large Ethernet -switch, or three-dimensional space in the case of wireless networks. - -We will use specialized versions of the @code{Channel} called -@code{CsmaChannel} and @code{PointToPointChannel} in this tutorial. The -@code{CsmaChannel}, for example, models a version of a communication subnetwork -that implements a @emph{carrier sense multiple access} communication medium. -This gives us Ethernet-like functionality. - -@subsection Net Device -@cindex NetDevice -@cindex Ethernet - -It used to be the case that if you wanted to connect a computers to a network, -you had to buy a specific kind of network cable and a hardware device called -(in PC terminology) a @emph{peripheral card} that needed to be installed in -your computer. These cards were called Network Interface Cards, or -@emph{NIC}s. Today most computers come with the network controller hardware -built in and users don't see these building blocks. - -A NIC will not work without a software driver to control the hardware. In -Unix (or Linux), a piece of peripheral hardware is classified as a -@emph{device}. Devices are controlled using @emph{device drivers}, and network -devices (NICs) are controlled using @emph{network device drivers} -collectively known as @emph{net devices}. In Unix and Linux you refer -to these net devices by names such as @emph{eth0}. - -In ns-3 the @emph{net device} abstraction covers both the software -driver and the simulated hardware. A net device is ``attached'' to a -@code{Node} in order to enable the @code{Node} to communicate with other -@code{Node}s in the simulation via @code{Channel}s. Just as in a real -computer, a @code{Node} may be connected to more than one @code{Channel} via -multiple @code{NetDevice}s. - -The net device abstraction is represented in C++ by the class @code{NetDevice}. -The @code{NetDevice} class provides methods for managing connections to -@code{Node} and @code{Channel} objects; and may be specialized by developers -in the object-oriented programming sense. We will use the specialized version -of the @code{NetDevice} called the @code{CsmaNetDevice} in this tutorial. -Just as an Ethernet NIC is designed to work with an Ethernet network, the -@code{CsmaNetDevice} is designed to work with a @code{CsmaChannel}. - -@subsection Topology Helpers -In a real network, you will find host computers with added (or built-in) -NICs. In ns-3 we would say that you will find @code{Nodes} with -attached @code{NetDevices}. In a large simulated network you will need to -arrange many connections between @code{Node}s, @code{NetDevice}s and -@code{Channel}s. - -Since connecting a @code{NetDevice} to a @code{Node}, and a @code{NetDevice} -to a @code{Channel} is such a common task in ns-3 we provide what we -call @emph{topology helpers} to make this as easy as possible. Topology -helpers perform much of the dirty work of creating and connecting net devices. -For example, it may take several distinct method calls to create a NetDevice, -add a MAC address, connect the net device to a @code{Node} and configure -the protocol stack, and then connect the @code{NetDevice} to a @code{Channel}. -We use topology helper functions to compose those distinct operations into -an easy to use model. - -Topology helper functions use the abstractions (described above) of Network -Interface Cards and Cables. When you think of adding a new kind of network, -you may think of going out to the local computer retailer and buying a kit. -This kit might include a nework cable and some number of peripheral cards and -thier associated software drivers. You can think of topology helpers in -roughly the same way. Instead of buying a kit for a given type of network, -you will use a topology helper class for a given type of network, to accomplish -the equivalent of installing the network ``kit.'' - -@section Important Idioms -Now that we have identified that there are C++ classes in the system called -@code{Node} and @code{InternetNode}, we need to understand how to bring -objects of these classes into existance, and manage their lifetimes. Let's -examine this in some detail here. - -@cindex InternetNode -@cindex CreateObject -@cindex Ptr -In ns-3, if we want to create an @code{InternetNode} in a -script, we will -typically do something like the following example: - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -@cindex smart pointer -To some, it may seem intuitively obvious that we're creating an -@code{InternetNode} object and assigning responsibility for managing the -object to a smart pointer named @code{p}. For the rest of us, there may be -a lot in that line that is unfamiliar, so let's look at what this line means -in some detail. - -@subsection Templates 101 -@cindex template -If you are familiar with C++ templates, you may skip this section as it is -just a cursory introduction to function and class templates. - -Referring back to the example line of code, reproduced below for your -convenience, the angle brackets you see in the code indicate that we are -using C++ @emph{templates}. - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -The purpose of templates is to allow a programmer to write one version of code -that is applicable over multiple types. Some people consider templates to be -an enhancement of the C preprocessor macro functionality. At some level -this comparison reveal some similarities, but C++ templates are really -quite different. - -@cindex template!declaration -@cindex template!definition -@cindex template!use -In C++, just as with most language constructs, templates are @emph{declared}, -@emph{defined} and @emph{used}. A declaration of a template might look -something like, - -@verbatim - template T Add (T first, T second); -@end verbatim - -@cindex template!typename -This line uses the keyword @code{template} followed by a declaration of a -type name (in this case @code{T}) in angle brackets. The angle brackets -should indicate to you that a template is being declared, defined or used. -The type name @code{T} can be thought of as a string that will be substitited -during the use phase of the template. For example, the @code{T} may be -replaced by the word @code{int}. It is this substitution that leads people -to compare templates with macros. - -Without going into too much more detail, this snippet declares that a piece -of code exists that will be able to call a function @code{Add} that will -add arbitrary types together. The @code{T} will be eventually replaced by -a C++ data type name. For example, - -@verbatim - T Add (T first, T second); -@end verbatim - -might eventually become - -@verbatim - int Add (int first, int second); -@end verbatim - -If the template has been declared, we need to @emph{define} what that piece of -code will actually do. That might look something like, - -@verbatim - template - T Add (T first, T second) - { - return first + second; - } -@end verbatim - -All we've done here is to provide an implementation of the template that -adds the two variables together and returns the result. Note that this -implementation works for any type that provides an @code{operator+}. - -The puzzle all comes together when you understand that @emph{using} a template -causes the compiler to automatically instantiate code for a specific function -according to the given template parameters. You might use the above template -like, - -@verbatim - int x, y, z; - z = Add (x, y); -@end verbatim - -@cindex template!instantiate -When the compiler sees @code{Add} it understands that it needs to make -sure that code is instantiated (created) to perform the @code{Add} using the -specified type @code{}. To a first approximation, the compiler will -replace the typename @code{T} with the specified type @code{int} and -automagically generate code equivalent to, - -@verbatim - int Add (int first, int second) - { - return first + second; - } -@end verbatim - -A user of the template definition could just as easily have provided a use -that assigned the type float. This would simply be done like, - -@verbatim - float x, y, z; - z = Add (x, y); -@end verbatim - -In this case, the compiler would automatically generate code that looked like, - -@verbatim - float Add (float first, float second) - { - return first + second; - } -@end verbatim - -@cindex template!function -This particular kind of template programming uses what are called -@emph{function templates}. They are called function templates since you -are @emph{templating} function declarations and definitions. - -@cindex template!class -Templates can also be used in conjunction with classes, in which case you are -said to be using, not too surprisingly, @emph{class templates}. The syntax and -use is similar. To declare a class template you might use something like, - -@verbatim - template - class MyStack - { - void Push (T data); - T Pop (void); - }; -@end verbatim - -The methods can be defined separately in a method similar to function template -definitions, - -@verbatim - template void MyStack::Push (T data) - { - ... - }; -@end verbatim - -You can then use the new templated class in the following way, - -@verbatim - int x, y; - - MyStack stack; - stack.Push (x); - y = stack.Pop (); -@end verbatim - -Similarly to the function template case, the compiler knows that it has to -automatically generate code to fill out the class and method declarations -and definitions using the appropriate type specified by @code{}. - -@node Smart Pointers 101 -@subsection Smart Pointers 101 -If you are familiar with C++ smart pointers, you may skip this section as it -is just a cursory introduction to smart pointers and intrusive reference -counting. - -@cindex smart pointer -Referring back to the example line of code, partially reproduced below for -your convenience below, the left hand side is the declaration and -initialization of a class template that implements a @emph{smart pointer}. - -@verbatim - Ptr p = ... -@end verbatim - -To a first approximation, you can think of @code{Ptr} as the a new kind -of declaration of a pointer to a @code{Node} object. The difference is that -a smart pointer is a user-defined data type (instantiated via a templated -class) that @emph{simulates} a classical pointer but provides additional -features. As an aside, you typically pronounce @code{Ptr} as -``pooter node'' where pooter rhymes with footer. - -@cindex memory management -One of the most important ``additional feature'' provided by smart pointers is -automatic memory management. Since you now understand class templates, you -will understand how the template allows us to write the pointer code once, but -allows us to point to many different kinds of objects. Later in the tutorial -you will see variations such as @code{Ptr} and @code{Ptr}, -which are smart pointers to an IP version 4 object and a channel object, -respectively. - -The use of built-in pointers in C and C++ is a major source of bugs. Constant -allocation of, passing of responsibility for, and deallocation of underlying -data makes it very likely that errors will occur. In one of these errors, -the usual problem is that the responsibility for deallocating a memory block -is misplaced. This may result in a memory leak or a duplicate deallocation. -Smart pointers try to prevent this kind of problem by working with the -@emph{scope} and @emph{extent} rules of the language to make memory -deallocation automatic. - -The scope of a variable defines where in a program a given variable may be -referred to. The extent of a variable defines when in the program's execution -the variable has a valid value. Consider a simple subroutine that contains a -smart pointer. - -@verbatim - void SimpleSubroutine (void) - { - Ptr p; - } -@end verbatim - -@cindex scope -The variable named @code{p} has a scope limited to the subroutine itself. The -variable is said to @emph{come into scope} as the subroutine is entered during -execution. At this time, the constructor of the underlying class is executed -and a valid variable is available for use. When the subroutine is done -executing, the variable is said to @emph{go out of scope}. This causes the -destructor of the underlying class to be executed and the variable no longer -has a valid value. This is not a problem since it is no longer valid to refer -to the parameter. Smart pointers take advantage of these defined actions at -points where variables must be valid and become discardable to determine when -underlying data can be freed. - -@cindex reference counting!intrusive -The ns-3 smart pointer mechanism uses a mechanism called intrusive -reference counting to determine when a memory block should be automatically -deallocated. The term ``intrusive'' means that a reference count (a count of -variables required to have valid data) is stored in the object being managed -instead of in a proxy object. This means that each piece of memory managed by -a ns-3 smart pointer includes a reference count. When a smart -pointer to a reference counted object is created, this reference count is -incremented. This indicates that a new variable requires a valid data object -be present. When a smart pointer to a reference counted object is destroyed -(for example, when going out of scope) the reference count of the managed -object is decremented. When the reference count goes to zero it means that -all smart pointers to the underlying object have gone out of scope and the -object is no longer needed by any past ``users'' of the object. This in turn -means that the object can be safely deallocated, and this is done -automatically for you as the ``last'' smart pointer goes out of scope. - -Consider how this might work as you pass a smart pointer to an object down -a protocol stack. At each level of the stack, you pass the smart pointer -by value. This causes a copy of the smart pointer to be made, which -increments the reference count of the underlying object. When the -@emph{calling} method is done executing, the calling smart pointer goes out of -scope and the reference count is decremented. This leaves the single smart -pointer in the @emph{called} method with a reference to the underlying object. -When the smart pointer in the called method goes out of scope, the destructor -for the smart pointer is called. The destructor checks the reference count -of the underlying object and sees that it becomes zero. This indicates that -the object can be deallocated, and the destructor does so. This results in -the lifetime management of the underlying object being automatically managed, -a boon if you have experience with ``manual'' memory management and finding -memory leaks. - -Now, we want to make this feature available as widely as possible to objects -in the ns-3 system. The basic operations of the smart pointer class -are the same across any intrusively reference counted object. C++ provides a -mechanism to achieve this kind of generic behavior --- the template. Let's -examine the declaration of the smart pointer in more detail. First consider -the way you might declare and use a built-in pointer. For the sake of -simplicity, just assume that a C++ object of the class @code{MyClass} exists. -Further assume that @code{MyClass} provides one method called @code{method}. -Using built-in pointers, you could do something like the following: - -@verbatim - MyClass *p = ... - p->method (); -@end verbatim - -@cindex smart pointer -One of the key design points of smart pointers is that they should simulate -built-in pointers. In C++ this is done by overloading @code{operator->}, -@code{operator=} and @code{operator*}. To implement a smart pointer we need -to provide a generic class that implements these operators. This generic -class should allow operations that appear as if it were a built-in pointer -to the reference counted object. Typically this is accomplished via a -relatively simple C++ class template. If you are interested in the details -of how this may be accomplished, see Alexandrescu for a good treatment, - -@cindex template -Taking the template as given, in order to declare a smart pointer you will -need to create a smart pointer object and provide the template parameter -needed to instantiate the required code. This parameter will be the name -of the reference counted class to which you want to point. The smart -pointer class overrides @code{operator=} which allows initialization of the -smart pointer just as if it were a built-in pointer. The end result is that -you use smart pointers just as if they were built-in pointers: - -@verbatim - SmartPointer p = ... - p->method (); -@end verbatim - -@node Object Creation -@subsection Object Creation -@cindex CreateObject -On the right hand side of the line of code we're examining (reproduced below -for convenience) is the creation of an @code{InternetNode} object. - -@verbatim - ... = CreateObject (); -@end verbatim - -@cindex template!function -This turns out to be an instance of use of a C++ @emph{function template}. The -definition of the @code{CreateObject()} template calls the new -operator to create an object of the type T. It then creates a new smart -pointer of the appropriate type (i.e., @code{Ptr}). This new smart -pointer is assigned initial responsibility for the new object which has its -reference count set to one. - -Since the underlying creation mechanism is via the @code{new} operator, and -you can pass parameters to the constructor for an object, we provide several -templates that you can use for passing parameters to the object constructors. -If the constructor for the object requires a parameter, you simply pass that -parameter to the @code{Create} function like this, - -@verbatim - int parm = 1; - ... = CreateObject (parm); -@end verbatim - -We provide Create templates with up to seven parameters, so you could -conceivably use the @code{Create} template in situations such as, - -@verbatim - int parm = 1; - ... = CreateObject (p1, p2, p3, p4, p5, p6, p7); -@end verbatim - -@subsection Type Safety -Lets take one final look at the now infamous example line of code that we -have been examining for some time (again reproduced below). - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -@cindex smart pointer -@cindex Node -@cindex Create -You may have noticed that the smart pointer on the left hand side of the -assignment is associated with the type @code{Node} and the @code{Create} -template on the right hand side creates an @code{InternetNode} object and -returns a @code{Ptr} smart pointer. For this assignment of a -@code{Ptr} to a @code{Ptr} to work, there must be some -kind of type conversion going on. - -@cindex implicit conversion -Many programmers use @code{implicit conversions} without even realizing it -since they are sometimes so intuitive. For example, in the following code, - -@verbatim - int i = 1; - double d = 2.; - if (n == d) ... -@end verbatim - -@cindex standard conversion -the integer (1) is implicitly converted to a double (1.) before the comparison -takes place. This conversion is performed using what is known as a C++ -@emph{standard conversion}. There are a number of standard conversions defined -by the C++ standard. Among them are, - -@itemize @bullet -@item Integral Promotions -@item Integral Conversions -@item Floating Conversions -@item Pointer Conversions -@item Reference Conversions -@end itemize - -@cindex assignment operator -@cindex Ptr -For the case of interest here, we need to know what happens in the -assignment operator (@code{operator=}) of our smart pointer @code{Ptr}. -This operator takes a reference to a @code{Ptr} and not a reference to -a @code{Ptr}. The one situation where this works automatically -in C++ is if the ``destination'' reference is to a visible, unambiguous base -class of the ``source'' reference. In this case, the underlying pointer is -@emph{cast} from one type to the other automatically. - -To summarize: The magic happens in the assignment operator. Class -@code{InternetNode} inherits from class @code{Node}. The reference to the -@code{InternetNode} object in question is, in essence, a pointer to an -@code{InternetNode} object. The @code{InternetNode} class inherits from the -@code{Node} base class in a way that makes @code{Node} visible and unambiguous. -Therefore, there exists a standard conversion from an @code{InternetNode *} -to a @code{Node *} and by extension from an @code{InternetNode &} to a -@code{Node &}. This conversion is applied automatically (and invisibly) -during paramater passing in the assignment operator we are examining. - -@cindex base class -This is a rather involved way of saying there's an invisible pointer cast -to a base class happening in the assignment. That means that - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -or, - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -will work just fine. Of course, if you try something @emph{bad} (TM), like: - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -the compiler will quite appropriately complain that there is no conversion -between these completely unrelated objects (CsmaChannel and Node). - -@subsection Summary -Going back to our infamous first line of ns-3 code, we said that if -we want to create an InternetNode in a script, we will typically do something -like: - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -@cindex Create -@cindex InternetNode -@cindex smart pointer -Now we know that this is really a simple statement. We create an -@code{InternetNode} object on the heap (indirecly using operator @code{new} -and passing no parameters to its constructor) and assign responsibility for -managing the new object's lifetime to a smart pointer. This smart pointer is -a pointer to a @code{Node} object, so there was a hidden cast from -@code{InternetNode} to a @code{Node} done via a standard C++ conversion. - -This may have been quite a hurdle to get past that first line of code, but -we have covered quite a few of the important idioms that you'll encounter in -this tutorial. - -@c ======================================================================== -@c A First ns-3 script -@c ======================================================================== - -@node A-First-ns-3-Script -@chapter A First ns-3 script -@cindex design pattern -@cindex idiom -Lets build a simple network using the ns-3 design patterns, idioms, -classes and helpers we have just looked at. If you downloaded the system as -was suggested above, you will have a release of ns-3 in a directory -called @code{repos} under your home directory. Change into that directory, -where you should see a directory structure something like the following. - -@verbatim - AUTHORS RELEASE_NOTES examples/ src/ waf* - LICENSE VERSION ns3/ tutorial/ waf.bat* - README doc/ samples/ utils/ wscript -@end verbatim - -@cindex hello-simulator.cc -Change into the tutorial directory. You should see a file named -@code{hello-simulator.cc} located there. Copy this file into one named -@code{simple.cc}. If you open this new file in your favorite editor you will -see some copyright information and the following C++ code: - -@verbatim - #include "ns3/log.h" - - NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Hello Simulator"); - } -@end verbatim - -This is the ns-3 version of the ubiquitous hello-world program. It -uses the ns-3 Log module to print ``Hello Simulator'' into the - standard error output stream. - -@cindex logging -Log components are named objects that provide for controlling the verbosity of -debugging output in the system. We'll have a lot more to say about logging -later on, but for now you can just consider the macro @code{NS_LOG_INFO} to be -a kind of fancy printf to the standard error. - -@section A Simple Network -@cindex InternetNode -Let's create a simple network of @code{InternetNode} elements. In order to -actually create an @code{InternetNode}, you will have to include some header -files. Put the following code after the include statement in @code{simple.cc}. - -@verbatim - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" -@end verbatim - -@cindex include files -The ns-3 build system places the core include files it needs into a -directory called @code{ns-3} and so whenever you need to include one of the -core files you need to explicitly code this. The file @code{ptr.h} defines -the generic smart pointer that we use. The file @code{internet-stack.h} -defines the class InternetNode which, as described above, represents an IP -version 4-based computing element in the simulator. - -So let's create a few new @code{InternetNode}s by adding the following lines -of code after the call to @code{NS_LOG_INFO} in the simple.cc file right -after the call to @code{NS_LOG_INFO}. - -@verbatim - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); -@end verbatim - -As we now understand, this will create four @code{InternetNode} objects on -the heap and create four @code{Ptr} smart pointer objects on the stack -to manage them. You should remember that by using the smart pointers you are -freed from the responsibility to delete the objects you assign to them. - -@cindex Channel -@cindex CsmaChannel -The next step is to create a channel over which these nodes can communicate. -Let's use the CsmaChannel and create a local area network that will allow us -to hook up nodes similarly to an Ethernet. - -As usual, we'll need to include the file that provides the appropriate class -declarations: - -@verbatim - #include "ns3/csma-channel.h" -@end verbatim - -Next, Add the following line of code (typically done after node creation) to -create a channel with a five megabit per second data rate and a two -millisecond speed-of-light delay between all nodes. The idiom for creating -the channel is similar to that of the node, but the actual @code{Create} -function is hidden from us in the topology code. Observe that we are -using a Csma topology helper function to free us from the details regarding -how the Carrier Sense Multiple Access Channel is actually brought into -existence and initialized. - -@verbatim - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); -@end verbatim - -@cindex idiom!unnamed parameter -You may be unfamiliar with the @emph{unnamed parameter} idiom used here. -When added to a list of parameters, the code @code{DataRate (5000000)} -constructs a DataRate object on the stack using the appropriate constructor. -The resulting object has no name, and therefore cannot be referenced -elsewhere, but is passed to the callee method where it has a valid name and -can be used. This idiom is essentially a shorthand version of the following: - -@verbatim - DataRate rate (5000000); - Time latency (MilliSeconds (2)); - Ptr lan = CsmaTopology::CreateCsmaChannel (rate, latency); -@end verbatim - -@cindex constructor -@cindex constructor!Time -We should pause for a moment and discuss the constructor to the @code{Time} -data type. There are a number of different constructors for these objects, and -so there are a number of ways that this initialization could have been done. -There is a constructor that takes a string argument, consisting of expressions -using the units @code{s, ms, us, ns, ps} or @code{fs}, so this could have been -written, - -@verbatim - Time latency ("2ms"); -@end verbatim - -There are also helper functions available that create time units (one of these -was used in the example): - -@itemize @bullet -@item @code{Seconds (double)} -@item @code{MilliSeconds (uint64_t)} -@item @code{MicroSeconds (uint64_t)} -@item @code{NanoSeconds (uint64_t)} -@item @code{PicoSeconds (uint64_t)} -@item @code{FemtoSeconds (uint64_t)} -@end itemize - -C++ will attempt to promote parameters appropriately, but you will typically -see constructions that respect the type corrrectness of the constructor, as -in @code{Seconds (1.)} and @code{MilliSeconds (2)}. Notice that the code -@code{Seconds (1)} will work just as well as @code{Seconds (1.)} since the -integer 1 will be automatically promoted to a double 1. in the former code. -The converse will not work --- i.e., you cannot write code that says -@code{MilliSeconds (2.)} since a @emph{type demotion} would be required that -could lose information and the compiler will not do such things ``behind your -back.'' Don't be thrown off by this kind of automatic conversion. - -@cindex MAC!address -Okay, now we have code to create four nodes and a local area network. The -next step is to wire the network together. We do this by adding net devices -to the node. When we add the net device, we also specify the network to which -the net device is connected and provide a MAC address appropriate to the -device and network types. Since we're creating an IP version 4 network using -a Csma channel, you may expect that we'll be using topology helpers -appropriate to those types --- the CsmaIpv4Topology helper. As you may expect, -we'll need to include some files to get the appropriate definitions: - -@verbatim - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" -@end verbatim - -Now, all that is left is to do the ``wiring'': - -@verbatim - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); -@end verbatim - -[Note the additional unnamed parameter idiom usage here.] - -This code calls the topology helper relating to Csma channels and IP version -four nodes. It asks to install a Csma net device ``into'' node zero -(@code{n0}) connecting the device to the channel named (@code{lan}). It also -assigns a MAC address to the net device. You can add similar lines of code -connecting the other nodes to the lan (remembering to assign new MAC -addresses). - -@verbatim - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); -@end verbatim - -@cindex IP!address -@cindex IP!network mask -@cindex multihome -Finally, we need to add IP addresses to our nodes. The pointers to the -nodes are stored in n0, n1, n2 and n3. We added net devices to each of -the nodes and remembered the net device index numbers as nd0, nd1, nd2 and -nd3. You can add multiple net devices to each node resulting in a situation -similar to a multi-homed host. Each time you add a net device, you will get -a new index. Since the IP address for a multi-homed host is associated with -a net device, we need to provide that index (which we have saved) to the -topology helper. We provide an IP version four address via the ns-3 -class @code{Ipv4Address} which takes a dotted decimal string as a constructor -parameter. We also provide a network mask using the ns-3 class -@code{Ipv4Mask} which also takes a dotted decimal string. The code to -perform the IP address assignment, then, looks like the following: - -@verbatim - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); -@end verbatim - -We have now constructed a simulated network. Your code should now look -something like the following, - -@verbatim - #include "ns3/log.h" - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" - #include "ns3/csma-channel.h" - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" - - NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Hello Simulator"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); - - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); - - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); - - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); - } -@end verbatim - -This script won't actually do anything yet. The next trick will be to -convince our nodes to try and send some data over the network. - -@section Using Applications -@cindex Create -As mentioned above, we use @code{Application}s in ns-3 to generate -the data used to drive simulations. An @code{Application} is added to a -ns-3 node conceptually just as if you would add an application to a -computer. When an application is created (using the @code{Create} template) -we tell the application which @code{Node} it belongs to (and therefore on -which node it is running) by passing a smart pointer to that @code{Node} in -the constructor arguments. - -@subsection A UDP Echo Client Application -To use an application, we first have to load the header file in which it is -defined. For the UDP echo client, this would mean adding the line, - -@verbatim -#include "ns3/udp-echo-client.h" -@end verbatim - -In order to create the UDP echo client application we will need to add the -following code: - -@verbatim - uint32_t packetSize = 1024; - uint16_t port = 7; - uint32_t maxPacketCount = 1; - Time interPacketInterval = Seconds (1.); - - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); -@end verbatim - -@cindex packet -The first four lines have broken out the configuration parameters for the -application as named parameters for clarity. We are telling the application -to generate 1024 byte packets (@code{packetSize = 1024}); and to send these -packets to port 7 (@code{port = 7;}). The application is told to send at most -one packet (@code{maxPacketCount = 1;}); and to delay for one second between -packet sends (@code{interpacketInterval = Seconds(1.)}) which is not used since -only one packet is sent. We will defer addressing the type @code{Time} until -we discuss the simulator engine. For now just understand the semantics are -to wait for one second. - -The code to actually create the @code{UdpEchoClient} application uses the -same creation idiom as we have used previously. Notice that we have a case -where the @code{Create} template is used to pass parameters to the constructor -of the underlying object. - -@cindex implicit conversion sequence -Notice that a string is passed as the second parameter. The formal parameter -to the constructor of the @code{UdpEchoClient} object is actually an -@code{Ipv4Address}. We get away with this since C++ allows what are called -@emph{implicit conversion sequences} to occur between the argument in the -function call and the corresponding parameter in the function declaration. -Basically, C++ will try to figure out a way to convert parameters for you -transparently. - -In this case the conversion sequence is based on the constructor for the -Ipv4Address that takes a @code{char const *} as a parameter. C++ notices -that @code{"10.1.1.2"} refers to a @code{char const *} and knows that it -needs to get from there to an @code{Ipv4Address}. The compiler notices that -there is an @code{Ipv4Address} constructor that takes a @code{char const *} -and so it uses that constructor transparently to arrange for the conversion. - -You therefore have several options for passing this value. You can use an -explicit named variable as in the following: - -@verbatim - Ipv4Address addr ("10.1.1.2"); - ... - - Ptr client = CreateObject (n0, addr, port, - maxPacketCount, interPacketInterval, packetSize); -@end verbatim - -@cindex idiom|unnamed parameter -You can use the unnamed parameter idiom that we have previously seen: - -@verbatim - Ptr client = CreateObject (n0, - Ipv4Address ("10.1.1.2"), port, maxPacketCount, interPacketInterval, - packetSize); -@end verbatim - -Or you can rely on implicit conversion sequences as we just saw: - -@verbatim - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); -@end verbatim - -Which approach to take is a matter of style, really, and you will probably -see all three approaches taken in the ns-3 code. You should be -comfortable seeing and using all three methods. - -@subsection A UDP Echo Server Application -As usual, to use the UDP echo server we need to add a line to define the -application: - -@verbatim -#include "ns3/udp-echo-server.h" -@end verbatim - -In order to create the UDP echo server application we will need to add the -following code: - -@verbatim - Ptr server = CreateObject (n1, port); -@end verbatim - -We only need to tell the application which node to reside on and which port -to listen on for UDP packets. The code to actually create the -@code{UdpEchoServer} application uses the now quite familiar ns-3 object -creation idiom. - -@subsection A UDP Echo Client-Server Simulation -Now we're getting somewhere. Your code should look something like the -following (let's change the log component name and program banner from -``Hello Simulator''to something more descriptive while we're at it). - -@verbatim - #include "ns3/log.h" - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" - #include "ns3/csma-channel.h" - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" - #include "ns3/udp-echo-client.h" - #include "ns3/udp-echo-server.h" - - NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("UDP Echo Simulation"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); - - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); - - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); - - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); - - uint32_t packetSize = 1024; - uint16_t port = 7; - uint32_t maxPacketCount = 1; - Time interPacketInterval = Seconds (1.); - - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); - - Ptr server = CreateObject (n1, port); - - } -@end verbatim - -@section Using the Simulation Engine -@cindex model -@cindex simulation executive -You could say that the heart of the ns-3 system is the -@emph{simulation engine} (sometimes called the simulation executive in other -systems). - -In a computer simulation, a computer @emph{model} of a real world @emph{system} -is constructed. This is typically done to minimize cost since you do not have -to actually buy, install and maintain physical hardware. In the case of -ns-3, a model is a representation of a networking component that is -designed to imitate some number of important behaviors or characteristics of -an actual component in a real network. A system is a collection of models -arranged for the purpose of analyzing some behavior. - -@section Models -@cindex CsmaNetDevice -@cindex CsmaChannel -@cindex InternetNode -@cindex NIC -@cindex CSMA -We have already encountered several ns-3 models without specifically -calling them so. The @code{InternetNode}, @code{CsmaNetDevice} and -@code{CsmaChannel} objects are models of an Internet computing node, a CSMA -network interface card (NIC), and a network cable able to move data to and -from other CSMA NICs. - -@cindex model -@cindex CSMA/CD -It is important to note that the @code{Csma} net devices and the @code{Csma} -channel do not correspond to any real world hardware that you can actually go -out and buy. These models implement an approximation, or subset, of the -behaviors that a real CSMA/CD network would have. In this case, the -@code{CsmaNetDevice} does not simulate collision detection (CD). It does -implement carrier sense and performs collision @emph{avoidance} using global -spatial knowledge available in the channel. This would be impossible in any -channel residing in our universe. - -@cindex Ethernet -No model will fully implement @emph{all} of the behaviors of a piece of -hardware. It is important to understand what is being modeled by the -ns-3 components you are using and what is not. For example, the Csma -components we use in this tutorial model a highly abstract multiple access -network that is topologically equivalent to an Ethernet. It is not necessarily -true that results found in a simulation using the Csma models will apply to -a real-world Ethernet network. You must understand what behaviors are -simulated in each of the models before trusting that any results can be -associated with real-world systems. - -@section Time, Events and Callbacks -@cindex time -@cindex event -In a @emph{discrete event simulator} time is not something that @emph{flows}, -nor is it something to be measured --- it is the driving force behind the -progress of the simulation. Time is progressed forward by the simulation -engine and anything that happens in the simulation is ultimately caused by -an @emph{event}. An event is some action in the system that is -@emph{scheduled} to happen at a certain time by the simulation engine. Time -does not flow continuously but steps discretely (in possibly large jumps) -from one scheduled event to another. - -@cindex packet -For example, to start the flow of a packet through the system, one would have -to schedule an event with the simulation engine @emph{before} the simulation -was started. This is important since the simulation engine only jumps time -forward if there is a next event to process. The simulation stops if there -are no more events, which is equivalent to a state where there is ``nothing -more to do.'' Before the simulation starts, one schedules driving events in -terms of absolute time. For example, one could schedule an event to start -the flow of a first packet at, say, ten simulated seconds. In this case, the -simulation would start its clock at zero seconds and look for the first event -in its @emph{event queue}. It would immediately jump time forward by ten -seconds and @emph{fire} the scheduled event --- that is, make the event happen. - -@cindex functor -@cindex function object -@cindex callback -@cindex Callback -In ns-3 an event is basically a pre-packaged function call called a -@emph{functor}. Functors are also known as @emph{function objects}, which is -a more descriptive term --- an object (in the object-oriented programming -sense) that can be called as if it was a function. Typically one uses a -functor to implement @emph{deferred execution} of a function or method. The -most commonly encoutered form of deferred execution is in a @emph{callback} -from an I/O system. In this case, the goal would be to start an I/O -operation and return immediately, without having to wait for the operation -to complete. One asks the I/O subsytem to notify you when an operation is -complete by calling some function you provide. This provided function is -known as a callback function. [Imagine calling someone on the telephone and -asking them to do something for you. You also ask them to @emph{call you back} -when they are done.] Events in the ns-3 system work conceptually -the same way, except that instead of an I/O completion driving the process, -the arrival of some simulated time drives the process. The ns-3 -deferred exectution mechanism is via a class called @code{Callback}. - -@cindex Time -@cindex Callback -The internal details of the classes representing @code{Time} and -@code{Callback} abstractions will be introduced as required. We won't see -events directly for some time, but you should know that they are happening -``under the sheets'' of the simulations you will be writing. - -@section Driving the Simulation -@cindex Application -As mentioned previously, time is the driving force behind the progress of -a ns-3 simulation. Events are scheduled to happen at certain times -by calling methods of the simulation engine, either directly or indirectly -through, for example, an @code{Application}. - -In order to get the simulation engine set up and running in our code, we must -first include the language definitions required to describe time- and -simulator-specific classes: - -@verbatim - #include "ns3/simulator.h" - #include "ns3/nstime.h" -@end verbatim - -@cindex Application -As we have seen, we need to ``seed'' the simulation with at least one event. -In the case of an @code{Application}, a method to do this is provided. This -method must be implemented by each specialization of the class and we must -call this method in our script before the simulation starts. We can also -provide an event (indirectly) to stop the output of the application at a -certain time. This is done by adding the following lines to our script: - -@verbatim - server->Start(Seconds(1.)); - client->Start(Seconds(2.)); - - server->Stop (Seconds(10.)); - client->Stop (Seconds(10.)); -@end verbatim - -@cindex Application -@cindex time -@cindex Time -@cindex socket -@cindex event -In the case of the UdpEchoServer, the call to @code{server->Start ()} gives -the @code{Application} the chance to schedule an event that will perform the -usual @emph{sockets} server sequence of socket creation, binding and -recvfrom (see Donahoo's UDPEchoServer.c). - -In the case of the UdpEchoClient, the call to @code{client->Start ()} gives -the @code{Application} the chance to schedule an event that will perform the -usual @emph{sockets} client sequence of socket creation, sendto and recvfrom -(see Donahoo's UDPEchoClient.c). - -@cindex event -Note that the start event for the server is scheduled to happen before the -start event of the client, just as you would start a server application before -you would attempt to start a client application in the real world. - -@cindex socket!sendto -The ns-3 equivalent of the call to @code{sendo} in the client will -schedule (immediately) the transmission of a UDP packet over the just created -socket. This will cause the packet to percolate down the protocol stack and -eventually into the channel. The channel will schedule a reception event in -the net device on the destination node. This event will eventually percolate -up into the server application. The server application will create a reply -packet and send it back down its stack and eventually back to the channel. -The channel will schedule a reception event back in the client and this will -cause the reply to be sent back up the protocol stack to the client -application. - -The calls to @code{Stop ()} for both applications cause the sockets to be -torn down and therefore the sending and receiving of packets will be stopped -irrespective of other application settings (such as max packets and interval -in the client). - -Finally, we need to run the simulation and when the simulation run is complete, -clean up any resources allocated during the run. This is done by the calling -the following static methods: - -@verbatim - Simulator::Run (); - Simulator::Destroy (); -@end verbatim - -We now have the makings of a complete ns-3 network simulation. The -source code for the script should look like the following: - -@verbatim - #include "ns3/log.h" - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" - #include "ns3/csma-channel.h" - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" - #include "ns3/udp-echo-client.h" - #include "ns3/udp-echo-server.h" - #include "ns3/simulator.h" - #include "ns3/nstime.h" - - NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("UDP Echo Simulation"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); - - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); - - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); - - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); - - uint32_t packetSize = 1024; - uint16_t port = 7; - uint32_t maxPacketCount = 1; - Time interPacketInterval = Seconds (1.); - - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); - - Ptr server = CreateObject (n1, port); - - server->Start(Seconds(1.)); - client->Start(Seconds(2.)); - - server->Stop (Seconds(10.)); - client->Stop (Seconds(10.)); - - Simulator::Run (); - Simulator::Destroy (); - } -@end verbatim - -@cindex tutorial-csma-echo.cc -Just to make sure you don't get caught up in debugging typographical errors -we have provided this source code for you (along with a copyright header) in -the @code{tutorial} subdirectory of the ns-3 distribution as -@code{tutorial-csma-echo.cc}. We used this opportunity to do some ``clean up'' -of some of our example cases by passing parameters using implicit conversion -sequences and removing some of the named parameters. [These were used for -pedagogic purposes and were not actually necessary.] - -@section Building the Script -@cindex Waf -C++ is a compiled language, so you know it had to happen. We have to build -the script before we run it. As mentioned before, we use the Waf build system -which is Python-based. We have to change gears slightly and switch ourselves -to Python mode in order to proceed. - -In each subdirectory of the ns-3 distribution in which there are -source files, you will find two files: one will be named @code{waf} and one -will be named @code{wscript}. The former, @code{waf}, is a link that allows -one to start the build process from any subdirectory. We can ignore that one. -The file we need to deal with is @code{wscript}. - -@cindex wscript -Open the file @code{ns-3-dev/tutorial/wscript} in your favorite editor -[remember I'm assuming that you have the distribution saved in a -repository under a directory called @code{repos} in you home directory.] - -@cindex Python -You should see the following Python code (after an emacs mode line). - -@verbatim - def build(bld): - obj = bld.create_ns3_program('hello-simulator') - obj.source = 'hello-simulator.cc' -@end verbatim - -These are the only instructions required to build a simulation (I told you -it wasn't going to be too bad). The line with the method -@code{bld.create_ns3_program} tells the build system to create an object -file that is a program (executable) named @code{hello-simulator}. The -following line, with the method @code{obj.source} tells the build system that -the source file for the program is the file @code{hello-simulator.cc'} in the -local directory. The required libraries are linked for you for free. - -All that needed to be done in order to build the new simulation using the new -source file was to copy the two lines describing the @code{hello-simulator} -program and change the names to @code{tutorial-csma-echo}. You can see these -lines in the @code{wscript} file, - -@verbatim - def build(bld): - obj = bld.create_ns3_program('hello-simulator') - obj.source = 'hello-simulator.cc' - - obj = bld.create_ns3_program('tutorial-csma-echo') - obj.source = 'tutorial-csma-echo.cc' - - ... -@end verbatim - -When you built the system above, you actually already built this new -simulation and a number of other examples. Since you have already configured -@code{Waf} and built the @code{tutorial-csma-echo} script, you can run the -simulation in the same way as you ran the @code{hello-simulator} script using -the @code{waf --run} command: - -@verbatim -~/repos/ns-3-dev/tutorial > waf --run tutorial-csma-echo -Entering directory `~/repos/ns-3-dev/build' -Compilation finished successfully -UDP Echo Simulation -~/repos/ns-3-dev/tutorial > -@end verbatim +that covers material you may need to understand if you look at the multicast +examples in the distribution. diff --git a/doc/tutorial/tutorial.texi b/doc/tutorial/tutorial.texi index 64185d03c..f3517b3d6 100644 --- a/doc/tutorial/tutorial.texi +++ b/doc/tutorial/tutorial.texi @@ -7,34 +7,36 @@ @ifinfo Primary documentation for the @command{ns-3} project is available in -three forms: +four forms: @itemize @bullet @item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator @item Tutorial (this document) +@item @uref{http://www.nsnam.org/docs/manual.html,,Reference Manual}: Reference Manual @item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} @end itemize -This document is written in GNU Texinfo and is to be maintained in -revision control on the @command{ns-3} code server. Both PDF and HTML versions -should be available on the server. Changes to -the document should be discussed on the ns-developers@@isi.edu mailing list. +This document is written in GNU Texinfo and is to be maintained in revision +control on the @command{ns-3} code server. Both PDF and HTML versions should +be available on the server. Changes to the document should be discussed on +the ns-developers@@isi.edu mailing list. @end ifinfo @copying This is an @command{ns-3} tutorial. Primary documentation for the @command{ns-3} project is available in -three forms: +four forms: @itemize @bullet @item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator @item Tutorial (this document) +@item @uref{http://www.nsnam.org/docs/manual.html,,Reference Manual}: Reference Manual @item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} @end itemize -This document is written in GNU Texinfo and is to be maintained in -revision control on the @command{ns-3} code server. Both PDF and HTML -versions should be available on the server. Changes to -the document should be discussed on the ns-developers@@isi.edu mailing list. +This document is written in GNU Texinfo and is to be maintained in revision +control on the @command{ns-3} code server. Both PDF and HTML versions should +be available on the server. Changes to the document should be discussed on +the ns-developers@@isi.edu mailing list. This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -66,7 +68,7 @@ along with this program. If not, see @uref{http://www.gnu.org/licenses/}. @contents @ifnottex -@node Top, Overview, Full Table of Contents +@node Top, Introduction, Full Table of Contents @top ns-3 Tutorial (html version) For a pdf version of this tutorial, @@ -76,51 +78,19 @@ see @uref{http://www.nsnam.org/docs/tutorial.pdf}. @end ifnottex @menu -* Tutorial Goals:: -Part 1: Getting Started with ns-3 -* Overview:: -* Browsing:: +* Introduction:: * Resources:: -* Downloading and Compiling:: -* Some-Prerequisites:: -Part 2: Reading ns-3 Programs -* A-First-ns-3-Script:: -Part 3: Reconfiguring Existing ns-3 Scripts -* Logging:: -* ns-3 Attributes:: -* Tracing:: -* Statistics:: -Part 4: Creating New or Revised Topologies -* Helper Functions:: -* Other-network-topologies:: -Part 5: Key ns-3 objects and systems -* ns-3 Packets:: -* ns-3 Callbacks:: -* Sockets APIs:: -* ns-3 routing overview:: -Part 6: Extending ns-3 -* Nonlinear-Thinking:: -* Summary:: -* Object-Model:: -* The-Doxygen-Documentation-System:: -* How-To-Change-Things:: -* How-To-Set-Default-Values:: -* How-To-Write-A-New-Application:: -@ Troubleshooting +* Getting Started:: +* Conceptual Overview:: +* Tweaking ns-3:: +* Building Topologies:: @end menu @include introduction.texi -@include log.texi -@include attributes.texi -@include statistics.texi -@include helpers.texi -@include packets.texi -@include callbacks.texi -@include sockets.texi -@c @include output.texi -@include routing.texi -@c @include other.texi -@include troubleshoot.texi +@include getting-started.texi +@include conceptual-overview.texi +@include tweaking.texi +@include building-topologies.texi @printindex cp diff --git a/doc/tutorial/tweaking.texi b/doc/tutorial/tweaking.texi new file mode 100644 index 000000000..caeac8666 --- /dev/null +++ b/doc/tutorial/tweaking.texi @@ -0,0 +1,1001 @@ + +@c ======================================================================== +@c Begin document body here +@c ======================================================================== + +@c ======================================================================== +@c PART: Tweaking ns-3 +@c ======================================================================== +@c The below chapters are under the major heading "Tweaking ns-3" +@c This is similar to the Latex \part command +@c +@c ======================================================================== +@c Tweaking ns-3 +@c ======================================================================== +@node Tweaking ns-3 +@chapter Tweaking ns-3 + +@menu +* Using the Logging Module:: +* Using Command Line Arguments:: +* Using the Tracing System:: +@end menu + +@c ======================================================================== +@c Using the Logging Module +@c ======================================================================== +@node Using the Logging Module +@section Using the Logging Module + +@cindex logging +We have already taken a brief look at the @command{ns-3} logging module while +going over the @code{first.cc} script. We will now take a closer look and +see what kind of use-cases the logging subsystem was designed to cover. + +@node Logging Overview +@subsection Logging Overview +Many large systems support some kind of message logging facility, and +@command{ns-3} is not an exception. In some cases, only error messages are +logged to the ``operator console'' (which is typically @code{stderr} in Unix- +based systems). In other systems, warning messages may be output as well as +more detailed informational messages. In some cases, logging facilities are +used to output debug messages which can quickly turn the output into a blur. + +@command{Ns-3} takes the view that all of these verbosity levels are useful +and we provide a selectable, multi-level approach to message logging. Logging +can be disabled completely, enabled on a component-by-component basis, or +enabled globally; and it provides selectable verbosity levels. The +@command{ns-3} log module provides a straightforward, relatively easy to use +way to get useful information out of your simulation. + +You should understand that we do provide a general purpose mechanism --- +tracing --- to get data out of your models which should be preferred for +simulation output (see the tutorial section Using the Tracing System for +more details on our tracing system). Logging should be preferred for +debugging information, warnings, error messages, or any time you want to +easily get a quick message out of your scripts or models. + +There are currently seven levels of log messages of increasing verbosity +defined in the system. + +@itemize @bullet +@item NS_LOG_ERROR --- Log error messages; +@item NS_LOG_WARN --- Log warning messages; +@item NS_LOG_DEBUG --- Log relatively rare, ad-hoc debugging messages; +@item NS_LOG_INFO --- Log informational messages about program progress; +@item NS_LOG_FUNCTION --- Log a message describing each function called; +@item NS_LOG_LOGIC -- Log messages describing logical flow within a function; +@item NS_LOG_ALL --- Log everything. +@end itemize + +We also provide an unconditional logging level that is always displayed, +irrespective of logging levels or component selection. + +@itemize @bullet +@item NS_LOG_UNCOND -- Log the associated message unconditionally. +@end itemize + +Each level can be requested singly or cumulatively; and logging can be set +up using a shell environment variable (NS_LOG) or by logging system function +call. As was seen earlier in the tutorial, the logging system has Doxygen +documentation and now would be a good time to peruse the Logging Module +documentation if you have not done so. + +Now that you have read the documentation in great detail, let's use some of +that knowledge to get some interesting information out of the @code{first.cc} +example script you have already built. + +@node Enabling Logging +@subsection Enabling Logging +@cindex NS_LOG +Let's use the NS_LOG environment variable to turn on some more logging, but +to get our bearings, go ahead and run the script just as you did previously, + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + ~/repos/ns-3-dev > +@end verbatim + +It turns out that the ``Sent'' and ``Received'' messages are actually logging +messages from the @code{UdpEchoClientApplication} and +@code{UdpEchoServerApplication}. We can ask the client application, for +example, to print more information by setting its logging level via the +NS_LOG environment variable. + +I am going to assume from here on that are using an sh-like shell that uses +the``VARIABLE=value'' syntax. If you are using a csh-like shell, then you +will have to convert my examples to the ``setenv VARIABLE value'' syntax +required by those shells. + +Right now, the UDP echo client application is responding to the following line +of code in @code{first.cc}, + +@verbatim + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); +@end verbatim + +This line of code enables the @code{LOG_LEVEL_INFO} level of logging. When +we pass a logging level flag, we are actually enabling the given level and +all lower levels. In this case, we have enabled @code{NS_LOG_INFO}, +@code{NS_LOG_DEBUG}, @code{NS_LOG_WARN} and @code{NS_LOG_ERROR}. We can +increase the logging level and get more information without changing the +script and recompiling by setting the NS_LOG environment variable like this: + +@verbatim + ~/repos/ns-3-dev > export NS_LOG=UdpEchoClientApplication=level_all +@end verbatim + +This sets the shell environment variable @code{NS_LOG} to the string, + +@verbatim + UdpEchoClientApplication=level_all +@end verbatim + +The left hand side of the assignment is the name of the logging component we +want to set, and the right hand side is the flag we want to use. In this case, +we are going to turn on all of the debugging levels for the application. If +you run the script with NS_LOG set this way, the @command{ns-3} logging +system will pick up the change and you should see the following output: + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + UdpEchoClientApplication:UdpEchoClient() + UdpEchoClientApplication:StartApplication() + UdpEchoClientApplication:ScheduleTransmit() + UdpEchoClientApplication:Send() + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + UdpEchoClientApplication:HandleRead(0x62c640, 0x62cd70) + Received 1024 bytes from 10.1.1.2 + UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + ~/repos/ns-3-dev > +@end verbatim + +The additional debug information provided by the application is from +the NS_LOG_FUNCTION level. This shows every time a function in the application +is called during script execution. Note that there are no requirements in the +@command{ns-3} system that models must support any particular logging +functionality. The decision regarding how much information is logged +is left to the individual model developer. In the case of the echo +applications, a good deal of log output is available. + +You can now see a log of the function calls that were made to the application. +If you look closely you will notice a single colon between the string +@code{UdpEchoClientApplication} and the method name where you might have +expected a C++ scope operator (@code{::}). This is intentional. + +The name is not actually a class name, it is a logging component name. When +there is a one-to-one correspondence between a source file and a class, this +will generally be the class name but you should understand that it is not +actually a class name, and there is a single colon there instead of a double +colon to remind you in a relatively subtle way to conceptually separate the +logging component name from the class name. + +It turns out that in some cases, it can be hard to determine which method +actually generates a log message. If you look in the text above, you may +wonder where the string ``@code{Received 1024 bytes from 10.1.1.2}'' comes +from. You can resolve this by ORing the @code{prefix_func} level into the +@code{NS_LOG} environment variable. Try doing the following, + +@verbatim + export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func' +@end verbatim + +Note that the quotes are required since the vertical bar we use to indicate an +OR operation is also a Unix pipe connector. + +Now, if you run the script you will see that the logging system makes sure +that every message from the given log component is prefixed with the component +name. + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + UdpEchoClientApplication:UdpEchoClient() + UdpEchoClientApplication:StartApplication() + UdpEchoClientApplication:ScheduleTransmit() + UdpEchoClientApplication:Send() + UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + UdpEchoClientApplication:HandleRead(0x62c710, 0x62ce40) + UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 + UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + ~/repos/ns-3-dev > +@end verbatim + +You can now see all of the messages coming from the UDP echo client application +are identified as such. The message ``Received 1024 bytes from 10.1.1.2'' is +now clearly identified as coming from the echo client application. The +remaining message must be coming from the UDP echo server application. We +can enable that component by entering a colon separated list of components in +the NS_LOG environment variable. + +@verbatim + export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func: + UdpEchoServerApplication=level_all|prefix_func' +@end verbatim + +Note that you will need to remove the newline after the @code{:} in the +example text above. + +Now, if you run the script you will see all of the log messages from both the +echo client and server applications. You may see that this can be very useful +in debugging problems. + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + UdpEchoServerApplication:UdpEchoServer() + UdpEchoClientApplication:UdpEchoClient() + UdpEchoServerApplication:StartApplication() + UdpEchoClientApplication:StartApplication() + UdpEchoClientApplication:ScheduleTransmit() + UdpEchoClientApplication:Send() + UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 + UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 + UdpEchoServerApplication:HandleRead(): Echoing packet + UdpEchoClientApplication:HandleRead(0x62c760, 0x62ce90) + UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 + UdpEchoServerApplication:StopApplication() + UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoServerApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + UdpEchoServerApplication:~UdpEchoServer() + ~/repos/ns-3-dev > +@end verbatim + +It is also sometimes useful to be able to see the simulation time at which a +log message is generated. You can do this by ORing in the prefix_time bit. + +@verbatim + export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time: + UdpEchoServerApplication=level_all|prefix_func|prefix_time' +@end verbatim + +If you run the script now, you should see the following output: + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + 0ns UdpEchoServerApplication:UdpEchoServer() + 0ns UdpEchoClientApplication:UdpEchoClient() + 1000000000ns UdpEchoServerApplication:StartApplication() + 2000000000ns UdpEchoClientApplication:StartApplication() + 2000000000ns UdpEchoClientApplication:ScheduleTransmit() + 2000000000ns UdpEchoClientApplication:Send() + 2000000000ns UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 + 2003686400ns UdpEchoServerApplication:HandleRead(): Received 1024 bytes + from 10.1.1.1 + 2003686400ns UdpEchoServerApplication:HandleRead(): Echoing packet + 2007372800ns UdpEchoClientApplication:HandleRead(0x62c8c0, 0x62d020) + 2007372800ns UdpEchoClientApplication:HandleRead(): Received 1024 bytes + from 10.1.1.2 + 10000000000ns UdpEchoServerApplication:StopApplication() + 10000000000ns UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoServerApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + UdpEchoServerApplication:~UdpEchoServer() + ~/repos/ns-3-dev > +@end verbatim + +You can see that the constructor for the UdpEchoServer was called at a +simulation time of 0 nanoseconds. This is actually happening before the +simulation starts. The same for the UdpEchoClient constructor. + +Recall that the @code{first.cc} script started the echo server application at +one second into the simulation. You can now see that the +@code{StartApplication} method of the server is, in fact, called at one second +(or one billion nanoseconds). You can also see that the echo client +application is started at a simulation time of two seconds as we requested in +the script. + +You can now follow the progress of the simulation from the +@code{ScheduleTransmit} call in the client that calls @code{Send} to the +@code{HandleRead} callback in the echo server application. Note that the +elapsed time as the packet is sent across the point-to-point link is 3.6864 +milliseconds. You see the echo server logging a message telling you that it +has echoed the packet and then, after a delay, you see the echo client receive +the echoed packet in its @code{HandleRead} method. + +There is a lot that is happening under the covers in this simulation that you +are not seeing as well. You can very easily follow the entire process by +turning on all of the logging components in the system. Try setting the +@code{NS_LOG} variable to the following, + +@verbatim + export 'NS_LOG=*=level_all|prefix_func|prefix_time' +@end verbatim + +The asterisk above is the logging component wildcard. This will turn on all +of the logging in all of the components used in the simulation. I won't +reproduce the output here (as of this writing it produces 772 lines of output +for the single packet echo) but you can redirect this information into a file +and look through it with your favorite editor if you like, + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first >& log.out +@end verbatim + +I personally use this quite a bit when I am presented with a problem and I +have no idea where things are going wrong. I can follow the progress of the +code quite easily without having to set breakpoints and step through code +in a debugger. When I have a general idea about what is going wrong, I +transition into a debugger for fine-grained examination of the problem. This +kind of output can be especially useful when your script does something +completely unexpected. If you are stepping using a debugger you may miss an +unexpected excursion completely. Logging the excursion makes it quickly +visible. + +@node Adding Logging to your Code +@subsection Adding Logging to your Code +@cindex NS_LOG +You can add new logging to your simulations by making calls to the log +component via several macros. Let's do so in the @code{first.cc} script we +have in the @code{scratch} directory. + +Recall that we have defined a logging component in that script: + +@verbatim + NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); +@end verbatim + +You now know that you can enable all of the logging for this component by +setting the @code{NS_LOG} environment variable to the various levels. Let's +go ahead add some logging to the script. The macro used to add an +informational level log message is @code{NS_LOG_INFO}. Go ahead and add one +just before we start creating the nodes that tells you that the script is +``Creating Topology.'' This is done as in this code snippet, + +@verbatim + NS_LOG_INFO ("Creating Topology"); +@end verbatim + +Now build the script using waf and clear the @code{NS_LOG} variable to turn +off the torrent of logging we previously enabled: + +@verbatim + ~/repos/ns-3-dev > export NS_LOG= +@end verbatim + +Now, if you run the script, you will not see your new message since its +associated logging component (@code{FirstScriptExample}) has not been enabled. +In order to see your message you will have to enable the +@code{FirstScriptExample} logging component with a level greater than or equal +to @code{NS_LOG_INFO}. If you just want to see this particular level of +logging, you can enable it by, + +@verbatim + ~/repos/ns-3-dev > export NS_LOG=FirstScriptExample=info +@end verbatim + +If you now run the script you will see your new ``Creating Topology'' log +message, + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Creating Topology + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + ~/repos/ns-3-dev > +@end verbatim + +@c ======================================================================== +@c Using Command Line Arguments +@c ======================================================================== +@node Using Command Line Arguments +@section Using Command Line Arguments + +@subsection Overriding Default Attributes +@cindex command line arguments +Another way you can change how @command{ns-3} scripts behave without editing +and building is via @emph{command line arguments.} We provide a mechanism to +parse command line arguments and automatically set local and global variables +based on those arguments. + +The first step in using the command line argument system is to declare the +command line parser. This is done quite simply (in your main program) as +in the following code, + +@verbatim + int + main (int argc, char *argv[]) + { + ... + + CommandLine cmd; + cmd.Parse (argc, argv); + + ... + } +@end verbatim + +This simple two line snippet is actually very useful by itself. It opens the +door to the @command{ns-3} global variable and attribute systems. Go ahead +and add that two lines of code to the @code{first.cc} script at the start of +@code{main}. Go ahead and build the script and run it, but ask the script +for help in the following way, + +@verbatim + ~/repos/ns-3-dev > ./waf --run "scratch/first --PrintHelp" +@end verbatim + +This will ask Waf to run the @code{scratch/first} script and pass the command +line argument @code{--PrintHelp} to the script. The quotes are required to +sort out which program gets which argument. The command line parser will +now see the @code{--PrintHelp} argument and respond with, + +@verbatim + ~/repos/ns-3-dev > ./waf --run ``scratch/first --PrintHelp'' + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + --PrintHelp: Print this help message. + --PrintGroups: Print the list of groups. + --PrintTypeIds: Print all TypeIds. + --PrintGroup=[group]: Print all TypeIds of group. + --PrintAttributes=[typeid]: Print all attributes of typeid. + --PrintGlobals: Print the list of globals. + ~/repos/ns-3-dev > +@end verbatim + +Let's focus on the @code{--PrintAttributes} option. We have already hinted +at the @command{ns-3} attribute system while walking through the +@code{first.cc} script. We looked at the following lines of code, + +@verbatim + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); +@end verbatim + +and mentioned that @code{DataRate} was actually an @code{Attribute} of the +@code{PointToPointNetDevice}. Let's use the command line argument parser +to take a look at the attributes of the PointToPointNetDevice. The help +listing says that we should provide a @code{TypeId}. This corresponds to the +class name of the class to which the attributes belong. In this case it will +be @code{ns3::PointToPointNetDevice}. Let's go ahead and type in, + +@verbatim + ./waf --run "scratch/first --PrintAttributes=ns3::PointToPointNetDevice" +@end verbatim + +The system will print out all of the attributes of this kind of net device. +Among the attributes you will see listed is, + +@verbatim + --ns3::PointToPointNetDevice::DataRate=[32768bps]: + The default data rate for point to point links +@end verbatim + +This is the default value that will be used when a @code{PointToPointNetDevice} +is created in the system. We overrode this default with the attribute +setting in the @code{PointToPointHelper} above. Let's use the default values +for the point-to-point devices and channels by deleting the +@code{SetDeviceAttribute} call and the @code{SetChannelAttribute} call from +the @code{first.cc} we have in the scratch directory. + +Your script should now just declare the @code{PointToPointHelper} and not do +any @code{set} operations as in the following example, + +@verbatim + ... + + NodeContainer nodes; + nodes.Create (2); + + PointToPointHelper pointToPoint; + + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); + + ... +@end verbatim + +Go ahead and build the new script with Waf (@code{./waf}) and let's go back +and enable some logging from the UDP echo server application and turn on the +time prefix. + +@verbatim + export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time' +@end verbatim + +If you run the script, you should now see the following output, + +@verbatim + ~/repos/ns-3-dev > ./waf --run scratch/first + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + 0ns UdpEchoServerApplication:UdpEchoServer() + 1000000000ns UdpEchoServerApplication:StartApplication() + Sent 1024 bytes to 10.1.1.2 + 2257324218ns Received 1024 bytes from 10.1.1.1 + 2257324218ns Echoing packet + Received 1024 bytes from 10.1.1.2 + 10000000000ns UdpEchoServerApplication:StopApplication() + UdpEchoServerApplication:DoDispose() + UdpEchoServerApplication:~UdpEchoServer() + ~/repos/ns-3-dev > +@end verbatim + +Recall that the last time we looked at the simulation time at which the packet +was received by the echo server, it was at 2.0036864 seconds. Now it is +receiving the packet at about 2.257 seconds. This is because we just dropped +the data rate of the @code{PointToPointNetDevice} down to its default of +32768 bits per second from five megabits per second. + +If we were to provide a new @code{DataRate} using the command line, we could +speed our simulation up again. We do this in the following way, according to +the formula implied by the help item: + +@verbatim + ./waf --run "scratch/first --ns3::PointToPointNetDevice::DataRate=5Mbps" +@end verbatim + +This will set the default value of the @code{DataRate} attribute back to +five megabits per second. To get the original behavior of the script back, +we will have to set the speed-of-light delay of the channel. We can ask the +command line system to print out the @code{Attributes} of the channel just +like we did the net device: + +@verbatim + ./waf --run "scratch/first --PrintAttributes=ns3::PointToPointChannel" +@end verbatim + +We discover the @code{Delay} attribute of the channel is set in the following +way: + +@verbatim + --ns3::PointToPointChannel::Delay=[0ns]: + Transmission delay through the channel +@end verbatim + +We can then set both of these default values through the command line system, + +@verbatim + ./waf --run "scratch/first + --ns3::PointToPointNetDevice::DataRate=5Mbps + --ns3::PointToPointChannel::Delay=2ms" +@end verbatim + +in which case we recover the timing we had when we explicitly set the +@code{DataRate} and @code{Delay} in the script: + +@verbatim + Compilation finished successfully + 0ns UdpEchoServerApplication:UdpEchoServer() + 1000000000ns UdpEchoServerApplication:StartApplication() + Sent 1024 bytes to 10.1.1.2 + 2003686400ns Received 1024 bytes from 10.1.1.1 + 2003686400ns Echoing packet + Received 1024 bytes from 10.1.1.2 + 10000000000ns UdpEchoServerApplication:StopApplication() + UdpEchoServerApplication:DoDispose() + UdpEchoServerApplication:~UdpEchoServer() +@end verbatim + +Note that the packet is again received by the server at 2.0036864 seconds. We +could actually set any of the attributes used in the script in this way. In +particular we could set the @code{UdpEchoClient} attribute @code{MaxPackets} +to some other value than one. + +How would you go about that? Give it a try. Remember you have to comment +out the place we override the default attribute in the script. Then you +have to rebuild the script using the default. You will also have to find the +syntax for actually setting the new default atribute value using the command +line help facility. Once you have this figured out you should be able to +control the number of packets echoed from the command line. Since we're nice +folks, we'll tell you that your command line should end up looking something +like, + +@verbatim + ./waf --run "scratch/first + --ns3::PointToPointNetDevice::DataRate=5Mbps + --ns3::PointToPointChannel::Delay=2ms + --ns3::UdpEchoClient::MaxPackets=2" +@end verbatim + +@subsection Hooking Your Own Values +You can also add your own hooks to the command line system. This is done +quite simply by using the @code{AddValue} method to the command line parser. + +Let's use this facility to specify the number of packets to echo in a +completely different way. Let's add a local variable called @code{nPackets} +to the @code{main} function. We'll initialize it to one to match our previous +default behavior. To allow the command line parser to change this value, we +need to hook the value into the parser. We do this by adding a call to +@code{AddValue}. Go ahead and change the @code{scratch/first.cc} script to +start with the following code, + +@verbatim + int + main (int argc, char *argv[]) + { + uint32_t nPackets = 1; + + CommandLine cmd; + cmd.AddValue("nPackets", "Number of packets to echo", nPackets); + cmd.Parse (argc, argv); + + ... +@end verbatim + +Scroll down to the point in the script where we set the @code{MaxPackets} +attribute and change it so that it is set to the variable @code{nPackets} +instead of the constant @code{1} as is shown below. + +@verbatim + echoClient.SetAppAttribute ("MaxPackets", UintegerValue (nPackets)); +@end verbatim + +Now if you run the script and provide the @code{--PrintHelp} argument, you +should see your new @code{User Argument} listed in the help display. + +@verbatim + ~/repos/ns-3-dev > ./waf --run "scratch/first --PrintHelp" + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + --PrintHelp: Print this help message. + --PrintGroups: Print the list of groups. + --PrintTypeIds: Print all TypeIds. + --PrintGroup=[group]: Print all TypeIds of group. + --PrintAttributes=[typeid]: Print all attributes of typeid. + --PrintGlobals: Print the list of globals. + User Arguments: + --nPackets: Number of packets to echo + ~/repos/ns-3-dev > +@end verbatim + +If you want to specify the number of packets to echo, you can now do so by +setting the @code{--nPackets} argument in the command line, + +@verbatim + ~/repos/ns-3-dev > ./waf --run "scratch/first --nPackets=2" + Entering directory `/home/craigdo/repos/ns-3-dev/build' + Compilation finished successfully + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + ~/repos/ns-3-dev > +@end verbatim + +You have now echoed two packets. + +You can see that if you are an @command{ns-3} user, you can use the command +line argument system to control global values and attributes. If you are a +model author, you can add new attributes to your Objects and they will +automatically be available for setting by your users through the command line +system. If you are a script author, you can add new variables to your scripts +and hook them into the command line system quite painlessly. + +@c ======================================================================== +@c Using the Tracing System +@c ======================================================================== +@node Using the Tracing System +@section Using the Tracing System + +The whole point of simulation is to generate output for further study, and +the @command{ns-3} tracing system is a primary mechanism for this. Since +@command{ns-3} is a C++ program, standard facilities for generating output +from C++ programs could be used: + +@verbatim + #include + ... + int main () + { + ... + std::cout << "The value of x is " << x << std::endl; + ... + } +@end verbatim + +You could even use the logging module to add a little structure to your +solution. There are many well-known problems generated by such approaches +and so we have provided a generic event tracing subsystem to address the +issues we thought were important. + +The basic goals of the @command{ns-3} tracing system are: + +@itemize @bullet +@item For basic tasks, the tracing system should allow the user to generate +standard tracing for popular tracing sources, and to customize which objects +generate the tracing; +@item Intermediate users must be able to extend the tracing system to modify +the output format generated, or to insert new tracing sources, without +modifying the core of the simulator; +@item Advanced users can modify the simulator core to add new tracing sources +and sinks. +@end itemize + +The @command{ns-3} tracing system is built on the concepts of independent +tracing sources and tracing sinks, and a uniform mechanism for connecting +sources to sinks. Trace sources are entities that can signal events that +happen in a simulation and provide access to interesting underlying data. +For example, a trace source could indicate when a packet is received by a net +device and provide access to the packet contents for interested trace sinks. + +Trace sources are not useful by themselves, they must be ``connected'' to +other pieces of code that actually do something useful with the information +provided by the sink. Trace sinks are consumers of the events and data +provided by the trace sources. For example, one could create a trace sink +that would (when connected to the trace source of the previous example) print +out interesting parts of the received packet. + +The rationale for this explicit division is to allow users to attach new +types of sinks to existing tracing sources, without requiring editing and +recompilation of the the core of the simulator. Thus, in the example above, +a user could define a new tracing sink in her script and attach it to an +existing tracing source defined in the simulation core by editing only the +user script. + +In this tutorial, we will walk through some pre-defined sources and sinks and +show how they may be customized with little user effort. See the ns-3 manual +or how-to sections for information on advanced tracing configuration including +extending the tracing namespace and creating new tracing sources. + +@cindex tracing +@cindex ASCII tracing +@subsection ASCII Tracing +@command{Ns-3} provides helper functionality that wraps the low-level tracing +system to help you with the details involved in configuring some easily +understood packet traces. If you enable this functionality, you will see +output in a ASCII files --- thus the name. For those familiar with +@command{ns-2} output, this type of trace is analogous to the @command{out.tr} +generated by many scripts. + +@cindex tracing packets +Let's just jump right in and add some ASCII tracing output to our +@code{first.cc} script. The first thing you need to do is to add the +following code to the script just before the call to @code{Simulator::Run ()}. + +@verbatim + std::ofstream ascii; + ascii.open ("first.tr"); + PointToPointHelper::EnableAsciiAll (ascii); +@end verbatim + +The first two lines are just vanilla C++ code to open a stream that will be +written to a file named ``first.tr.'' See your favorite C++ tutorial if you +are unfamiliar with this code. The last line of code in the snippet above +tells @command{ns-3} that you want to enable ASCII tracing on all +point-to-point devices in your simulation; and you want the (provided) trace +sinks to write out information about packet movement in ASCII format to the +stream provided. For those familiar with @command{ns-2}, the traced events are +equivalent to the popular trace points that log "+", "-", "d", and "r" events. + +Since we have used a @code{std::ofstream} object, we also need to include the +appropriate header. Add the following line to the script (I typically add it +above the ns-3 includes): + +@verbatim + #include +@end verbatim + +You can now build the script and run it from the command line: + +@verbatim + ./waf --run scratch/first +@end verbatim + +@cindex first.tr +Just as you have seen previously, you may see some messages from Waf and then +the ``Compilation finished successfully'' with some number of messages from +the running program. + +When it ran, the program will have created a file named @code{first.tr}. +Because of the way that Waf works, the file is not created in the local +directory, it is created at the top-level directory of the repository by +default. If you want to control where the traces are saved you can use the +@code{--cwd} option of Waf to specify this. We have not done so, thus we +need to change into the top level directory of our repo and take a look at +the ASCII trace file @code{first.tr} in your favorite editor. + +@subsubsection Parsing Ascii Traces +@cindex parsing ascii traces +There's a lot of information there in a pretty dense form, but the first thing +to notice is that there are a number of distinct lines in this file. It may +be difficult to see this clearly unless you widen your window considerably. + +Each line in the file corresponds to a @emph{trace event}. In this case +we are tracing events on the @emph{transmit queue} present in every +point-to-point net device in the simulation. The transmit queue is a queue +through which every packet destined for a point-to-point channel must pass. +Note that each line in the trace file begins with a lone character (has a +space after it). This character will have the following meaning: + +@cindex ascii trace enqueue operation +@cindex ascii trace dequeue operation +@cindex ascii trace drop operation +@cindex ascii trace receive operation +@itemize @bullet +@item @code{+}: An enqueue operation occurred on the device queue; +@item @code{-}: A dequeue operation occurred on the device queue; +@item @code{d}: A packet was dropped, typically because the queue was full; +@item @code{r}: A packet was received by the net device. +@end itemize + +Let's take a more detailed view of the first line in the trace file. I'll +break it down into sections (indented for clarity) with a two digit reference +number on the left side: + +@verbatim + 00 + + 01 2 + 02 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue + 03 ns3::PppHeader ( + 04 Point-to-Point Protocol: IP (0x0021)) + 05 ns3::Ipv4Header ( + 06 tos 0x0 ttl 64 id 0 offset 0 flags [none] + 07 length: 1052 10.1.1.1 > 10.1.1.2) + 08 ns3::UdpHeader ( + 09 length: 1032 49153 > 9) + 10 Payload (size=1024) +@end verbatim + +@cindex trace event +@cindex simulation time +The first line of this expanded trace event (reference number 00) is the +operation. We have a @code{+} character, so this corresponds to an +@emph{enqueue} operation on the transmit queue. The second line (reference 01) +is the simulation time expressed in seconds. You may recall that we asked the +@code{UdpEchoClientApplication} to start sending packets at two seconds. Here +we see confirmation that this is, indeed, happening. + +@cindex node number +@cindex net device number +@cindex smart pointer +The next line of the example trace (reference 02) tell us which trace source +originated this event (expressed in the tracing namespace). You can think +of the tracing namespace somewhat like you would a filesystem namespace. The +root of the namespace is the @code{NodeList}. This corresponds to a container +managed in the @command{ns-3} core code that contains all of the nodes that are +created in a script. Just as a filesystem may have directories under the +root, we may have node numbers in the @code{NodeList}. The string +@code{/NodeList/0} therefore refers to the zeroth node in the @code{NodeList} +which we typically think of as ``node 0.'' In each node there is a list of +devices that have been installed. This list appears next in the namespace. +You can see that this trace event comes from @code{DeviceList/0} which is the +zeroth device installed in the node. + +The next string, @code{$ns3::PointToPointNetDevice} tells you what kind of +device is in the zeroth position of the device list for node zero. +Recall that the operation @code{+} found at reference 00 meant that an enqueue +operation happened on the transmit queue of the device. This is reflected in +the final segments of the ``trace path'' which are @code{TxQueue/Enqueue}. + +The remaining lines in the trace should be fairly intuitive. References 03-04 +indicate that the packet is encapulated in the point-to-point protocol. +References 05-07 show that the packet has an IP version four header and has +originated from IP address 10.1.1.1 and is destined for 10.1.1.2. References +08-09 show that this packet has a UDP header and, finally, reference 10 shows +that the payload is the expected 1024 bytes. + +The next line in the trace file shows the same packet being dequeued from the +transmit queue on the same node. + +The Third line in the trace file shows the packet being received by the net +device on the node with the echo server. I have reproduced that event below. + +@verbatim + 00 r + 01 2.25732 + 02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/Rx + 03 ns3::PppHeader ( + 04 Point-to-Point Protocol: IP (0x0021)) + 05 ns3::Ipv4Header ( + 06 tos 0x0 ttl 64 id 0 offset 0 flags [none] + 07 length: 1052 10.1.1.1 > 10.1.1.2) + 08 ns3::UdpHeader ( + 09 length: 1032 49153 > 9) + 10 Payload (size=1024) +@end verbatim + +Notice that the trace operation is now @code{r} and the simulation time has +increased to 2.25732 seconds. If you have been following the tutorial steps +closely this means that you have left the @code{DataRate} of the net devices +and the channel @code{Delay} set to their default values. This time should +be familiar as you have seen it before in a previous section. + +The trace source namespace entry (reference 02) has changed to reflect that +this event is coming from node 1 (@code{/NodeList/1}) and the packet reception +trace source (@code{/Rx}). It should be quite easy for you to follow the +progress of the packet through the topology by looking at the rest of the +traces in the file. + +@subsection PCAP Tracing +@cindex pcap +@cindex Wireshark +The @command{ns-3} device helpers can also be used to create trace files in the +@code{.pcap} format. The acronym pcap (usually written in lower case) stands +for @emph{p}acket @emph{cap}ture, and is actually an API that includes the +definition of a @code{.pcap} file format. The most popular program that can +read and display this format is Wireshark (formerly called Ethereal). +However, there are many traffic trace analyzers that use this packet format. +We encourage users to exploit the many tools available for analyzing pcap +traces. In this tutorial, we concentrate on viewing pcap traces with tcpdump. + +@cindex pcap tracing +The code used to enable pcap tracing is a one-liner. + +@verbatim + PointToPointHelper::EnablePcapAll ("first"); +@end verbatim + +Go ahead and insert this line of code after the ASCII tracing code we just +added to @code{scratch/first.cc}. Notice that we only passed the string +``first,'' and not ``first.pcap'' or something similar. This is because the +parameter is a prefix, not a complete file name. The helper will actually +create a trace file for every point-to-point device in the simulation. The +file names will be built using the prefix, the node number, the device number + and a ``.pcap'' suffix. + +In our example script, we will eventually see files named ``first-0-0.pcap'' +and ``first.1-0.pcap'' which are the pcap traces for node 0-device 0 and +node 1-device 1, respectively. + +Once you have added the line of code to enable pcap tracing, you can run the +script in the usual way: + +@verbatim + ./waf --run scratch/first +@end verbatim + +If you look at the top level directory of your distribution, you should now +see three log files: @code{first.tr} is the ASCII trace file we have +previously examined. @code{first-0-0.pcap} and @code{first-1-0.pcap} +are the new pcap files we just generated. + +@subsubsection Reading output with tcpdump +@cindex tcpdump +The easiest thing to do at this point will be to use @code{tcpdump} to look +at the @code{pcap} files. Output from dumping both files is shown below: + +@verbatim + ~/repos/ns-3-dev > /usr/sbin/tcpdump -r first-0-0.pcap -nn -tt + reading from file first-0-0.pcap, link-type PPP (PPP) + 2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 + 2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 + ~/repos/ns-3-dev > /usr/sbin/tcpdump -r first-1-0.pcap -nn -tt + reading from file first-1-0.pcap, link-type PPP (PPP) + 2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 + 2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 + ~/repos/ns-3-dev > +@end verbatim + +You can see in the dump of ``first-0.0.pcap'' (the client device) that the +echo packet is sent at 2 seconds into the simulation. If you look at the +second dump (of ``first-1-0.pcap'') you can see that packet being received +at 2.257324 seconds. You see the packet being echoed at 2.257324 seconds +in the second dump, and finally, you see the packet being received back at +the client in the first dump at 2.514648 seconds. + +@subsubsection Reading output with Wireshark +@cindex Wireshark +If you are unfamilar with Wireshark, there is a web site available from which +you can download programs and documentation: @uref{http://www.wireshark.org/}. + +Wireshark is a graphical user interface which can be used for displaying these +trace files. If you have Wireshark available, you can open each of the trace +files and display the contents as if you had captured the packets using a +@emph{packet sniffer}. diff --git a/examples/csma-bridge.cc b/examples/csma-bridge.cc new file mode 100644 index 000000000..4d99b4e24 --- /dev/null +++ b/examples/csma-bridge.cc @@ -0,0 +1,171 @@ +/* -*- 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 + */ + +// Network topology +// +// n0 n1 +// | | +// ---------- +// | Switch | +// ---------- +// | | +// n2 n3 +// +// +// - CBR/UDP flows from n0 to n1 and from n3 to n0 +// - DropTail queues +// - Tracing of queues and packet receptions to file "csma-bridge.tr" + +#include +#include + +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/core-module.h" +#include "ns3/helper-module.h" +#include "ns3/bridge-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("CsmaBridgeExample"); + +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 + LogComponentEnable ("CsmaBridgeExample", LOG_LEVEL_INFO); +#endif + + // + // Make the random number generators generate reproducible results. + // + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + // + // Allow the user to override any of the defaults and the above Bind() at + // run-time, via command-line arguments + // + CommandLine cmd; + cmd.Parse (argc, argv); + + // + // Explicitly create the nodes required by the topology (shown above). + // + NS_LOG_INFO ("Create nodes."); + NodeContainer terminals; + terminals.Create (4); + + NodeContainer csmaSwitch; + csmaSwitch.Create (1); + + NS_LOG_INFO ("Build Topology"); + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", DataRateValue (5000000)); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + + // Create the csma links, from each terminal to the switch + + NetDeviceContainer terminalDevices; + NetDeviceContainer switchDevices; + + for (int i = 0; i < 4; i++) + { + NetDeviceContainer link = csma.Install (NodeContainer (terminals.Get (i), csmaSwitch)); + terminalDevices.Add (link.Get (0)); + switchDevices.Add (link.Get (1)); + } + + // Create the bridge netdevice, which will do the packet switching + Ptr switchNode = csmaSwitch.Get (0); + BridgeHelper bridge; + bridge.Install (switchNode, switchDevices); + + // Add internet stack to the terminals + InternetStackHelper internet; + internet.Install (terminals); + + // We've got the "hardware" in place. Now we need to add IP addresses. + // + NS_LOG_INFO ("Assign IP Addresses."); + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.1.1.0", "255.255.255.0"); + ipv4.Assign (terminalDevices); + + // + // Create an OnOff application to send UDP datagrams from node zero to node 1. + // + NS_LOG_INFO ("Create Applications."); + uint16_t port = 9; // Discard port (RFC 863) + + OnOffHelper onoff ("ns3::UdpSocketFactory", + Address (InetSocketAddress (Ipv4Address ("10.1.1.2"), port))); + onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + + ApplicationContainer app = onoff.Install (terminals.Get (0)); + // Start the application + app.Start (Seconds (1.0)); + app.Stop (Seconds (10.0)); + + // Create an optional packet sink to receive these packets + PacketSinkHelper sink ("ns3::UdpSocketFactory", + Address (InetSocketAddress (Ipv4Address::GetAny (), port))); + app = sink.Install (terminals.Get (1)); + app.Start (Seconds (0.0)); + + // + // Create a similar flow from n3 to n0, starting at time 1.1 seconds + // + onoff.SetAttribute ("Remote", + AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.1"), port))); + app = onoff.Install (terminals.Get (3)); + app.Start (Seconds (1.1)); + app.Stop (Seconds (10.0)); + + app = sink.Install (terminals.Get (0)); + app.Start (Seconds (0.0)); + + + // + // Configure tracing of all enqueue, dequeue, and NetDevice receive events. + // Trace output will be sent to the file "csma-bridge.tr" + // + NS_LOG_INFO ("Configure Tracing."); + std::ofstream ascii; + ascii.open ("csma-bridge.tr"); + CsmaHelper::EnableAsciiAll (ascii); + + // + // Also configure some tcpdump traces; each interface will be traced. + // The output files will be named: + // csma-bridge.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + // + CsmaHelper::EnablePcapAll ("csma-bridge"); + + // + // Now, do the actual simulation. + // + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +} diff --git a/examples/csma-bridge.py b/examples/csma-bridge.py new file mode 100644 index 000000000..0c8e8e3aa --- /dev/null +++ b/examples/csma-bridge.py @@ -0,0 +1,156 @@ +# /* +# * 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 +# */ + +# Network topology +# +# n0 n1 +# | | +# ---------- +# | Switch | +# ---------- +# | | +# n2 n3 +# +# +# - CBR/UDP flows from n0 to n1 and from n3 to n0 +# - DropTail queues +# - Tracing of queues and packet receptions to file "csma-bridge.tr" + +import ns3 + + +def main(argv): + # + # Make the random number generators generate reproducible results. + # + ns3.RandomVariable.UseGlobalSeed(1, 1, 2, 3, 5, 8) + + # + # Allow the user to override any of the defaults and the above Bind() at + # run-time, via command-line arguments + # + cmd = ns3.CommandLine() + cmd.Parse(argv) + + # + # Explicitly create the nodes required by the topology(shown above). + # + #print "Create nodes." + terminals = ns3.NodeContainer() + terminals.Create(4) + + csmaSwitch = ns3.NodeContainer() + csmaSwitch.Create(1) + + #print "Build Topology" + csma = ns3.CsmaHelper() + csma.SetChannelAttribute("DataRate", ns3.DataRateValue(ns3.DataRate(5000000))) + csma.SetChannelAttribute("Delay", ns3.TimeValue(ns3.MilliSeconds(2))) + + # Create the csma links, from each terminal to the switch + + terminalDevices = ns3.NetDeviceContainer() + switchDevices = ns3.NetDeviceContainer() + + for i in range(4): + link = csma.Install(ns3.NodeContainer(ns3.NodeContainer(terminals.Get(i)), csmaSwitch)) + terminalDevices.Add(link.Get(0)) + switchDevices.Add(link.Get(1)) + + # Create the bridge netdevice, which will do the packet switching + switchNode = csmaSwitch.Get(0) + bridgeDevice = ns3.BridgeNetDevice() + switchNode.AddDevice(bridgeDevice) + + for portIter in range(switchDevices.GetN()): + bridgeDevice.AddBridgePort(switchDevices.Get(portIter)) + + # Add internet stack to the terminals + internet = ns3.InternetStackHelper() + internet.Install(terminals) + + # We've got the "hardware" in place. Now we need to add IP addresses. + # + #print "Assign IP Addresses." + ipv4 = ns3.Ipv4AddressHelper() + ipv4.SetBase(ns3.Ipv4Address("10.1.1.0"), ns3.Ipv4Mask("255.255.255.0")) + ipv4.Assign(terminalDevices) + + # + # Create an OnOff application to send UDP datagrams from node zero to node 1. + # + #print "Create Applications." + port = 9 # Discard port(RFC 863) + + onoff = ns3.OnOffHelper("ns3::UdpSocketFactory", + ns3.Address(ns3.InetSocketAddress(ns3.Ipv4Address("10.1.1.2"), port))) + onoff.SetAttribute("OnTime", ns3.RandomVariableValue(ns3.ConstantVariable(1))) + onoff.SetAttribute("OffTime", ns3.RandomVariableValue(ns3.ConstantVariable(0))) + + app = onoff.Install(ns3.NodeContainer(terminals.Get(0))) + # Start the application + app.Start(ns3.Seconds(1.0)) + app.Stop(ns3.Seconds(10.0)) + + # Create an optional packet sink to receive these packets + sink = ns3.PacketSinkHelper("ns3::UdpSocketFactory", + ns3.Address(ns3.InetSocketAddress(ns3.Ipv4Address.GetAny(), port))) + app = sink.Install(ns3.NodeContainer(terminals.Get(1))) + app.Start (ns3.Seconds (0.0)) + + # + # Create a similar flow from n3 to n0, starting at time 1.1 seconds + # + onoff.SetAttribute("Remote", + ns3.AddressValue(ns3.InetSocketAddress(ns3.Ipv4Address("10.1.1.1"), port))) + app = onoff.Install(ns3.NodeContainer(terminals.Get(3))) + app.Start(ns3.Seconds(1.1)) + app.Stop(ns3.Seconds(10.0)) + + app = sink.Install(ns3.NodeContainer(terminals.Get(0))) + app.Start (ns3.Seconds (0.0)) + + # + # Configure tracing of all enqueue, dequeue, and NetDevice receive events. + # Trace output will be sent to the file "csma-bridge.tr" + # + #print "Configure Tracing." + #std.ofstream ascii + #ascii.open("csma-bridge.tr") + #CsmaHelper.EnableAsciiAll(ascii) + + # + # Also configure some tcpdump traces; each interface will be traced. + # The output files will be named: + # csma-bridge.pcap-- + # and can be read by the "tcpdump -r" command(use "-tt" option to + # display timestamps correctly) + # + ns3.CsmaHelper.EnablePcapAll("csma-bridge") + + # + # Now, do the actual simulation. + # + #print "Run Simulation." + ns3.Simulator.Run() + ns3.Simulator.Destroy() + #print "Done." + + + +if __name__ == '__main__': + import sys + main(sys.argv) + diff --git a/examples/csma-broadcast.cc b/examples/csma-broadcast.cc index 963be3ff5..64c20645d 100644 --- a/examples/csma-broadcast.cc +++ b/examples/csma-broadcast.cc @@ -69,8 +69,8 @@ main (int argc, char *argv[]) NS_LOG_INFO ("Build Topology."); CsmaHelper csma; - csma.SetChannelParameter ("DataRate", DataRateValue (DataRate(5000000))); - csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds(2))); + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds(2))); NetDeviceContainer n0 = csma.Install (c0); NetDeviceContainer n1 = csma.Install (c1); diff --git a/examples/csma-multicast.cc b/examples/csma-multicast.cc index a7775c7b8..a50045b17 100644 --- a/examples/csma-multicast.cc +++ b/examples/csma-multicast.cc @@ -58,8 +58,8 @@ main (int argc, char *argv[]) // // Set up default values for the simulation. // - // Select Ethernet II-style encapsulation (no LLC/Snap header) - Config::SetDefault ("ns3::CsmaNetDevice::EncapsulationMode", StringValue ("IpArp")); + // Select DIX/Ethernet II-style encapsulation (no LLC/Snap header) + Config::SetDefault ("ns3::CsmaNetDevice::EncapsulationMode", StringValue ("Dix")); // Allow the user to override any of the defaults at // run-time, via command-line arguments @@ -75,8 +75,8 @@ main (int argc, char *argv[]) NS_LOG_INFO ("Build Topology."); CsmaHelper csma; - csma.SetChannelParameter ("DataRate", DataRateValue (DataRate (5000000))); - csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2))); + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate (5000000))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); // We will use these NetDevice containers later, for IP addressing NetDeviceContainer nd0 = csma.Install (c0); // First LAN diff --git a/examples/csma-one-subnet.cc b/examples/csma-one-subnet.cc index bd827b904..ea74763c8 100644 --- a/examples/csma-one-subnet.cc +++ b/examples/csma-one-subnet.cc @@ -61,33 +61,28 @@ main (int argc, char *argv[]) // Explicitly create the nodes required by the topology (shown above). // NS_LOG_INFO ("Create nodes."); - NodeContainer c; - c.Create (4); + NodeContainer nodes; + nodes.Create (4); NS_LOG_INFO ("Build Topology"); CsmaHelper csma; - csma.SetChannelParameter ("DataRate", DataRateValue (5000000)); - csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2))); + csma.SetChannelAttribute ("DataRate", DataRateValue (5000000)); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); // // Now fill out the topology by creating the net devices required to connect -// the nodes to the channels and hooking them up. AddIpv4CsmaNetDevice will -// create a net device, add a MAC address (in memory of the pink flamingo) and -// connect the net device to a nodes and also to a channel. the -// AddIpv4CsmaNetDevice method returns a net device index for the net device -// created on the node. Interpret nd0 as the net device we created for node -// zero. +// the nodes to the channels and hooking them up. // - NetDeviceContainer nd0 = csma.Install (c); + NetDeviceContainer devices = csma.Install (nodes); InternetStackHelper internet; - internet.Install (c); + internet.Install (nodes); // We've got the "hardware" in place. Now we need to add IP addresses. // NS_LOG_INFO ("Assign IP Addresses."); Ipv4AddressHelper ipv4; ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - ipv4.Assign (nd0); + Ipv4InterfaceContainer interfaces = ipv4.Assign (devices); // // Create an OnOff application to send UDP datagrams from node zero to node 1. @@ -96,11 +91,11 @@ main (int argc, char *argv[]) uint16_t port = 9; // Discard port (RFC 863) OnOffHelper onoff ("ns3::UdpSocketFactory", - Address (InetSocketAddress (Ipv4Address ("10.1.1.2"), port))); + Address (InetSocketAddress (interfaces.GetAddress (1), port))); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); - ApplicationContainer app = onoff.Install (c.Get (0)); + ApplicationContainer app = onoff.Install (nodes.Get (0)); // Start the application app.Start (Seconds (1.0)); app.Stop (Seconds (10.0)); @@ -108,19 +103,21 @@ main (int argc, char *argv[]) // Create an optional packet sink to receive these packets PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny (), port))); - sink.Install (c.Get (1)); + app = sink.Install (nodes.Get (1)); + app.Start (Seconds (0.0)); // // Create a similar flow from n3 to n0, starting at time 1.1 seconds // onoff.SetAttribute ("Remote", - AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.1"), port))); - ApplicationContainer app2 = onoff.Install (c.Get (3)); + AddressValue (InetSocketAddress (interfaces.GetAddress (0), port))); + app = onoff.Install (nodes.Get (3)); + app.Start(Seconds (1.1)); + app.Stop (Seconds (10.0)); - sink.Install (c.Get (0)); + app = sink.Install (nodes.Get (0)); + app.Start (Seconds (0.0)); - app2.Start(Seconds (1.1)); - app2.Stop (Seconds (10.0)); // // Configure tracing of all enqueue, dequeue, and NetDevice receive events. // Trace output will be sent to the file "csma-one-subnet.tr" diff --git a/examples/csma-packet-socket.cc b/examples/csma-packet-socket.cc index f35fc77c5..cb63e9933 100644 --- a/examples/csma-packet-socket.cc +++ b/examples/csma-packet-socket.cc @@ -42,6 +42,14 @@ using namespace ns3; NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample"); +std::ofstream g_os; + +static void +SinkRx (std::string path, Ptr p, const Address &address) +{ + g_os << p->GetSize () << std::endl; +} + int main (int argc, char *argv[]) { @@ -57,13 +65,15 @@ main (int argc, char *argv[]) CommandLine cmd; cmd.Parse (argc, argv); + g_os.open ("csma-packet-socket-sink.tr"); + // Here, we will explicitly create four nodes. NS_LOG_INFO ("Create nodes."); - NodeContainer c; - c.Create (4); + NodeContainer nodes; + nodes.Create (4); PacketSocketHelper packetSocket; - packetSocket.Install (c); + packetSocket.Install (nodes); // create the shared medium used by all csma devices. NS_LOG_INFO ("Create channels."); @@ -74,8 +84,8 @@ main (int argc, char *argv[]) // use a helper function to connect our nodes to the shared channel. NS_LOG_INFO ("Build Topology."); CsmaHelper csma; - csma.SetDeviceParameter ("EncapsulationMode", StringValue ("Llc")); - NetDeviceContainer devs = csma.Install (c, channel); + csma.SetDeviceAttribute ("EncapsulationMode", StringValue ("Llc")); + NetDeviceContainer devs = csma.Install (nodes, channel); NS_LOG_INFO ("Create Applications."); // Create the OnOff application to send raw datagrams @@ -86,19 +96,27 @@ main (int argc, char *argv[]) OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket)); onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1.0))); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0.0))); - - ApplicationContainer apps = onoff.Install (c.Get (0)); + ApplicationContainer apps = onoff.Install (nodes.Get (0)); apps.Start (Seconds (1.0)); apps.Stop (Seconds (10.0)); - + socket.SetSingleDevice (devs.Get (3)->GetIfIndex ()); socket.SetPhysicalAddress (devs.Get (0)->GetAddress ()); socket.SetProtocol (3); onoff.SetAttribute ("Remote", AddressValue (socket)); onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0.0))); - apps = onoff.Install (c.Get (3)); + apps = onoff.Install (nodes.Get (3)); apps.Start (Seconds (1.0)); apps.Stop (Seconds (10.0)); + + PacketSinkHelper sink = PacketSinkHelper ("ns3::PacketSocketFactory", + socket); + apps = sink.Install (nodes.Get (0)); + apps.Start (Seconds (0.0)); + apps.Stop (Seconds (20.0)); + + Config::Connect ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", + MakeCallback (&SinkRx)); // Configure tracing of all enqueue, dequeue, and NetDevice receive events // Trace output will be sent to the csma-packet-socket.tr file @@ -111,4 +129,8 @@ main (int argc, char *argv[]) Simulator::Run (); Simulator::Destroy (); NS_LOG_INFO ("Done."); + + g_os.close (); + + return 0; } diff --git a/examples/csma-star.cc b/examples/csma-star.cc new file mode 100644 index 000000000..8a1d854d3 --- /dev/null +++ b/examples/csma-star.cc @@ -0,0 +1,201 @@ +/* -*- 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/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/global-route-manager.h" + +// Network topology (default) +// +// n2 + + n3 . +// | ... |\ /| ... | . +// ======= \ / ======= . +// CSMA \ / CSMA . +// \ / . +// n1 +--- n0 ---+ n4 . +// | ... | / \ | ... | . +// ======= / \ ======= . +// CSMA / \ CSMA . +// / \ . +// n6 + + n5 . +// | ... | | ... | . +// ======= ======= . +// CSMA CSMA . +// + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("CsmaStar"); + +int +main (int argc, char *argv[]) +{ + // + // Make the random number generators generate reproducible results. + // + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + // + // Set up some default values for the simulation. + // + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (137)); + + // ??? try and stick 15kb/s into the data rate + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("14kb/s")); + + // + // Default number of nodes in the star. Overridable by command line argument. + // + uint32_t nNodes = 7; + + CommandLine cmd; + cmd.AddValue("nNodes", "Number of nodes to place in the star", nNodes); + cmd.Parse (argc, argv); + + NS_LOG_INFO ("Create nodes."); + NodeContainer hubNode; + NodeContainer spokeNodes; + hubNode.Create (1); + Ptr hub = hubNode.Get (0); + spokeNodes.Create (nNodes - 1); + + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); + csma.SetChannelAttribute ("Delay", StringValue ("1ms")); + + NS_LOG_INFO ("Build star topology."); + NetDeviceContainer hubDevices, spokeDevices; + csma.InstallStar (hubNode.Get (0), spokeNodes, hubDevices, spokeDevices); + + NodeContainer fillNodes; + + // + // Just to be nasy, hang some more nodes off of the CSMA channel for each + // spoke, so that there are a total of 16 nodes on each channel. Stash + // all of these new devices into a container. + // + NetDeviceContainer fillDevices; + + uint32_t nFill = 14; + for (uint32_t i = 0; i < spokeDevices.GetN (); ++i) + { + Ptr channel = spokeDevices.Get (i)->GetChannel (); + Ptr csmaChannel = channel->GetObject (); + NodeContainer newNodes; + NetDeviceContainer newDevices; + newNodes.Create (nFill); + fillNodes.Add (newNodes); + fillDevices.Add (csma.Install (newNodes, csmaChannel)); + } + + NS_LOG_INFO ("Install internet stack on all nodes."); + InternetStackHelper internet; + internet.Install (NodeContainer (hubNode, spokeNodes, fillNodes)); + + NS_LOG_INFO ("Assign IP Addresses."); + Ipv4AddressHelper address; + + // + // Assign IPv4 interfaces and IP addresses to the devices we previously + // created. Keep track of the resulting addresses, one for the addresses + // of the hub node, and one for addresses on the spoke nodes. Despite the + // name of the class, what is visible to clients is really the address. + // + Ipv4InterfaceContainer hubAddresses; + Ipv4InterfaceContainer spokeAddresses; + + for(uint32_t i = 0; i < spokeNodes.GetN (); ++i) + { + std::ostringstream subnet; + subnet << "10.1." << i << ".0"; + NS_LOG_INFO ("Assign IP Addresses for CSMA subnet " << subnet.str ()); + address.SetBase (subnet.str ().c_str (), "255.255.255.0"); + hubAddresses.Add (address.Assign (hubDevices.Get (i))); + spokeAddresses.Add (address.Assign (spokeDevices.Get (i))); + } + + NS_LOG_INFO ("Create applications."); + // + // Create a packet sink on the star "hub" to receive packets. + // + uint16_t port = 50000; + Address hubLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), port)); + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", hubLocalAddress); + ApplicationContainer hubApp = packetSinkHelper.Install (hubNode); + hubApp.Start (Seconds (1.0)); + hubApp.Stop (Seconds (10.0)); + + // + // Create OnOff applications to send TCP to the hub, one on each spoke node. + // + OnOffHelper onOffHelper ("ns3::TcpSocketFactory", Address ()); + onOffHelper.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + onOffHelper.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + + ApplicationContainer spokeApps; + + for (uint32_t i = 0; i < spokeNodes.GetN (); ++i) + { + AddressValue remoteAddress (InetSocketAddress (hubAddresses.GetAddress (i), port)); + onOffHelper.SetAttribute ("Remote", remoteAddress); + spokeApps.Add (onOffHelper.Install (spokeNodes.Get (i))); + } + + spokeApps.Start (Seconds (1.0)); + spokeApps.Stop (Seconds (10.0)); + + // + // Because we are evil, we also add OnOff applications to send TCP to the hub + // from the fill devices on each CSMA link. The first nFill nodes in the + // fillNodes container are on the CSMA network talking to the zeroth device + // on the hub node. The next nFill nodes are on the CSMA network talking to + // the first device on the hub node, etc. So the ith fillNode is associated + // with the hub address found on the (i / nFill)th device on the hub node. + // + ApplicationContainer fillApps; + + for (uint32_t i = 0; i < fillNodes.GetN (); ++i) + { + AddressValue remoteAddress (InetSocketAddress (hubAddresses.GetAddress (i / nFill), port)); + onOffHelper.SetAttribute ("Remote", remoteAddress); + fillApps.Add (onOffHelper.Install (fillNodes.Get (i))); + } + + fillApps.Start (Seconds (1.0)); + fillApps.Stop (Seconds (10.0)); + + NS_LOG_INFO ("Enable static global routing."); + // + // Turn on global static routing so we can actually be routed across the star. + // + GlobalRouteManager::PopulateRoutingTables (); + + NS_LOG_INFO ("Enable pcap tracing."); + // + // Do pcap tracing on all devices on all nodes. + // + PointToPointHelper::EnablePcapAll ("csma-star"); + + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); + + return 0; +} diff --git a/examples/first.cc b/examples/first.cc new file mode 100644 index 000000000..0461d4cc9 --- /dev/null +++ b/examples/first.cc @@ -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/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); + + int +main (int argc, char *argv[]) +{ + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); + + NodeContainer nodes; + nodes.Create (2); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); + + InternetStackHelper stack; + stack.Install (nodes); + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); + + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (nodes.Get (1)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + + UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (nodes.Get (0)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/tutorial/hello-simulator.cc b/examples/hello-simulator.cc similarity index 85% rename from tutorial/hello-simulator.cc rename to examples/hello-simulator.cc index 691098071..37f99ccd5 100644 --- a/tutorial/hello-simulator.cc +++ b/examples/hello-simulator.cc @@ -20,11 +20,8 @@ NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); using namespace ns3; -int + int main (int argc, char *argv[]) { - // LogComponentEnable ("HelloSimulator", - // LogLevel (LOG_LEVEL_INFO | LOG_PREFIX_ALL)); - - NS_LOG_INFO ("Hello Simulator"); + NS_LOG_UNCOND ("Hello Simulator"); } diff --git a/examples/mixed-global-routing.cc b/examples/mixed-global-routing.cc index dfa262414..18141a7d1 100644 --- a/examples/mixed-global-routing.cc +++ b/examples/mixed-global-routing.cc @@ -71,20 +71,20 @@ main (int argc, char *argv[]) // We create the channels first without any IP addressing information NS_LOG_INFO ("Create channels."); PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps")); - p2p.SetChannelParameter ("Delay", StringValue ("2ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("2ms")); NetDeviceContainer d0d2 = p2p.Install (n0n2); NetDeviceContainer d1d2 = p2p.Install (n1n2); - p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps")); - p2p.SetChannelParameter ("Delay", StringValue ("10ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("1500kbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("10ms")); NetDeviceContainer d5d6 = p2p.Install (n5n6); // We create the channels first without any IP addressing information CsmaHelper csma; - csma.SetChannelParameter ("DataRate", StringValue ("5Mbps")); - csma.SetChannelParameter ("Delay", StringValue ("2ms")); + csma.SetChannelAttribute ("DataRate", StringValue ("5Mbps")); + csma.SetChannelAttribute ("Delay", StringValue ("2ms")); NetDeviceContainer d2345 = csma.Install (n2345); // Later, we add IP addresses. diff --git a/examples/mixed-wireless.cc b/examples/mixed-wireless.cc index ae7b89dd5..3b1be7a05 100644 --- a/examples/mixed-wireless.cc +++ b/examples/mixed-wireless.cc @@ -116,9 +116,6 @@ main (int argc, char *argv[]) // cmd.Parse (argc, argv); - // The metadata system (off by default) is used by ascii tracing below - Packet::EnableMetadata (); - /////////////////////////////////////////////////////////////////////////// // // // Construct the backbone // @@ -199,9 +196,9 @@ main (int argc, char *argv[]) // collection. // CsmaHelper csma; - csma.SetChannelParameter ("DataRate", + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate (5000000))); - csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); NetDeviceContainer lanDevices = csma.Install (lan); // // Add the IPv4 protocol stack to the new LAN nodes diff --git a/examples/mixed-wireless.py b/examples/mixed-wireless.py new file mode 100644 index 000000000..ad677c78a --- /dev/null +++ b/examples/mixed-wireless.py @@ -0,0 +1,338 @@ +# /* +# * 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 ns-3 example demonstrates the use of helper functions to ease +# the construction of simulation scenarios. +# +# The simulation topology consists of a mixed wired and wireless +# scenario in which a hierarchical mobility model is used. +# +# The simulation layout consists of N backbone routers interconnected +# by an ad hoc wifi network. +# Each backbone router also has a local 802.11 network and is connected +# to a local LAN. An additional set of(K-1) nodes are connected to +# this backbone. Finally, a local LAN is connected to each router +# on the backbone, with L-1 additional hosts. +# +# The nodes are populated with TCP/IP stacks, and OLSR unicast routing +# on the backbone. An example UDP transfer is shown. The simulator +# be configured to output tcpdumps or traces from different nodes. +# +# +# +--------------------------------------------------------+ +# | | +# | 802.11 ad hoc, ns-2 mobility | +# | | +# +--------------------------------------------------------+ +# | o o o(N backbone routers) | +# +--------+ +--------+ +# wired LAN | mobile | wired LAN | mobile | +# -----------| router | -----------| router | +# --------- --------- +# | | +# +----------------+ +----------------+ +# | 802.11 | | 802.11 | +# | net | | net | +# | K-1 hosts | | K-1 hosts | +# +----------------+ +----------------+ +# + +import ns3 + +# # +# # This function will be used below as a trace sink +# # +# static void +# CourseChangeCallback(std.string path, Ptr model) +# { +# Vector position = model.GetPosition(); +# std.cout << "CourseChange " << path << " x=" << position.x << ", y=" << position.y << ", z=" << position.z << std.endl; +# } + +def main(argv): + # + # First, we declare and initialize a few local variables that control some + # simulation parameters. + # + backboneNodes = 10 + infraNodes = 5 + lanNodes = 5 + stopTime = 10 + + # + # Simulation defaults are typically set next, before command line + # arguments are parsed. + # + ns3.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns3.StringValue("210")) + ns3.Config.SetDefault("ns3::OnOffApplication::DataRate", ns3.StringValue("448kb/s")) + + # + # For convenience, we add the local variables to the command line argument + # system so that they can be overridden with flags such as + # "--backboneNodes=20" + # + cmd = ns3.CommandLine() + #cmd.AddValue("backboneNodes", "number of backbone nodes", backboneNodes) + #cmd.AddValue("infraNodes", "number of leaf nodes", infraNodes) + #cmd.AddValue("lanNodes", "number of LAN nodes", lanNodes) + #cmd.AddValue("stopTime", "simulation stop time(seconds)", stopTime) + + # + # The system global variables and the local values added to the argument + # system can be overridden by command line arguments by using this call. + # + cmd.Parse(argv) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + # # + # Construct the backbone # + # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + + # + # Create a container to manage the nodes of the adhoc(backbone) network. + # Later we'll create the rest of the nodes we'll need. + # + backbone = ns3.NodeContainer() + backbone.Create(backboneNodes) + # + # Create the backbone wifi net devices and install them into the nodes in + # our container + # + wifi = ns3.WifiHelper() + wifi.SetMac("ns3::AdhocWifiMac") + wifi.SetPhy("ns3::WifiPhy") + backboneDevices = wifi.Install(backbone) + # + # Add the IPv4 protocol stack to the nodes in our container + # + internet = ns3.InternetStackHelper() + internet.Install(backbone) + # + # Assign IPv4 addresses to the device drivers(actually to the associated + # IPv4 interfaces) we just created. + # + ipAddrs = ns3.Ipv4AddressHelper() + ipAddrs.SetBase(ns3.Ipv4Address("192.168.0.0"), ns3.Ipv4Mask("255.255.255.0")) + ipAddrs.Assign(backboneDevices) + + # + # The ad-hoc network nodes need a mobility model so we aggregate one to + # each of the nodes we just finished building. + # + mobility = ns3.MobilityHelper() + positionAlloc = ns3.ListPositionAllocator() + x = 0.0 + for i in range(backboneNodes): + positionAlloc.Add(ns3.Vector(x, 0.0, 0.0)) + x += 5.0 + mobility.SetPositionAllocator(positionAlloc) + mobility.SetMobilityModel("ns3::RandomDirection2dMobilityModel", + "Bounds", ns3.RectangleValue(ns3.Rectangle(0, 1000, 0, 1000)), + "Speed", ns3.RandomVariableValue(ns3.ConstantVariable(2000)), + "Pause", ns3.RandomVariableValue(ns3.ConstantVariable(0.2))) + mobility.Install(backbone) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + # # + # Construct the LANs # + # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + + # Reset the address base-- all of the CSMA networks will be in + # the "172.16 address space + ipAddrs.SetBase(ns3.Ipv4Address("172.16.0.0"), ns3.Ipv4Mask("255.255.255.0")) + + for i in range(backboneNodes): + print "Configuring local area network for backbone node ", i + # + # Create a container to manage the nodes of the LAN. We need + # two containers here; one with all of the new nodes, and one + # with all of the nodes including new and existing nodes + # + newLanNodes = ns3.NodeContainer() + newLanNodes.Create(lanNodes - 1) + # Now, create the container with all nodes on this link + lan = ns3.NodeContainer(ns3.NodeContainer(backbone.Get(i)), newLanNodes) + # + # Create the CSMA net devices and install them into the nodes in our + # collection. + # + csma = ns3.CsmaHelper() + csma.SetChannelAttribute("DataRate", ns3.DataRateValue(ns3.DataRate(5000000))) + csma.SetChannelAttribute("Delay", ns3.TimeValue(ns3.MilliSeconds(2))) + lanDevices = csma.Install(lan) + # + # Add the IPv4 protocol stack to the new LAN nodes + # + internet.Install(newLanNodes) + # + # Assign IPv4 addresses to the device drivers(actually to the + # associated IPv4 interfaces) we just created. + # + ipAddrs.Assign(lanDevices) + # + # Assign a new network prefix for the next LAN, according to the + # network mask initialized above + # + ipAddrs.NewNetwork() + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + # # + # Construct the mobile networks # + # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + + # Reset the address base-- all of the 802.11 networks will be in + # the "10.0" address space + ipAddrs.SetBase(ns3.Ipv4Address("10.0.0.0"), ns3.Ipv4Mask("255.255.255.0")) + + for i in range(backboneNodes): + print "Configuring wireless network for backbone node ", i + # + # Create a container to manage the nodes of the LAN. We need + # two containers here; one with all of the new nodes, and one + # with all of the nodes including new and existing nodes + # + newInfraNodes = ns3.NodeContainer() + newInfraNodes.Create(infraNodes - 1) + # Now, create the container with all nodes on this link + infra = ns3.NodeContainer(ns3.NodeContainer(backbone.Get(i)), newInfraNodes) + # + # Create another ad hoc network and devices + # + wifiInfra = ns3.WifiHelper() + wifiInfra.SetMac("ns3::AdhocWifiMac") + wifiInfra.SetPhy("ns3::WifiPhy") + infraDevices = wifiInfra.Install(infra) + + # Add the IPv4 protocol stack to the nodes in our container + # + internet.Install(newInfraNodes) + # + # Assign IPv4 addresses to the device drivers(actually to the associated + # IPv4 interfaces) we just created. + # + ipAddrs.Assign(infraDevices) + # + # Assign a new network prefix for each mobile network, according to + # the network mask initialized above + # + ipAddrs.NewNetwork() + # + # The new wireless nodes need a mobility model so we aggregate one + # to each of the nodes we just finished building. + # + subnetAlloc = ns3.ListPositionAllocator() + for j in range(infra.GetN()): + subnetAlloc.Add(ns3.Vector(0.0, j, 0.0)) + + mobility.PushReferenceMobilityModel(backbone.Get(i)) + mobility.SetPositionAllocator(subnetAlloc) + mobility.SetMobilityModel("ns3::RandomDirection2dMobilityModel", + "Bounds", ns3.RectangleValue(ns3.Rectangle(-25, 25, -25, 25)), + "Speed", ns3.RandomVariableValue(ns3.ConstantVariable(30)), + "Pause", ns3.RandomVariableValue(ns3.ConstantVariable(0.4))) + mobility.Install(infra) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + # # + # Routing configuration # + # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + + print "Enabling OLSR routing on all backbone nodes" + olsr = ns3.OlsrHelper() + olsr.Install(backbone) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + # # + # Application configuration # + # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + + # Create the OnOff application to send UDP datagrams of size + # 210 bytes at a rate of 448 Kb/s, between two nodes + print "Create Applications." + port = 9 # Discard port(RFC 863) + + # Let's make sure that the user does not define too few LAN nodes + # to make this example work. We need lanNodes >= 5 + assert (lanNodes >= 5) + appSource = ns3.NodeList.GetNode(11) + appSink = ns3.NodeList.GetNode(13) + remoteAddr = ns3.Ipv4Address("172.16.0.5") + + onoff = ns3.OnOffHelper("ns3::UdpSocketFactory", + ns3.Address(ns3.InetSocketAddress(remoteAddr, port))) + onoff.SetAttribute("OnTime", ns3.RandomVariableValue(ns3.ConstantVariable(1))) + onoff.SetAttribute("OffTime", ns3.RandomVariableValue(ns3.ConstantVariable(0))) + apps = onoff.Install(ns3.NodeContainer(appSource)) + apps.Start(ns3.Seconds(3.0)) + apps.Stop(ns3.Seconds(20.0)) + + # Create a packet sink to receive these packets + sink = ns3.PacketSinkHelper("ns3::UdpSocketFactory", + ns3.InetSocketAddress(ns3.Ipv4Address.GetAny(), port)) + apps = sink.Install(ns3.NodeContainer(appSink)) + apps.Start(ns3.Seconds(3.0)) + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + # # + # Tracing configuration # + # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / + + print "Configure Tracing." + # + # Let's set up some ns-2-like ascii traces, using another helper class + # + #std.ofstream ascii + #ascii.open("mixed-wireless.tr") + #WifiHelper.EnableAsciiAll(ascii) + #CsmaHelper.EnableAsciiAll(ascii) + print "(tracing not done for Python)" + # Look at nodes 11, 13 only + # WifiHelper.EnableAscii(ascii, 11, 0); + # WifiHelper.EnableAscii(ascii, 13, 0); + + # Let's do a pcap trace on the backbone devices + ns3.WifiHelper.EnablePcap("mixed-wireless", backboneDevices) + # Let's additionally trace the application Sink, ifIndex 0 + ns3.CsmaHelper.EnablePcap("mixed-wireless", appSink.GetId(), 0) + +# #ifdef ENABLE_FOR_TRACING_EXAMPLE +# Config.Connect("/NodeList/*/$MobilityModel/CourseChange", +# MakeCallback(&CourseChangeCallback)) +# #endif + + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # # + # Run simulation # + # # + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + print "Run Simulation." + ns3.Simulator.Stop(ns3.Seconds(stopTime)) + ns3.Simulator.Run() + ns3.Simulator.Destroy() + + +if __name__ == '__main__': + import sys + main(sys.argv) diff --git a/examples/realtime-udp-echo.cc b/examples/realtime-udp-echo.cc new file mode 100644 index 000000000..7018f4b36 --- /dev/null +++ b/examples/realtime-udp-echo.cc @@ -0,0 +1,125 @@ +/* -*- 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 + */ + +// Network topology +// +// n0 n1 n2 n3 +// | | | | +// ================= +// LAN +// +// - UDP flows from n0 to n1 and back +// - DropTail queues +// - Tracing of queues and packet receptions to file "udp-echo.tr" + +#include +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/helper-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("RealtimeUdpEchoExample"); + +int +main (int argc, char *argv[]) +{ + // + // Make the random number generators generate reproducible results. + // + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + // + // Allow the user to override any of the defaults and the above Bind() at + // run-time, via command-line arguments + // + CommandLine cmd; + cmd.Parse (argc, argv); + + // + // But since this is a realtime script, don't allow the user to mess with + // that. + // + GlobalValue::Bind ("SimulatorImplementationType", + StringValue ("ns3::RealtimeSimulatorImpl")); + + // + // Explicitly create the nodes required by the topology (shown above). + // + NS_LOG_INFO ("Create nodes."); + NodeContainer n; + n.Create (4); + + InternetStackHelper internet; + internet.Install (n); + + // + // Explicitly create the channels required by the topology (shown above). + // + NS_LOG_INFO ("Create channels."); + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + csma.SetDeviceAttribute ("Mtu", UintegerValue (1400)); + NetDeviceContainer d = csma.Install (n); + + // + // We've got the "hardware" in place. Now we need to add IP addresses. + // + NS_LOG_INFO ("Assign IP Addresses."); + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer i = ipv4.Assign (d); + + NS_LOG_INFO ("Create Applications."); + + // + // Create a UdpEchoServer application on node one. + // + uint16_t port = 9; // well-known echo port number + UdpEchoServerHelper server (port); + ApplicationContainer apps = server.Install (n.Get(1)); + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (10.0)); + + // + // Create a UdpEchoClient application to send UDP datagrams from node zero to + // node one. + // + uint32_t packetSize = 1024; + uint32_t maxPacketCount = 500; + Time interPacketInterval = Seconds (0.01); + UdpEchoClientHelper client (i.GetAddress (1), port); + client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + client.SetAttribute ("Interval", TimeValue (interPacketInterval)); + client.SetAttribute ("PacketSize", UintegerValue (packetSize)); + apps = client.Install (n.Get (0)); + apps.Start (Seconds (2.0)); + apps.Stop (Seconds (10.0)); + + std::ofstream ascii; + ascii.open ("realtime-udp-echo.tr"); + CsmaHelper::EnablePcapAll ("realtime-udp-echo"); + CsmaHelper::EnableAsciiAll (ascii); + + // + // Now, do the actual simulation. + // + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +} diff --git a/examples/second.cc b/examples/second.cc new file mode 100644 index 000000000..a54205f58 --- /dev/null +++ b/examples/second.cc @@ -0,0 +1,102 @@ +/* -*- 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/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/global-routing-module.h" + +// Default Network Topology +// +// 10.1.1.0 +// n0 -------------- n1 n2 n3 n4 +// point-to-point | | | | +// ================ +// LAN 10.1.2.0 + + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("SecondScriptExample"); + +int +main (int argc, char *argv[]) +{ + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); + + uint32_t nCsma = 3; + CommandLine cmd; + cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); + cmd.Parse (argc,argv); + + NodeContainer p2pNodes; + p2pNodes.Create (2); + + NodeContainer csmaNodes; + csmaNodes.Add (p2pNodes.Get (1)); + csmaNodes.Create (nCsma); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (p2pNodes); + + CsmaHelper csma; + + NetDeviceContainer csmaDevices; + csmaDevices = csma.Install (csmaNodes); + + InternetStackHelper stack; + stack.Install (p2pNodes.Get (0)); + stack.Install (csmaNodes); + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + + address.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4InterfaceContainer csmaInterfaces; + csmaInterfaces = address.Assign (csmaDevices); + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + + UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + + GlobalRouteManager::PopulateRoutingTables (); + + PointToPointHelper::EnablePcapAll ("second"); + CsmaHelper::EnablePcapAll ("second"); + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/examples/simple-alternate-routing.cc b/examples/simple-alternate-routing.cc index 2d130e7f0..e8360e7ef 100644 --- a/examples/simple-alternate-routing.cc +++ b/examples/simple-alternate-routing.cc @@ -97,17 +97,17 @@ main (int argc, char *argv[]) // We create the channels first without any IP addressing information NS_LOG_INFO ("Create channels."); PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps")); - p2p.SetChannelParameter ("Delay", StringValue ("2ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("2ms")); NetDeviceContainer d0d2 = p2p.Install (n0n2); NetDeviceContainer d1d2 = p2p.Install (n1n2); - p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps")); - p2p.SetChannelParameter ("Delay", StringValue ("10ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("1500kbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("10ms")); NetDeviceContainer d3d2 = p2p.Install (n3n2); - p2p.SetChannelParameter ("Delay", StringValue ("100ms")); + p2p.SetChannelAttribute ("Delay", StringValue ("100ms")); NetDeviceContainer d1d3 = p2p.Install (n1n3); InternetStackHelper internet; @@ -148,7 +148,7 @@ main (int argc, char *argv[]) ApplicationContainer apps = onoff.Install (c.Get (3)); apps.Start (Seconds (1.1)); - apps.Start (Seconds (10.0)); + apps.Stop (Seconds (10.0)); // Create a packet sink to receive these packets PacketSinkHelper sink ("ns3::UdpSocketFactory", diff --git a/examples/simple-error-model.cc b/examples/simple-error-model.cc index 71d022200..10a48c05b 100644 --- a/examples/simple-error-model.cc +++ b/examples/simple-error-model.cc @@ -64,7 +64,7 @@ main (int argc, char *argv[]) // RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); - // Set a few parameters + // Set a few attributes Config::SetDefault ("ns3::RateErrorModel::ErrorRate", DoubleValue (0.01)); Config::SetDefault ("ns3::RateErrorModel::ErrorUnit", StringValue ("EU_PKT")); @@ -92,14 +92,14 @@ main (int argc, char *argv[]) // We create the channels first without any IP addressing information NS_LOG_INFO ("Create channels."); PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate (5000000))); - p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2))); + p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (5000000))); + p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); NetDeviceContainer d0d2 = p2p.Install (n0n2); NetDeviceContainer d1d2 = p2p.Install (n1n2); - p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate (1500000))); - p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds (10))); + p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (1500000))); + p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (10))); NetDeviceContainer d3d2 = p2p.Install (n3n2); // Later, we add IP addresses. @@ -134,7 +134,7 @@ main (int argc, char *argv[]) // Create an optional packet sink to receive these packets PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny (), port))); - apps = sink.Install (c.Get (3)); + apps = sink.Install (c.Get (2)); apps.Start (Seconds (1.0)); apps.Stop (Seconds (10.0)); diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index 35fb96d94..a0ddb0d7a 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -92,14 +92,14 @@ main (int argc, char *argv[]) // We create the channels first without any IP addressing information NS_LOG_INFO ("Create channels."); PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps")); - p2p.SetChannelParameter ("Delay", StringValue ("2ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("2ms")); NetDeviceContainer d0d2 = p2p.Install (n0n2); NetDeviceContainer d1d2 = p2p.Install (n1n2); - p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps")); - p2p.SetChannelParameter ("Delay", StringValue ("10ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("1500kbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("10ms")); NetDeviceContainer d3d2 = p2p.Install (n3n2); // Later, we add IP addresses. diff --git a/examples/simple-point-to-point-olsr.cc b/examples/simple-point-to-point-olsr.cc index e11816bff..5079706ed 100644 --- a/examples/simple-point-to-point-olsr.cc +++ b/examples/simple-point-to-point-olsr.cc @@ -93,12 +93,12 @@ main (int argc, char *argv[]) // We create the channels first without any IP addressing information NS_LOG_INFO ("Create channels."); PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps")); - p2p.SetChannelParameter ("Delay", StringValue ("2ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("2ms")); NetDeviceContainer nd02 = p2p.Install (n02); NetDeviceContainer nd12 = p2p.Install (n12); - p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps")); - p2p.SetChannelParameter ("Delay", StringValue ("10ms")); + p2p.SetDeviceAttribute ("DataRate", StringValue ("1500kbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("10ms")); NetDeviceContainer nd32 = p2p.Install (n32); NetDeviceContainer nd34 = p2p.Install (n34); diff --git a/examples/star.cc b/examples/star.cc new file mode 100644 index 000000000..1cc58457d --- /dev/null +++ b/examples/star.cc @@ -0,0 +1,153 @@ +/* -*- 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/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/global-route-manager.h" + +// Network topology (default) +// +// n2 n3 n4 . +// \ | / . +// \|/ . +// n1--- n0---n5 . +// /|\ . +// / | \ . +// n8 n7 n6 . +// + + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("Star"); + +int +main (int argc, char *argv[]) +{ + // + // Make the random number generators generate reproducible results. + // + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + // + // Set up some default values for the simulation. + // + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (137)); + + // ??? try and stick 15kb/s into the data rate + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("14kb/s")); + + // + // Default number of nodes in the star. Overridable by command line argument. + // + uint32_t nNodes = 9; + + CommandLine cmd; + cmd.AddValue("nNodes", "Number of nodes to place in the star", nNodes); + cmd.Parse (argc, argv); + + NS_LOG_INFO ("Create nodes."); + NodeContainer hubNode; + NodeContainer spokeNodes; + hubNode.Create (1); + Ptr hub = hubNode.Get (0); + spokeNodes.Create (nNodes - 1); + + NS_LOG_INFO ("Install internet stack on all nodes."); + InternetStackHelper internet; + internet.Install (NodeContainer (hubNode, spokeNodes)); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NS_LOG_INFO ("Build star topology."); + NetDeviceContainer hubDevices, spokeDevices; + pointToPoint.InstallStar (hubNode.Get (0), spokeNodes, hubDevices, spokeDevices); + + NS_LOG_INFO ("Assign IP Addresses."); + Ipv4AddressHelper address; + + // + // Assign IPv4 interfaces and IP addresses to the devices we previously + // created. Keep track of the resulting addresses, one for the addresses + // of the hub node, and one for addresses on the spoke nodes. Despite the + // name of the class, what is visible to clients is really the address. + // + Ipv4InterfaceContainer hubAddresses; + Ipv4InterfaceContainer spokeAddresses; + + for(uint32_t i = 0; i < spokeNodes.GetN (); ++i) + { + std::ostringstream subnet; + subnet << "10.1.1." << (i << 2); + NS_LOG_INFO ("Assign IP Addresses for point-to-point subnet " << subnet.str ()); + address.SetBase (subnet.str ().c_str (), "255.255.255.252"); + hubAddresses.Add (address.Assign (hubDevices.Get (i))); + spokeAddresses.Add (address.Assign (spokeDevices.Get (i))); + } + + NS_LOG_INFO ("Create applications."); + // + // Create a packet sink on the star "hub" to receive packets. + // + uint16_t port = 50000; + Address hubLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), port)); + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", hubLocalAddress); + ApplicationContainer hubApp = packetSinkHelper.Install (hubNode); + hubApp.Start (Seconds (1.0)); + hubApp.Stop (Seconds (10.0)); + + // + // Create OnOff applications to send TCP to the hub, one on each spoke node. + // + OnOffHelper onOffHelper ("ns3::TcpSocketFactory", Address ()); + onOffHelper.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + onOffHelper.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + + ApplicationContainer spokeApps; + + for (uint32_t i = 0; i < spokeNodes.GetN (); ++i) + { + AddressValue remoteAddress (InetSocketAddress (hubAddresses.GetAddress (i), port)); + onOffHelper.SetAttribute ("Remote", remoteAddress); + spokeApps.Add (onOffHelper.Install (spokeNodes.Get (i))); + } + spokeApps.Start (Seconds (1.0)); + spokeApps.Stop (Seconds (10.0)); + + NS_LOG_INFO ("Enable static global routing."); + // + // Turn on global static routing so we can actually be routed across the star. + // + GlobalRouteManager::PopulateRoutingTables (); + + NS_LOG_INFO ("Enable pcap tracing."); + // + // Do pcap tracing on all devices on all nodes. + // + PointToPointHelper::EnablePcapAll ("star"); + + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); + + return 0; +} diff --git a/examples/stats/README b/examples/stats/README new file mode 100644 index 000000000..e4a98209c --- /dev/null +++ b/examples/stats/README @@ -0,0 +1,16 @@ + + ns-3 stats example + +The example script wifi-example-db.sh in this directly will run +through the entire process of running a simple experiment. It assumes +sqlite3 is installed as it uses the sqlite3 data output format of the +statistics package. It also assumes it is being run from the +examples/stats/ subdirectory of the ns-3 package, together with its +gnuplot script. When the script completes successfully, a graph will +be have been produced in examples/stats/wifi-default.eps demonstrating +output from this example. + +More information on the statistics package and this example is +available online on the ns-3 wiki at: + +http://www.nsnam.org/wiki/index.php/Statistical_Framework_for_Network_Simulation diff --git a/examples/stats/wifi-example-apps.cc b/examples/stats/wifi-example-apps.cc new file mode 100644 index 000000000..d7eb63767 --- /dev/null +++ b/examples/stats/wifi-example-apps.cc @@ -0,0 +1,330 @@ +/* -*- 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 + * + * Authors: Joe Kopena + * + * These applications are used in the WiFi Distance Test experiment, + * described and implemented in test02.cc. That file should be in the + * same place as this file. The applications have two very simple + * jobs, they just generate and receive packets. We could use the + * standard Application classes included in the NS-3 distribution. + * These have been written just to change the behavior a little, and + * provide more examples. + * + */ + +#include + +#include "ns3/core-module.h" +#include "ns3/common-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/internet-stack-module.h" + +#include "ns3/stats-module.h" + +#include "wifi-example-apps.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("WiFiDistanceApps"); + +TypeId +Sender::GetTypeId(void) +{ + static TypeId tid = TypeId ("Sender") + .SetParent () + .AddConstructor () + .AddAttribute ("PacketSize", "The size of packets transmitted.", + UintegerValue(64), + MakeUintegerAccessor(&Sender::m_pktSize), + MakeUintegerChecker(1)) + .AddAttribute("Destination", "Target host address.", + Ipv4AddressValue("255.255.255.255"), + MakeIpv4AddressAccessor(&Sender::m_destAddr), + MakeIpv4AddressChecker()) + .AddAttribute("Port", "Destination app port.", + UintegerValue(1603), + MakeUintegerAccessor(&Sender::m_destPort), + MakeUintegerChecker()) + .AddAttribute("NumPackets", "Total number of packets to send.", + UintegerValue(30), + MakeUintegerAccessor(&Sender::m_numPkts), + MakeUintegerChecker(1)) + .AddAttribute ("Interval", "Delay between transmissions.", + RandomVariableValue(ConstantVariable(0.5)), + MakeRandomVariableAccessor(&Sender::m_interval), + MakeRandomVariableChecker()) + .AddTraceSource ("Tx", "A new packet is created and is sent", + MakeTraceSourceAccessor (&Sender::m_txTrace)) + ; + return tid; +} + + +Sender::Sender() +{ + NS_LOG_FUNCTION_NOARGS (); + m_socket = 0; +} + +Sender::~Sender() +{ + NS_LOG_FUNCTION_NOARGS (); +} + +void +Sender::DoDispose (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + m_socket = 0; + // chain up + Application::DoDispose (); +} + +void Sender::StartApplication() +{ + NS_LOG_FUNCTION_NOARGS (); + + if (m_socket == 0) { + Ptr socketFactory = GetNode()->GetObject + (UdpSocketFactory::GetTypeId()); + m_socket = socketFactory->CreateSocket (); + m_socket->Bind (); + } + + m_count = 0; + + Simulator::Cancel(m_sendEvent); + m_sendEvent = Simulator::ScheduleNow(&Sender::SendPacket, this); + + // end Sender::StartApplication +} + +void Sender::StopApplication() +{ + NS_LOG_FUNCTION_NOARGS (); + Simulator::Cancel(m_sendEvent); + // end Sender::StopApplication +} + +void Sender::SendPacket() +{ + // NS_LOG_FUNCTION_NOARGS (); + NS_LOG_INFO("Sending packet at " << Simulator::Now() << " to " << + m_destAddr); + + Ptr packet = Create(m_pktSize); + + TimestampTag timestamp; + timestamp.SetTimestamp(Simulator::Now()); + packet->AddTag(timestamp); + + // Could connect the socket since the address never changes; using SendTo + // here simply because all of the standard apps do not. + m_socket->SendTo(packet, 0, InetSocketAddress(m_destAddr, m_destPort)); + + // Report the event to the trace. + m_txTrace(packet); + + if (++m_count < m_numPkts) { + m_sendEvent = Simulator::Schedule(Seconds(m_interval.GetValue()), + &Sender::SendPacket, this); + } + + // end Sender::SendPacket +} + + + + +//---------------------------------------------------------------------- +//-- Receiver +//------------------------------------------------------ +TypeId +Receiver::GetTypeId(void) +{ + static TypeId tid = TypeId ("Receiver") + .SetParent () + .AddConstructor () + .AddAttribute("Port", "Listening port.", + UintegerValue(1603), + MakeUintegerAccessor(&Receiver::m_port), + MakeUintegerChecker()) + ; + return tid; +} + +Receiver::Receiver() : + m_calc(0), + m_delay(0) +{ + NS_LOG_FUNCTION_NOARGS (); + m_socket = 0; +} + +Receiver::~Receiver() +{ + NS_LOG_FUNCTION_NOARGS (); +} + +void +Receiver::DoDispose (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + m_socket = 0; + // chain up + Application::DoDispose (); +} + +void +Receiver::StartApplication() +{ + NS_LOG_FUNCTION_NOARGS (); + + if (m_socket == 0) { + Ptr socketFactory = GetNode()->GetObject + (UdpSocketFactory::GetTypeId()); + m_socket = socketFactory->CreateSocket(); + InetSocketAddress local = + InetSocketAddress(Ipv4Address::GetAny(), m_port); + m_socket->Bind(local); + } + + m_socket->SetRecvCallback(MakeCallback(&Receiver::Receive, this)); + + // end Receiver::StartApplication +} + +void +Receiver::StopApplication() +{ + NS_LOG_FUNCTION_NOARGS (); + + if (m_socket != 0) { + m_socket->SetRecvCallback(MakeNullCallback > ()); + } + + // end Receiver::StopApplication +} + +void +Receiver::SetCounter(Ptr > calc) +{ + m_calc = calc; + // end Receiver::SetCounter +} +void +Receiver::SetDelayTracker(Ptr delay) +{ + m_delay = delay; + // end Receiver::SetDelayTracker +} + +void +Receiver::Receive(Ptr socket) +{ + // NS_LOG_FUNCTION (this << socket << packet << from); + + Ptr packet; + Address from; + while (packet = socket->RecvFrom(from)) { + if (InetSocketAddress::IsMatchingType (from)) { + InetSocketAddress address = InetSocketAddress::ConvertFrom (from); + NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << + address.GetIpv4()); + } + + TimestampTag timestamp; + packet->FindFirstMatchingTag(timestamp); + Time tx = timestamp.GetTimestamp(); + + if (m_delay != 0) { + m_delay->Update(Simulator::Now() - tx); + } + + if (m_calc != 0) { + m_calc->Update(); + } + + // end receiving packets + } + + // end Receiver::Receive +} + + + + +//---------------------------------------------------------------------- +//-- TimestampTag +//------------------------------------------------------ +TypeId +TimestampTag::GetTypeId(void) +{ + static TypeId tid = TypeId ("TimestampTag") + .SetParent () + .AddConstructor () + .AddAttribute ("Timestamp", + "Some momentous point in time!", + EmptyAttributeValue(), + MakeTimeAccessor(&TimestampTag::GetTimestamp), + MakeTimeChecker()) + ; + return tid; +} +TypeId +TimestampTag::GetInstanceTypeId(void) const +{ + return GetTypeId (); +} + +uint32_t +TimestampTag::GetSerializedSize (void) const +{ + return 8; +} +void +TimestampTag::Serialize (TagBuffer i) const +{ + int64_t t = m_timestamp.GetNanoSeconds(); + i.Write((const uint8_t *)&t, 8); +} +void +TimestampTag::Deserialize (TagBuffer i) +{ + int64_t t; + i.Read((uint8_t *)&t, 8); + m_timestamp = NanoSeconds(t); +} + +void +TimestampTag::SetTimestamp(Time time) +{ + m_timestamp = time; +} +Time +TimestampTag::GetTimestamp(void) const +{ + return m_timestamp; +} + +void +TimestampTag::Print(std::ostream &os) const +{ + os << "t=" << m_timestamp; +} diff --git a/examples/stats/wifi-example-apps.h b/examples/stats/wifi-example-apps.h new file mode 100644 index 000000000..afde4fd34 --- /dev/null +++ b/examples/stats/wifi-example-apps.h @@ -0,0 +1,126 @@ +/* -*- 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 + * + * Authors: Joe Kopena + * + * These applications are used in the WiFi Distance Test experiment, + * described and implemented in test02.cc. That file should be in the + * same place as this file. The applications have two very simple + * jobs, they just generate and receive packets. We could use the + * standard Application classes included in the NS-3 distribution. + * These have been written just to change the behavior a little, and + * provide more examples. + * + */ + +// #define NS3_LOG_ENABLE // Now defined by Makefile + +#include "ns3/core-module.h" +#include "ns3/common-module.h" +#include "ns3/application.h" + +#include "ns3/stats-module.h" + +using namespace ns3; + +//---------------------------------------------------------------------- +//------------------------------------------------------ +class Sender: public Application { +public: + static TypeId GetTypeId(void); + Sender(); + virtual ~Sender(); + +protected: + virtual void DoDispose(void); + +private: + virtual void StartApplication(void); + virtual void StopApplication(void); + + void SendPacket(); + + uint32_t m_pktSize; + Ipv4Address m_destAddr; + uint32_t m_destPort; + RandomVariable m_interval; + uint32_t m_numPkts; + + Ptr m_socket; + EventId m_sendEvent; + + TracedCallback > m_txTrace; + + uint32_t m_count; + + // end class Sender +}; + + + + +//------------------------------------------------------ +class Receiver: public Application { +public: + static TypeId GetTypeId(void); + Receiver(); + virtual ~Receiver(); + + void SetCounter(Ptr > calc); + void SetDelayTracker(Ptr delay); + +protected: + virtual void DoDispose(void); + +private: + virtual void StartApplication(void); + virtual void StopApplication(void); + + void Receive(Ptr socket); + + Ptr m_socket; + + uint32_t m_port; + + Ptr > m_calc; + Ptr m_delay; + + // end class Receiver +}; + + + + +//------------------------------------------------------ +class TimestampTag : public Tag { +public: + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); + + // these are our accessors to our tag structure + void SetTimestamp(Time time); + Time GetTimestamp(void) const; + + void Print(std::ostream &os) const; + +private: + Time m_timestamp; + + // end class TimestampTag +}; diff --git a/examples/stats/wifi-example-db.sh b/examples/stats/wifi-example-db.sh new file mode 100755 index 000000000..ca2bd2c8f --- /dev/null +++ b/examples/stats/wifi-example-db.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +DISTANCES="25 50 75 100 125 145 147 150 152 155 157 160 162 165 167 170 172 175 177 180" +TRIALS="1 2 3 4 5" + +echo WiFi Experiment Example + +pCheck=`which sqlite3` +if [ -z "$pCheck" ] +then + echo "ERROR: This script requires sqlite3 (wifi-example-sim does not)." + exit 255 +fi + +pCheck=`which gnuplot` +if [ -z "$pCheck" ] +then + echo "ERROR: This script requires gnuplot (wifi-example-sim does not)." + exit 255 +fi + +pCheck=`which sed` +if [ -z "$pCheck" ] +then + echo "ERROR: This script requires sed (wifi-example-sim does not)." + exit 255 +fi + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:bin/ + +if [ -e ../../data.db ] +then + echo "Kill data.db? (y/n)" + read ANS + if [ "$ANS" = "yes" -o "$ANS" = "y" ] + then + echo Deleting database + rm ../../data.db + fi +fi + +for trial in $TRIALS +do + for distance in $DISTANCES + do + echo Trial $trial, distance $distance + ../../waf --run "wifi-example-sim --format=db --distance=$distance --run=run-$distance-$trial" + done +done + +# +#Another SQL command which just collects raw numbers of frames receved. +# +#CMD="select Experiments.input,avg(Singletons.value) \ +# from Singletons,Experiments \ +# where Singletons.run = Experiments.run AND \ +# Singletons.name='wifi-rx-frames' \ +# group by Experiments.input \ +# order by abs(Experiments.input) ASC;" + +mv ../../data.db . + +CMD="select exp.input,avg(100-((rx.value*100)/tx.value)) \ + from Singletons rx, Singletons tx, Experiments exp \ + where rx.run = tx.run AND \ + rx.run = exp.run AND \ + rx.name='receiver-rx-packets' AND \ + tx.name='sender-tx-packets' \ + group by exp.input \ + order by abs(exp.input) ASC;" + +sqlite3 -noheader data.db "$CMD" > wifi-default.data +sed -i "s/|/ /" wifi-default.data +gnuplot wifi-example.gnuplot + +echo "Done; data in wifi-default.data, plot in wifi-default.eps" diff --git a/examples/stats/wifi-example-sim.cc b/examples/stats/wifi-example-sim.cc new file mode 100644 index 000000000..07b951ce8 --- /dev/null +++ b/examples/stats/wifi-example-sim.cc @@ -0,0 +1,317 @@ +/* -*- 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 + * + * Authors: Joe Kopena + * + * This program conducts a simple experiment: It places two nodes at a + * parameterized distance apart. One node generates packets and the + * other node receives. The stat framework collects data on packet + * loss. Outside of this program, a control script uses that data to + * produce graphs presenting performance at the varying distances. + * This isn't a typical simulation but is a common "experiment" + * performed in real life and serves as an accessible exemplar for the + * stat framework. It also gives some intuition on the behavior and + * basic reasonability of the NS-3 WiFi models. + * + * Applications used by this program are in test02-apps.h and + * test02-apps.cc, which should be in the same place as this file. + * + */ + +// #define NS3_LOG_ENABLE // Now defined by Makefile + +#include + +#include "ns3/core-module.h" +#include "ns3/common-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/mobility-module.h" +#include "ns3/wifi-module.h" + +#include "ns3/stats-module.h" + +#include "wifi-example-apps.h" + +using namespace ns3; +using namespace std; + +NS_LOG_COMPONENT_DEFINE ("WiFiDistanceExperiment"); + + + + +void TxCallback(Ptr > datac, + std::string path, Ptr packet, + Mac48Address realto) { + NS_LOG_INFO("Sent frame to " << realto << "; counted in " << + datac->GetKey()); + datac->Update(); + // end TxCallback +} + + + + +//---------------------------------------------------------------------- +//-- main +//---------------------------------------------- +int main(int argc, char *argv[]) { + + double distance = 50.0; + string format("omnet"); + + string experiment("wifi-distance-test"); + string strategy("wifi-default"); + string input; + string runID; + + { + stringstream sstr; + sstr << "run-" << time(NULL); + runID = sstr.str(); + } + + // Set up command line parameters used to control the experiment. + CommandLine cmd; + cmd.AddValue("distance", "Distance apart to place nodes (in meters).", + distance); + cmd.AddValue("format", "Format to use for data output.", + format); + cmd.AddValue("experiment", "Identifier for experiment.", + experiment); + cmd.AddValue("strategy", "Identifier for strategy.", + strategy); + cmd.AddValue("run", "Identifier for run.", + runID); + cmd.Parse (argc, argv); + + if (format != "omnet" && format != "db") { + NS_LOG_ERROR("Unknown output format '" << format << "'"); + return -1; + } + + #ifndef STATS_HAS_SQLITE3 + if (format == "db") { + NS_LOG_ERROR("sqlite support not compiled in."); + return -1; + } + #endif + + { + stringstream sstr(""); + sstr << distance; + input = sstr.str(); + } + + + + + //------------------------------------------------------------ + //-- Create nodes and network stacks + //-------------------------------------------- + NS_LOG_INFO("Creating nodes."); + NodeContainer nodes; + nodes.Create(2); + + NS_LOG_INFO("Installing WiFi and Internet stack."); + WifiHelper wifi; + wifi.SetMac("ns3::AdhocWifiMac"); + NetDeviceContainer nodeDevices = wifi.Install(nodes); + + InternetStackHelper internet; + internet.Install(nodes); + Ipv4AddressHelper ipAddrs; + ipAddrs.SetBase("192.168.0.0", "255.255.255.0"); + ipAddrs.Assign(nodeDevices); + + + + + //------------------------------------------------------------ + //-- Setup physical layout + //-------------------------------------------- + NS_LOG_INFO("Installing static mobility; distance " << distance << " ."); + MobilityHelper mobility; + Ptr positionAlloc = + CreateObject(); + positionAlloc->Add(Vector(0.0, 0.0, 0.0)); + positionAlloc->Add(Vector(0.0, distance, 0.0)); + mobility.SetPositionAllocator(positionAlloc); + mobility.Install(nodes); + + + + + //------------------------------------------------------------ + //-- Create a custom traffic source and sink + //-------------------------------------------- + NS_LOG_INFO ("Create traffic source & sink."); + Ptr appSource = NodeList::GetNode(0); + Ptr sender = CreateObject(); + appSource->AddApplication(sender); + sender->Start(Seconds(1)); + + Ptr appSink = NodeList::GetNode(1); + Ptr receiver = CreateObject(); + appSink->AddApplication(receiver); + receiver->Start(Seconds(0)); + + // Config::Set("/NodeList/*/ApplicationList/*/$Sender/Destination", + // Ipv4AddressValue("192.168.0.2")); + + + + + //------------------------------------------------------------ + //-- Setup stats and data collection + //-------------------------------------------- + + // Create a DataCollector object to hold information about this run. + DataCollector data; + data.DescribeRun(experiment, + strategy, + input, + runID); + + // Add any information we wish to record about this run. + data.AddMetadata("author", "tjkopena"); + + + // Create a counter to track how many frames are generated. Updates + // are triggered by the trace signal generated by the WiFi MAC model + // object. Here we connect the counter to the signal via the simple + // TxCallback() glue function defined above. + Ptr > totalTx = + CreateObject >(); + totalTx->SetKey("wifi-tx-frames"); + Config::Connect("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Tx", + MakeBoundCallback(&TxCallback, totalTx)); + data.AddDataCalculator(totalTx); + + // This is similar, but creates a counter to track how many frames + // are received. Instead of our own glue function, this uses a + // method of an adapter class to connect a counter directly to the + // trace signal generated by the WiFi MAC. + Ptr totalRx = + CreateObject(); + totalRx->SetKey("wifi-rx-frames"); + Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Rx", + MakeCallback(&PacketCounterCalculator::FrameUpdate, + totalRx)); + data.AddDataCalculator(totalRx); + + + + + // This counter tracks how many packets---as opposed to frames---are + // generated. This is connected directly to a trace signal provided + // by our Sender class. + Ptr appTx = + CreateObject(); + appTx->SetKey("sender-tx-packets"); + Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx", + MakeCallback(&PacketCounterCalculator::PacketUpdate, + appTx)); + data.AddDataCalculator(appTx); + + // Here a counter for received packets is directly manipulated by + // one of the custom objects in our simulation, the Receiver + // Application. The Receiver object is given a pointer to the + // counter and calls its Update() method whenever a packet arrives. + Ptr > appRx = + CreateObject >(); + appRx->SetKey("receiver-rx-packets"); + receiver->SetCounter(appRx); + data.AddDataCalculator(appRx); + + + + + /** + * Just to show this is here... + Ptr > test = + CreateObject >(); + test->SetKey("test-dc"); + data.AddDataCalculator(test); + + test->Update(4); + test->Update(8); + test->Update(24); + test->Update(12); + **/ + + // This DataCalculator connects directly to the transmit trace + // provided by our Sender Application. It records some basic + // statistics about the sizes of the packets received (min, max, + // avg, total # bytes), although in this scenaro they're fixed. + Ptr appTxPkts = + CreateObject(); + appTxPkts->SetKey("tx-pkt-size"); + Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx", + MakeCallback + (&PacketSizeMinMaxAvgTotalCalculator::PacketUpdate, + appTxPkts)); + data.AddDataCalculator(appTxPkts); + + + // Here we directly manipulate another DataCollector tracking min, + // max, total, and average propagation delays. Check out the Sender + // and Receiver classes to see how packets are tagged with + // timestamps to do this. + Ptr delayStat = + CreateObject(); + delayStat->SetKey("delay"); + receiver->SetDelayTracker(delayStat); + data.AddDataCalculator(delayStat); + + + + + //------------------------------------------------------------ + //-- Run the simulation + //-------------------------------------------- + NS_LOG_INFO("Run Simulation."); + Simulator::Run(); + Simulator::Destroy(); + + + + + //------------------------------------------------------------ + //-- Generate statistics output. + //-------------------------------------------- + + // Pick an output writer based in the requested format. + Ptr output = 0; + if (format == "omnet") { + NS_LOG_INFO("Creating omnet formatted data output."); + output = CreateObject(); + } else if (format == "db") { + #ifdef STATS_HAS_SQLITE3 + NS_LOG_INFO("Creating sqlite formatted data output."); + output = CreateObject(); + #endif + } else { + NS_LOG_ERROR("Unknown output format " << format); + } + + // Finally, have that writer interrogate the DataCollector and save + // the results. + if (output != 0) + output->Output(data); + + // end main +} diff --git a/examples/stats/wifi-example.gnuplot b/examples/stats/wifi-example.gnuplot new file mode 100644 index 000000000..e2349e52c --- /dev/null +++ b/examples/stats/wifi-example.gnuplot @@ -0,0 +1,13 @@ +set terminal postscript portrait enhanced lw 2 "Helvetica" 14 + +set size 1.0, 0.66 + +#------------------------------------------------------- +set out "wifi-default.eps" +#set title "Packet Loss Over Distance" +set xlabel "Distance (m)" +set xrange [0:200] +set ylabel "% Packet Loss --- average of 5 trials per distance" +set yrange [0:110] + +plot "wifi-default.data" with lines title "WiFi Defaults" diff --git a/examples/stats/wscript b/examples/stats/wscript new file mode 100644 index 000000000..e3ac10d5b --- /dev/null +++ b/examples/stats/wscript @@ -0,0 +1,6 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_program('wifi-example-sim', ['stats']) + obj.source = ['wifi-example-sim.cc', + 'wifi-example-apps.cc'] diff --git a/examples/tcp-large-transfer.cc b/examples/tcp-large-transfer.cc index c715e348a..4a4d294f3 100644 --- a/examples/tcp-large-transfer.cc +++ b/examples/tcp-large-transfer.cc @@ -25,12 +25,10 @@ // - Tracing of queues and packet receptions to file // "tcp-large-transfer.tr" // - pcap traces also generated in the following files -// "tcp-large-transfer.pcap-$n-$i" where n and i represent node and interface numbers respectively +// "tcp-large-transfer-$n-$i.pcap" where n and i represent node and interface +// numbers respectively // Usage (e.g.): ./waf --run tcp-large-transfer -//XXX this isn't working as described right now -//it is just blasting away for 10 seconds, with no fixed amount of data -//being sent #include #include @@ -48,37 +46,15 @@ using namespace ns3; NS_LOG_COMPONENT_DEFINE ("TcpLargeTransfer"); -void -ApplicationTraceSink (Ptr packet, - const Address &addr) -{ -// g_log is not declared in optimized builds -// should convert this to use of some other flag than the logging system -#ifdef NS3_LOG_ENABLE - if (!g_log.IsNoneEnabled ()) { - if (InetSocketAddress::IsMatchingType (addr) ) - { - InetSocketAddress address = InetSocketAddress::ConvertFrom (addr); - std::cout << "PacketSink received size " << - packet->GetSize () << " at time " << - Simulator::Now ().GetSeconds () << " from address: " << - address.GetIpv4 () << std::endl; - char buf[2000]; - memcpy(buf, packet->PeekData (), packet->GetSize ()); - for (uint32_t i=0; i < packet->GetSize (); i++) - { - std::cout << buf[i]; - if (i && i % 60 == 0) - std::cout << std::endl; - } - std::cout << std::endl << std::endl; - } - } -#endif -} +// The number of bytes to send in this simulation. +static uint32_t txBytes = 2000000; -void CloseConnection (Ptr localSocket); -void StartFlow(Ptr, uint32_t, Ipv4Address, uint16_t); +// These are for starting the writing process, and handling the sending +// socket's notification upcalls (events). These two together more or less +// implement a sending "Application", although not a proper ns3::Application +// subclass. + +void StartFlow(Ptr, Ipv4Address, uint16_t); void WriteUntilBufferFull (Ptr, uint32_t); int main (int argc, char *argv[]) @@ -87,7 +63,7 @@ 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 // LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL); - // LogComponentEnable("TcpSocket", LOG_LEVEL_ALL); + // LogComponentEnable("TcpSocketImpl", LOG_LEVEL_ALL); // LogComponentEnable("PacketSink", LOG_LEVEL_ALL); // LogComponentEnable("TcpLargeTransfer", LOG_LEVEL_ALL); @@ -101,27 +77,34 @@ int main (int argc, char *argv[]) CommandLine cmd; cmd.Parse (argc, argv); - // Here, we will explicitly create three nodes. - NodeContainer c0; - c0.Create (2); + // Here, we will explicitly create three nodes. The first container contains + // nodes 0 and 1 from the diagram above, and the second one contains nodes + // 1 and 2. This reflects the channel connectivity, and will be used to + // install the network interfaces and connect them with a channel. + NodeContainer n0n1; + n0n1.Create (2); - NodeContainer c1; - c1.Add (c0.Get (1)); - c1.Create (1); + NodeContainer n1n2; + n1n2.Add (n0n1.Get (1)); + n1n2.Create (1); // We create the channels first without any IP addressing information + // First make and configure the helper, so that it will put the appropriate + // attributes on the network interfaces and channels we are about to install. PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate(10000000))); - p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds(10))); - NetDeviceContainer dev0 = p2p.Install (c0); - NetDeviceContainer dev1 = p2p.Install (c1); + p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate(10000000))); + p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds(10))); - // add ip/tcp stack to nodes. - NodeContainer c = NodeContainer (c0, c1.Get (1)); + // And then install devices and channels connecting our topology. + NetDeviceContainer dev0 = p2p.Install (n0n1); + NetDeviceContainer dev1 = p2p.Install (n1n2); + + // Now add ip/tcp stack to all nodes. + NodeContainer allNodes = NodeContainer (n0n1, n1n2.Get (1)); InternetStackHelper internet; - internet.Install (c); + internet.Install (allNodes); - // Later, we add IP addresses. + // Later, we add IP addresses. Ipv4AddressHelper ipv4; ipv4.SetBase ("10.1.3.0", "255.255.255.0"); ipv4.Assign (dev0); @@ -133,83 +116,106 @@ int main (int argc, char *argv[]) /////////////////////////////////////////////////////////////////////////// // Simulation 1 - // + // // Send 2000000 bytes over a connection to server port 50000 at time 0 - // Should observe SYN exchange, a lot of data segments, and FIN exchange + // Should observe SYN exchange, a lot of data segments and ACKS, and FIN + // exchange. FIN exchange isn't quite compliant with TCP spec (see release + // notes for more info) // /////////////////////////////////////////////////////////////////////////// - int nBytes = 2000000; uint16_t servPort = 50000; - // Create a packet sink to receive these packets + // Create a packet sink to receive these packets on n2... PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort)); - ApplicationContainer apps = sink.Install (c1.Get (1)); + ApplicationContainer apps = sink.Install (n1n2.Get (1)); apps.Start (Seconds (0.0)); + apps.Stop (Seconds (3.0)); - // and generate traffic to remote sink. - //TypeId tid = TypeId::LookupByName ("ns3::TcpSocketFactory"); - Ptr localSocket = Socket::CreateSocket (c0.Get (0), TcpSocketFactory::GetTypeId ()); + // Create a source to send packets from n0. Instead of a full Application + // and the helper APIs you might see in other example files, this example + // will use sockets directly and register some socket callbacks as a sending + // "Application". + + // Create and bind the socket... + Ptr localSocket = + Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory::GetTypeId ()); localSocket->Bind (); - Simulator::ScheduleNow (&StartFlow, localSocket, nBytes, + + // ...and schedule the sending "Application"; This is similar to what an + // ns3::Application subclass would do internally. + Simulator::ScheduleNow (&StartFlow, localSocket, ipInterfs.GetAddress (1), servPort); - Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/Rx", - MakeCallback (&ApplicationTraceSink)); + // One can toggle the comment for the following line on or off to see the + // effects of finite send buffer modelling. One can also change the size of + // said buffer. + //localSocket->SetAttribute("SndBufSize", UintegerValue(4096)); + + //Ask for ASCII and pcap traces of network traffic std::ofstream ascii; ascii.open ("tcp-large-transfer.tr"); PointToPointHelper::EnableAsciiAll (ascii); PointToPointHelper::EnablePcapAll ("tcp-large-transfer"); + // Finally, set up the simulator to run. The 1000 second hard limit is a + // failsafe in case some change above causes the simulation to never end Simulator::Stop (Seconds(1000)); Simulator::Run (); Simulator::Destroy (); } -void CloseConnection (Ptr localSocket) -{ - localSocket->Close (); -} -void StartFlow(Ptr localSocket, uint32_t nBytes, +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//begin implementation of sending "Application" +void StartFlow(Ptr localSocket, Ipv4Address servAddress, uint16_t servPort) { - // NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ()); + NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ()); localSocket->Connect (InetSocketAddress (servAddress, servPort));//connect - localSocket->SetConnectCallback (MakeCallback (&CloseConnection), - Callback > (), - Callback > ()); - //we want to close as soon as the connection is established - //the tcp state machine and outgoing buffer will assure that - //all of the data is delivered + + // tell the tcp implementation to call WriteUntilBufferFull again + // if we blocked and new tx buffer space becomes available localSocket->SetSendCallback (MakeCallback (&WriteUntilBufferFull)); - WriteUntilBufferFull (localSocket, nBytes); + WriteUntilBufferFull (localSocket, txBytes); } -void WriteUntilBufferFull (Ptr localSocket, uint32_t nBytes) +void WriteUntilBufferFull (Ptr localSocket, uint32_t txSpace) { // Perform series of 1040 byte writes (this is a multiple of 26 since // we want to detect data splicing in the output stream) uint32_t writeSize = 1040; uint8_t data[writeSize]; - while (nBytes > 0) { - uint32_t curSize= nBytes > writeSize ? writeSize : nBytes; + + while (txBytes > 0) { + uint32_t curSize= txBytes > writeSize ? writeSize : txBytes; + if (curSize > txSpace) + curSize = txSpace; for(uint32_t i = 0; i < curSize; ++i) { char m = toascii (97 + i % 26); data[i] = m; } - uint32_t amountSent = localSocket->Send (data, curSize); - if(amountSent < curSize) + int amountSent = localSocket->Send (data, curSize, 0); + if(amountSent < 0) { - std::cout << "Socket blocking, returning" << std::endl; + // we will be called again when new tx space becomes available. + std::cout << "Socket blocking, " << txBytes << " left to write, returning" << std::endl; + return; + } + txBytes -= curSize; + if (amountSent != (int)curSize) + { + std::cout << "Short Write, returning" << std::endl; return; } - nBytes -= curSize; } + localSocket->Close (); } diff --git a/examples/tcp-nsc-lfn.cc b/examples/tcp-nsc-lfn.cc new file mode 100644 index 000000000..a57e2b633 --- /dev/null +++ b/examples/tcp-nsc-lfn.cc @@ -0,0 +1,145 @@ +/* -*- 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 + * + */ + +// +// Network topology +// +// 6Mb/s, 500ms +// n0-----------------n1 +// +// - a 'lossy' network with long delay +// - TCP flow from n0 to n1 and from n1 to n0 +// - pcap traces generated as tcp-nsc-lfn-0-0.pcap and tcp-nsc-lfn-1-0.pcap +// Usage (e.g.): ./waf --run 'tcp-nsc-lfn --TCP_CONGESTION=hybla --runtime=30' + +#include +#include +#include +#include +#include + +#include "ns3/core-module.h" +#include "ns3/common-module.h" +#include "ns3/helper-module.h" +#include "ns3/node-module.h" +#include "ns3/global-route-manager.h" +#include "ns3/simulator-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpNscLfn"); + + +int main (int argc, char *argv[]) +{ + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (4096)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("6Mbps")); + + // cubic is the default congestion algorithm in Linux 2.6.26 + std::string tcpCong = "cubic"; + // this is the default error rate of our link, that is, the the probability of a single + // byte being 'corrupted' during transfer. + double errRate = 0.000001; + // how long the sender should be running, in seconds. + unsigned int runtime = 120; + // the name of the NSC stack library that should be used + std::string nscStack = "liblinux2.6.26.so"; + + CommandLine cmd; + // Here, we define additional command line options. + // This allows a user to override the defaults set above from the command line. + cmd.AddValue("TCP_CONGESTION", "Linux 2.6.26 Tcp Congestion control algorithm to use", tcpCong); + cmd.AddValue("error-rate", "Error rate to apply to link", errRate); + cmd.AddValue("runtime", "How long the applications should send data (default 120 seconds)", runtime); + cmd.AddValue("nscstack", "Set name of NSC stack (shared library) to use (default liblinux2.6.26.so)", nscStack); + cmd.Parse (argc, argv); + + NodeContainer n; + n.Create (2); + + PointToPointHelper p2p; + // create point-to-point link with a bandwidth of 6MBit/s and a large delay (0.5 seconds) + p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate(6 * 1000 * 1000))); + p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds(500))); + + NetDeviceContainer p2pInterfaces = p2p.Install (n); + // The default MTU of the p2p link would be 65535, which doesn't work + // well with our default errRate (most packets would arrive corrupted). + p2pInterfaces.Get(0)->SetMtu(1500); + p2pInterfaces.Get(1)->SetMtu(1500); + + InternetStackHelper internet; + // The next statement switches the nodes to 'NSC'-Mode. + // It disables the native ns-3 TCP model and loads the NSC library. + internet.SetNscStack (nscStack); + internet.Install (n); + + if (tcpCong != "cubic") // make sure we only fail if both --nscstack and --TCP_CONGESTION are used + { + // This uses ns-3s attribute system to set the 'net.ipv4.tcp_congestion_control' sysctl of the + // stack. + // The same mechanism could be used to e.g. disable TCP timestamps: + // Config::Set ("/NodeList/*/$ns3::Ns3NscStack/net.ipv4.tcp_timestamps", StringValue ("0")); + Config::Set ("/NodeList/*/$ns3::Ns3NscStack/net.ipv4.tcp_congestion_control", StringValue (tcpCong)); + } + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.0.0.0", "255.255.255.0"); + Ipv4InterfaceContainer ipv4Interfaces = ipv4.Assign (p2pInterfaces); + + DoubleValue rate(errRate); + RandomVariableValue u01(UniformVariable (0.0, 1.0)); + Ptr em1 = + CreateObject ("RanVar", u01, "ErrorRate", rate); + Ptr em2 = + CreateObject ("RanVar", u01, "ErrorRate", rate); + + // This enables the specified errRate on both link endpoints. + p2pInterfaces.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue (em1)); + p2pInterfaces.Get(1)->SetAttribute("ReceiveErrorModel", PointerValue (em2)); + + GlobalRouteManager::PopulateRoutingTables (); + + uint16_t servPort = 8080; + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort)); + ApplicationContainer sinkApp = sinkHelper.Install (n); + sinkApp.Start (Seconds (0.0)); + // this makes sure that the receiver will run one minute longer than the sender applicaton. + sinkApp.Stop (Seconds (runtime + 60.0)); + + // This sets up two TCP flows, one from A -> B, one from B -> A. + for (int i = 0, j = 1; i < 2; j--, i++) + { + Address remoteAddress(InetSocketAddress(ipv4Interfaces.GetAddress (i), servPort)); + OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress); + clientHelper.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + clientHelper.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + ApplicationContainer clientApp = clientHelper.Install(n.Get(j)); + clientApp.Start (Seconds (1.0 + i)); + clientApp.Stop (Seconds (runtime + 1.0 + i)); + } + + // This tells ns-3 to generate pcap traces. + PointToPointHelper::EnablePcapAll ("tcp-nsc-lfn"); + + Simulator::Stop (Seconds(900)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; +} diff --git a/examples/tcp-nsc-zoo.cc b/examples/tcp-nsc-zoo.cc new file mode 100644 index 000000000..e02a5b1b1 --- /dev/null +++ b/examples/tcp-nsc-zoo.cc @@ -0,0 +1,148 @@ +/* -*- 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 + * + */ + + +// Network topology +// +// n0 n1 n2 n3 +// | | | | +// ================= +// LAN +// +// - Pcap traces are saved as tcp-nsc-zoo-$n-0.pcap, where $n represents the node number +// - TCP flows from n0 to n1, n2, n3, from n1 to n0, n2, n3, etc. +// Usage (e.g.): ./waf --run 'tcp-nsc-zoo --nodes=5' + +#include +#include + +#include "ns3/core-module.h" +#include "ns3/helper-module.h" +#include "ns3/node-module.h" +#include "ns3/global-route-manager.h" +#include "ns3/simulator-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpNscZoo"); + +// Simulates a diverse network with various stacks supported by NSC. +int main(int argc, char *argv[]) +{ + CsmaHelper csma; + unsigned int MaxNodes = 4; + unsigned int runtime = 3; + + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (2048)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("8kbps")); + CommandLine cmd; + // this allows the user to raise the number of nodes using --nodes=X command-line argument. + cmd.AddValue("nodes", "Number of nodes in the network (must be > 1)", MaxNodes); + cmd.AddValue("runtime", "How long the applications should send data (default 3 seconds)", runtime); + cmd.Parse (argc, argv); + + if (MaxNodes < 2) + { + std::cerr << "--nodes: must be >= 2" << std::endl; + return 1; + } + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(100 * 1000 * 1000))); + csma.SetChannelAttribute ("Delay", TimeValue (MicroSeconds (200))); + + NodeContainer n; + n.Create(MaxNodes); + NetDeviceContainer ethInterfaces = csma.Install (n); + + InternetStackHelper internetStack; + + internetStack.SetNscStack ("liblinux2.6.26.so"); + // this switches nodes 0 and 1 to NSCs Linux 2.6.26 stack. + internetStack.Install (n.Get(0)); + internetStack.Install (n.Get(1)); + // this disables TCP SACK, wscale and timestamps on node 1 (the attributes represent sysctl-values). + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_sack", StringValue ("0")); + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_timestamps", StringValue ("0")); + Config::Set ("/NodeList/1/$ns3::Ns3NscStack/net.ipv4.tcp_window_scaling", StringValue ("0")); + + if (MaxNodes > 2) + { + internetStack.Install (n.Get(2)); + } + + if (MaxNodes > 3) + { + // the next statement doesn't change anything for the nodes 0, 1, and 2; since they + // already have a stack assigned. + internetStack.SetNscStack ("liblinux2.6.18.so"); + // this switches node 3 to NSCs Linux 2.6.18 stack. + internetStack.Install (n.Get(3)); + // and then agains disables sack/timestamps/wscale on node 3. + Config::Set ("/NodeList/3/$ns3::Ns3NscStack/net.ipv4.tcp_sack", StringValue ("0")); + Config::Set ("/NodeList/3/$ns3::Ns3NscStack/net.ipv4.tcp_timestamps", StringValue ("0")); + Config::Set ("/NodeList/3/$ns3::Ns3NscStack/net.ipv4.tcp_window_scaling", StringValue ("0")); + } + // the freebsd stack is not yet built by default, so its commented out for now. + // internetStack.SetNscStack ("libfreebsd5.so"); + for (unsigned int i =4; i < MaxNodes; i++) + { + internetStack.Install (n.Get(i)); + } + Ipv4AddressHelper ipv4; + + ipv4.SetBase ("10.0.0.0", "255.255.255.0"); + Ipv4InterfaceContainer ipv4Interfaces = ipv4.Assign (ethInterfaces); + + GlobalRouteManager::PopulateRoutingTables (); + + uint16_t servPort = 8080; + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort)); + // start a sink client on all nodes + ApplicationContainer sinkApp = sinkHelper.Install (n); + sinkApp.Start (Seconds (0)); + sinkApp.Stop (Seconds (30.0)); + + // This tells every node on the network to start a flow to all other nodes on the network ... + for (unsigned int i = 0 ; i < MaxNodes;i++) + { + for (unsigned int j = 0 ; j < MaxNodes;j++) + { + if (i == j) + { // ...but we don't want a node to talk to itself. + continue; + } + Address remoteAddress(InetSocketAddress(ipv4Interfaces.GetAddress (j), servPort)); + OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress); + clientHelper.SetAttribute + ("OnTime", RandomVariableValue (ConstantVariable (1))); + clientHelper.SetAttribute + ("OffTime", RandomVariableValue (ConstantVariable (0))); + ApplicationContainer clientApp = clientHelper.Install(n.Get(i)); + clientApp.Start (Seconds (j)); /* delay startup depending on node number */ + clientApp.Stop (Seconds (j + runtime)); + } + } + + CsmaHelper::EnablePcapAll ("tcp-nsc-zoo"); + + Simulator::Stop (Seconds(100)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; +} diff --git a/examples/tcp-star-server.cc b/examples/tcp-star-server.cc new file mode 100644 index 000000000..ca79d681e --- /dev/null +++ b/examples/tcp-star-server.cc @@ -0,0 +1,172 @@ +/* -*- 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 + * + */ + + +// Default Network topology, 9 nodes in a star +/* + n2 n3 n4 + \ | / + \|/ + n1---n0---n5 + /|\ + / | \ + n8 n7 n6 +*/ +// - CBR Traffic goes from the star "arms" to the "hub" +// - Tracing of queues and packet receptions to file +// "tcp-star-server.tr" +// - pcap traces also generated in the following files +// "tcp-star-server-$n-$i.pcap" where n and i represent node and interface +// numbers respectively +// Usage examples for things you might want to tweak: +// ./waf --run="tcp-star-server" +// ./waf --run="tcp-star-server --nNodes=25" +// ./waf --run="tcp-star-server --ns3::OnOffApplication::DataRate=10000" +// ./waf --run="tcp-star-server --ns3::OnOffApplication::PacketSize=500" +// See the ns-3 tutorial for more info on the command line: +// http://www.nsnam.org/tutorials.html + + + + +#include +#include +#include +#include + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/global-route-manager.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TcpServer"); + +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 + + //LogComponentEnable ("TcpServer", LOG_LEVEL_INFO); + //LogComponentEnable ("TcpL4Protocol", LOG_LEVEL_ALL); + //LogComponentEnable ("TcpSocketImpl", LOG_LEVEL_ALL); + //LogComponentEnable ("PacketSink", LOG_LEVEL_ALL); + // + // Make the random number generators generate reproducible results. + // + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + // Set up some default values for the simulation. + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (250)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("5kb/s")); + uint32_t N = 9; //number of nodes in the star + + // Allow the user to override any of the defaults and the above + // Config::SetDefault()s at run-time, via command-line arguments + CommandLine cmd; + cmd.AddValue("nNodes", "Number of nodes to place in the star", N); + cmd.Parse (argc, argv); + + // Here, we will create N nodes in a star. + NS_LOG_INFO ("Create nodes."); + NodeContainer serverNode; + NodeContainer clientNodes; + serverNode.Create(1); + clientNodes.Create(N-1); + NodeContainer allNodes = NodeContainer(serverNode, clientNodes); + + // Install network stacks on the nodes + InternetStackHelper internet; + internet.Install (allNodes); + + //Collect an adjacency list of nodes for the p2p topology + std::vector nodeAdjacencyList(N-1); + for(uint32_t i=0; i deviceAdjacencyList(N-1); + for(uint32_t i=0; i interfaceAdjacencyList(N-1); + for(uint32_t i=0; i channel = CreateObject (); + + channel->SetPropagationDelayModel ( + CreateObject ()); + + Ptr log = + CreateObject (); + + log->SetReferenceModel (CreateObject ()); + + channel->SetPropagationLossModel (log); + + WifiHelper wifi; + wifi.SetPhy ("ns3::WifiPhy"); + wifi.SetRemoteStationManager ("ns3::ArfWifiManager"); + + Ssid ssid = Ssid ("ns-3-ssid"); + wifi.SetMac ("ns3::NqstaWifiMac", + "Ssid", SsidValue (ssid), + "ActiveProbing", BooleanValue (false)); + + NetDeviceContainer staDevices; + staDevices = wifi.Install (wifiStaNodes, channel); + + wifi.SetMac ("ns3::NqapWifiMac", + "Ssid", SsidValue (ssid), + "BeaconGeneration", BooleanValue (true), + "BeaconInterval", TimeValue (Seconds (2.5))); + + NetDeviceContainer apDevices; + apDevices = wifi.Install (wifiApNode, channel); + + MobilityHelper mobility; + + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (0.0), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (5.0), + "DeltaY", DoubleValue (10.0), + "GridWidth", UintegerValue (3), + "LayoutType", StringValue ("RowFirst")); + + mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", + "Bounds", RectangleValue (Rectangle (-50, 50, -50, 50))); + mobility.Install (wifiStaNodes); + + mobility.SetMobilityModel ("ns3::StaticMobilityModel"); + mobility.Install (wifiApNode); + + InternetStackHelper stack; + stack.Install (csmaNodes); + stack.Install (wifiApNode); + stack.Install (wifiStaNodes); + + Ipv4AddressHelper address; + + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + + address.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4InterfaceContainer csmaInterfaces; + csmaInterfaces = address.Assign (csmaDevices); + + address.SetBase ("10.1.3.0", "255.255.255.0"); + address.Assign (staDevices); + address.Assign (apDevices); + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + + UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = + echoClient.Install (wifiStaNodes.Get (nWifi - 1)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + + GlobalRouteManager::PopulateRoutingTables (); + + Simulator::Stop (Seconds (10.0)); + + WifiHelper::EnablePcap ("third", + wifiStaNodes.Get (nWifi - 1)->GetId (), 0); + CsmaHelper::EnablePcap ("third", + csmaNodes.Get (nCsma)->GetId (), 0); + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/examples/udp-echo.cc b/examples/udp-echo.cc index edf59ac41..af338c8cb 100644 --- a/examples/udp-echo.cc +++ b/examples/udp-echo.cc @@ -87,8 +87,9 @@ main (int argc, char *argv[]) // Explicitly create the channels required by the topology (shown above). // CsmaHelper csma; - csma.SetChannelParameter ("DataRate", DataRateValue (DataRate(5000000))); - csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2))); + csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000))); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + csma.SetDeviceAttribute ("Mtu", UintegerValue (1400)); NetDeviceContainer d = csma.Install (n); Ipv4AddressHelper ipv4; @@ -104,8 +105,7 @@ main (int argc, char *argv[]) // Create a UdpEchoServer application on node one. // uint16_t port = 9; // well-known echo port number - UdpEchoServerHelper server; - server.SetPort (port); + UdpEchoServerHelper server (port); ApplicationContainer apps = server.Install (n.Get(1)); apps.Start (Seconds (1.0)); apps.Stop (Seconds (10.0)); @@ -117,11 +117,10 @@ main (int argc, char *argv[]) uint32_t packetSize = 1024; uint32_t maxPacketCount = 1; Time interPacketInterval = Seconds (1.); - UdpEchoClientHelper client; - client.SetRemote (i.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (maxPacketCount)); - client.SetAppAttribute ("Interval", TimeValue (interPacketInterval)); - client.SetAppAttribute ("PacketSize", UintegerValue (packetSize)); + UdpEchoClientHelper client (i.GetAddress (1), port); + client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + client.SetAttribute ("Interval", TimeValue (interPacketInterval)); + client.SetAttribute ("PacketSize", UintegerValue (packetSize)); apps = client.Install (n.Get (0)); apps.Start (Seconds (2.0)); apps.Stop (Seconds (10.0)); diff --git a/examples/wifi-ap.cc b/examples/wifi-ap.cc index e85f437ff..a96747c9d 100644 --- a/examples/wifi-ap.cc +++ b/examples/wifi-ap.cc @@ -110,7 +110,7 @@ AdvancePosition (Ptr node) int main (int argc, char *argv[]) { - Packet::EnableMetadata (); + Packet::EnablePrinting (); // enable rts cts all the time. Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("0")); diff --git a/examples/wifi-wired-bridging.cc b/examples/wifi-wired-bridging.cc new file mode 100644 index 000000000..1a01534e7 --- /dev/null +++ b/examples/wifi-wired-bridging.cc @@ -0,0 +1,162 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/mobility-module.h" +#include "ns3/helper-module.h" +#include "ns3/wifi-module.h" +#include "ns3/node-module.h" +#include "ns3/global-route-manager.h" +#include +#include +#include +#include + +using namespace ns3; + +Ptr +CreateChannel (void) +{ + Ptr channel = CreateObject (); + channel->SetPropagationDelayModel (CreateObject ()); + Ptr log = CreateObject (); + log->SetReferenceModel (CreateObject ()); + channel->SetPropagationLossModel (log); + return channel; +} + +int main (int argc, char *argv[]) +{ + uint32_t nWifis = 2; + uint32_t nStas = 2; + bool sendIp = true; + + RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); + + CommandLine cmd; + cmd.AddValue ("nWifis", "Number of wifi networks", nWifis); + cmd.AddValue ("nStas", "Number of stations per wifi network", nStas); + cmd.AddValue ("SendIp", "Send Ipv4 or raw packets", sendIp); + cmd.Parse (argc, argv); + + NodeContainer backboneNodes; + NetDeviceContainer backboneDevices; + Ipv4InterfaceContainer backboneInterfaces; + std::vector staNodes; + std::vector staDevices; + std::vector apDevices; + std::vector staInterfaces; + std::vector apInterfaces; + + InternetStackHelper stack; + CsmaHelper csma; + Ipv4AddressHelper ip; + ip.SetBase ("192.168.0.0", "255.255.255.0"); + + backboneNodes.Create (nWifis); + stack.Install (backboneNodes); + + backboneDevices = csma.Install (backboneNodes); + backboneInterfaces = ip.Assign (backboneDevices); + + double wifiX = 0.0; + for (uint32_t i = 0; i < nWifis; ++i) + { + // calculate ssid for wifi subnetwork + std::ostringstream oss; + oss << "wifi-default-" << i; + Ssid ssid = Ssid (oss.str ()); + + NodeContainer sta; + NetDeviceContainer staDev; + NetDeviceContainer apDev; + Ipv4InterfaceContainer staInterface; + Ipv4InterfaceContainer apInterface; + MobilityHelper mobility; + BridgeHelper bridge; + WifiHelper wifi; + Ptr channel; + + sta.Create (nStas); + channel = CreateChannel (); + ip.NewNetwork (); + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (wifiX), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (5.0), + "DeltaY", DoubleValue (5.0), + "GridWidth", UintegerValue (1), + "LayoutType", StringValue ("RowFirst")); + + + // setup the AP. + mobility.SetMobilityModel ("ns3::StaticMobilityModel"); + mobility.Install (backboneNodes.Get (i)); + wifi.SetMac ("ns3::NqapWifiMac", + "Ssid", SsidValue (ssid), + "BeaconGeneration", BooleanValue (true), + "BeaconInterval", TimeValue (Seconds (2.5))); + apDev = wifi.Install (backboneNodes.Get (i), channel); + apInterface = ip.Assign (apDev); + bridge.Install (backboneNodes.Get (i), NetDeviceContainer (apDev, backboneDevices.Get (i))); + + // setup the STAs + stack.Install (sta); + mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", + "Mode", StringValue ("Time"), + "Time", StringValue ("2s"), + "Speed", StringValue ("Constant:1.0"), + "Bounds", RectangleValue (Rectangle (wifiX, wifiX+5.0,0.0, (nStas+1)*5.0))); + mobility.Install (sta); + wifi.SetMac ("ns3::NqstaWifiMac", + "Ssid", SsidValue (ssid), + "ActiveProbing", BooleanValue (false)); + staDev = wifi.Install (sta, channel); + staInterface = ip.Assign (staDev); + + // save everything in containers. + staNodes.push_back (sta); + apDevices.push_back (apDev); + apInterfaces.push_back (apInterface); + staDevices.push_back (staDev); + staInterfaces.push_back (staInterface); + + wifiX += 20.0; + } + + GlobalRouteManager::PopulateRoutingTables (); + + Address dest; + std::string protocol; + if (sendIp) + { + dest = InetSocketAddress (staInterfaces[1].GetAddress (1), 1025); + protocol = "ns3::UdpSocketFactory"; + } + else + { + PacketSocketAddress tmp; + tmp.SetSingleDevice (staDevices[0].Get (0)->GetIfIndex ()); + tmp.SetPhysicalAddress (staDevices[1].Get (0)->GetAddress ()); + tmp.SetProtocol (0x807); + dest = tmp; + protocol = "ns3::PacketSocketFactory"; + } + OnOffHelper onoff = OnOffHelper (protocol, dest); + onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1))); + onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0))); + ApplicationContainer apps = onoff.Install (staNodes[0].Get (0)); + apps.Start (Seconds (0.5)); + apps.Stop (Seconds (3.0)); + + + WifiHelper::EnablePcap ("wifi-wire-bridging", staNodes[1].Get (1)); + WifiHelper::EnablePcap ("wifi-wire-bridging", staNodes[0].Get (0)); + std::ofstream os; + os.open ("wifi-wire-bridging.mob"); + MobilityHelper::EnableAsciiAll (os); + + Simulator::Stop (Seconds (100.0)); + Simulator::Run (); + Simulator::Destroy (); +} diff --git a/examples/wscript b/examples/wscript index eb668e130..e68afba06 100644 --- a/examples/wscript +++ b/examples/wscript @@ -1,55 +1,85 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): + obj = bld.create_ns3_program('hello-simulator') + obj.source = 'hello-simulator.cc' obj = bld.create_ns3_program('mixed-wireless', - ['core', 'simulator', 'mobility', 'wifi', 'point-to-point', 'internet-stack']) + ['core', 'simulator', 'mobility', 'wifi', 'point-to-point', 'internet-stack']) obj.source = 'mixed-wireless.cc' obj = bld.create_ns3_program('simple-global-routing', - ['point-to-point', 'internet-stack', 'global-routing']) + ['point-to-point', 'internet-stack', 'global-routing']) obj.source = 'simple-global-routing.cc' obj = bld.create_ns3_program('simple-alternate-routing', - ['point-to-point', 'internet-stack', 'global-routing']) + ['point-to-point', 'internet-stack', 'global-routing']) obj.source = 'simple-alternate-routing.cc' obj = bld.create_ns3_program('simple-error-model', - ['point-to-point', 'internet-stack']) + ['point-to-point', 'internet-stack']) obj.source = 'simple-error-model.cc' obj = bld.create_ns3_program('csma-one-subnet', - ['csma', 'internet-stack']) + ['csma', 'internet-stack']) obj.source = 'csma-one-subnet.cc' + obj = bld.create_ns3_program('csma-bridge', + ['bridge', 'csma', 'internet-stack']) + obj.source = 'csma-bridge.cc' + obj = bld.create_ns3_program('udp-echo', - ['csma', 'internet-stack']) + ['csma', 'internet-stack']) obj.source = 'udp-echo.cc' + obj = bld.create_ns3_program('realtime-udp-echo', + ['csma', 'internet-stack']) + obj.source = 'realtime-udp-echo.cc' + obj = bld.create_ns3_program('csma-broadcast', - ['csma', 'internet-stack']) + ['csma', 'internet-stack']) obj.source = 'csma-broadcast.cc' obj = bld.create_ns3_program('csma-packet-socket', - ['csma', 'internet-stack']) + ['csma', 'internet-stack']) obj.source = 'csma-packet-socket.cc' obj = bld.create_ns3_program('csma-multicast', - ['csma', 'internet-stack']) + ['csma', 'internet-stack']) obj.source = 'csma-multicast.cc' obj = bld.create_ns3_program( 'mixed-global-routing', - ['point-to-point', 'internet-stack', 'global-routing' , 'csma-cd']) + ['point-to-point', 'internet-stack', 'global-routing' , 'csma-cd']) obj.source = 'mixed-global-routing.cc' obj = bld.create_ns3_program('simple-point-to-point-olsr', - ['point-to-point', 'internet-stack', 'olsr']) + ['point-to-point', 'internet-stack', 'olsr']) obj.source = 'simple-point-to-point-olsr.cc' obj = bld.create_ns3_program('tcp-large-transfer', - ['point-to-point', 'internet-stack']) + ['point-to-point', 'internet-stack']) obj.source = 'tcp-large-transfer.cc' + obj = bld.create_ns3_program('tcp-nsc-lfn', + ['point-to-point', 'internet-stack']) + obj.source = 'tcp-nsc-lfn.cc' + + obj = bld.create_ns3_program('tcp-nsc-zoo', + ['csma', 'internet-stack']) + obj.source = 'tcp-nsc-zoo.cc' + + obj = bld.create_ns3_program('tcp-star-server', + ['point-to-point', 'internet-stack']) + obj.source = 'tcp-star-server.cc' + + obj = bld.create_ns3_program('star', + ['point-to-point', 'internet-stack']) + obj.source = 'star.cc' + + obj = bld.create_ns3_program('csma-star', + ['csma', 'internet-stack']) + obj.source = 'csma-star.cc' + obj = bld.create_ns3_program('wifi-adhoc', ['core', 'simulator', 'mobility', 'wifi']) obj.source = 'wifi-adhoc.cc' @@ -58,3 +88,9 @@ def build(bld): ['core', 'simulator', 'mobility', 'wifi']) obj.source = 'wifi-ap.cc' + bld.add_subdirs('stats') + + obj = bld.create_ns3_program('wifi-wired-bridging', + ['core', 'simulator', 'mobility', 'wifi', + 'csma', 'helper', 'bridge']) + obj.source = 'wifi-wired-bridging.cc' diff --git a/regression/tests/test-csma-bridge.py b/regression/tests/test-csma-bridge.py new file mode 100644 index 000000000..996bc1da9 --- /dev/null +++ b/regression/tests/test-csma-bridge.py @@ -0,0 +1,16 @@ +#! /usr/bin/env python + +"""Generic trace-comparison-type regression test.""" + +import os +import sys +import tracediff + +def run(verbose, generate, refDirName): + """Execute a test.""" + if tracediff.env['ENABLE_PYTHON_BINDINGS']: + return tracediff.run_test(verbose, generate, refDirName, + "csma-bridge", pyscript=os.path.join('examples', 'csma-bridge.py')) + else: + print >> sys.stderr, "Skipping csma-bridge: Python bindings not available." + raise NotImplementedError diff --git a/regression/tests/test-realtime-udp-echo.py b/regression/tests/test-realtime-udp-echo.py new file mode 100644 index 000000000..76ac10b52 --- /dev/null +++ b/regression/tests/test-realtime-udp-echo.py @@ -0,0 +1,12 @@ +#! /usr/bin/env python + +"""Generic trace-comparison-type regression test.""" + +import os +import shutil +import tracediff + +def run(verbose, generate, refDirName): + """Execute a test.""" + + return tracediff.run_test(verbose, generate, refDirName, "realtime-udp-echo") diff --git a/regression/tests/test-tcp-nsc-lfn.py b/regression/tests/test-tcp-nsc-lfn.py new file mode 100644 index 000000000..84042603f --- /dev/null +++ b/regression/tests/test-tcp-nsc-lfn.py @@ -0,0 +1,33 @@ +#! /usr/bin/env python + +"""Trace-comparison-type regression test for the Network Simulation Cradle.""" + +import os +import shutil +import sys +import tracediff +import platform + + +def run(verbose, generate, refDirName): + """Run a Network Simulation Cradle test involving two TCP streams.""" + + if not tracediff.env['ENABLE_NSC']: + print >>sys.stderr, "Skipping tcp-nsc-lfn: NSC not available." + raise NotImplementedError + + testName = "tcp-nsc-lfn" + arguments = ["--ns3::OnOffApplication::DataRate=40000", "--runtime=20"] + platform_bits = platform.architecture()[0] + + if platform_bits == "64bit": + traceDirName = testName + "_64bit.ref" + elif platform_bits == "32bit": + traceDirName = testName + "_32bit.ref" + else: + # Something unexpected. How should we signal an error here? Rasing a + # string might not be the best idea? + raise "Unknown architecture, not 64 or 32 bit?" + + return tracediff.run_test(verbose, generate, refDirName, + testName, arguments=arguments, refTestName=traceDirName) diff --git a/regression/tests/test-udp-echo.py b/regression/tests/test-udp-echo.py index e3dd72194..46346f5a4 100644 --- a/regression/tests/test-udp-echo.py +++ b/regression/tests/test-udp-echo.py @@ -8,5 +8,5 @@ import tracediff def run(verbose, generate, refDirName): """Execute a test.""" - + #print tracediff.env return tracediff.run_test(verbose, generate, refDirName, "udp-echo") diff --git a/regression/tests/test-wifi-wired-bridging.py b/regression/tests/test-wifi-wired-bridging.py new file mode 100644 index 000000000..cda3a3dfd --- /dev/null +++ b/regression/tests/test-wifi-wired-bridging.py @@ -0,0 +1,12 @@ +#! /usr/bin/env python + +"""Compare that Wifi-Wired Bridging generates correct traces.""" + +import os +import shutil +import tracediff + +def run(verbose, generate, refDirName): + """Execute a test.""" + + return tracediff.run_test(verbose, generate, refDirName, "wifi-wired-bridging", ["--SendIp=0"]) diff --git a/samples/main-ns2-mob.cc b/samples/main-ns2-mob.cc new file mode 100644 index 000000000..1b4f827f2 --- /dev/null +++ b/samples/main-ns2-mob.cc @@ -0,0 +1,38 @@ +#include "ns3/core-module.h" +#include "ns3/mobility-module.h" +#include "ns3/simulator-module.h" +#include "ns3/helper-module.h" +#include "ns3/mobility-module.h" +#include +#include + +using namespace ns3; + +static void +CourseChange (std::ostream *os, std::string foo, Ptr mobility) +{ + Vector pos = mobility->GetPosition (); + Vector vel = mobility->GetVelocity (); + *os << Simulator::Now () << " POS: x=" << pos.x << ", y=" << pos.y + << ", z=" << pos.z << "; VEL:" << vel.x << ", y=" << vel.y + << ", z=" << vel.z << std::endl; +} + +int main (int argc, char *argv[]) +{ + Ns2MobilityHelper mobility(argv[1]); + std::ofstream os; + os.open (argv[2]); + NodeContainer stas; + stas.Create (1); + + mobility.Install (); + + Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange", + MakeBoundCallback (&CourseChange, &os)); + + Simulator::Stop (Seconds (10.0)); + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/samples/main-propagation-loss.cc b/samples/main-propagation-loss.cc index 2ab140bfa..e86d569bd 100644 --- a/samples/main-propagation-loss.cc +++ b/samples/main-propagation-loss.cc @@ -51,8 +51,8 @@ PrintOne (double minTxpower, double maxTxpower, double stepTxpower, double min, int main (int argc, char *argv[]) { - Config::SetGlobal ("LogDistancePropagationLossModel::ReferenceDistance", StringValue ("1.0")); - Config::SetGlobal ("LogDistancePropagationLossModel::Exponent", StringValue ("4")); + Config::SetDefault ("ns3::LogDistancePropagationLossModel::ReferenceDistance", StringValue ("1.0")); + Config::SetDefault ("ns3::LogDistancePropagationLossModel::Exponent", StringValue ("4")); PrintOne (-10, 20, 5, 0, 10000, 2); diff --git a/samples/main-test-sync.cc b/samples/main-test-sync.cc new file mode 100644 index 000000000..0db9f7151 --- /dev/null +++ b/samples/main-test-sync.cc @@ -0,0 +1,133 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include "ns3/simulator.h" +#include "ns3/realtime-simulator-impl.h" +#include "ns3/nstime.h" +#include "ns3/log.h" +#include "ns3/system-thread.h" +#include "ns3/string.h" +#include "ns3/config.h" +#include "ns3/global-value.h" +#include "ns3/ptr.h" + +#include +#include + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("TestSync"); + +bool gFirstRun = false; + +void +inserted_function (void) +{ + NS_ASSERT (gFirstRun); + NS_LOG_UNCOND ("inserted_function() called at " << + Simulator::Now ().GetSeconds () << " s"); +} + +void +background_function (void) +{ + NS_ASSERT (gFirstRun); + NS_LOG_UNCOND ("background_function() called at " << + Simulator::Now ().GetSeconds () << " s"); +} + +void +first_function (void) +{ + NS_LOG_UNCOND ("first_function() called at " << + Simulator::Now ().GetSeconds () << " s"); + gFirstRun = true; +} + +class FakeNetDevice +{ +public: + FakeNetDevice (); + void Doit3 (void); + void Doit4 (void); +}; + +FakeNetDevice::FakeNetDevice () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +void +FakeNetDevice::Doit3 (void) +{ + NS_LOG_FUNCTION_NOARGS (); + sleep (1); + for (uint32_t i = 0.001; i < 10000; ++i) + { + // + // Exercise the realtime relative now path + // + DynamicCast (Simulator::GetImplementation ())->ScheduleRealtimeNow (MakeEvent (&inserted_function)); + usleep (1000); + } +} + +void +FakeNetDevice::Doit4 (void) +{ + NS_LOG_FUNCTION_NOARGS (); + sleep (1); + for (uint32_t i = 0.001; i < 10000; ++i) + { + // + // Exercise the realtime relative schedule path + // + DynamicCast (Simulator::GetImplementation ())->ScheduleRealtime (Seconds (0), MakeEvent (&inserted_function)); + usleep (1000); + } +} + +void +test (void) +{ + GlobalValue::Bind ("SimulatorImplementationType", + StringValue ("ns3::RealtimeSimulatorImpl")); + + FakeNetDevice fnd; + + // + // Make sure ScheduleNow works when the system isn't running + // + DynamicCast (Simulator::GetImplementation ())->ScheduleRealtimeNow(MakeEvent (&first_function)); + + // + // drive the progression of m_currentTs at a ten millisecond rate + // + for (double d = 0.; d < 14.999; d += 0.01) + { + Simulator::Schedule (Seconds (d), &background_function); + } + + Ptr st3 = Create ( + MakeCallback (&FakeNetDevice::Doit3, &fnd)); + st3->Start (); + + Ptr st4 = Create ( + MakeCallback (&FakeNetDevice::Doit4, &fnd)); + st4->Start (); + + Simulator::Stop (Seconds (15.0)); + Simulator::Run (); + st3->Join (); + st4->Join (); + Simulator::Destroy (); +} + +int +main (int argc, char *argv[]) +{ + while (true) + { + test (); + } +} + diff --git a/samples/ns2-mob.tr b/samples/ns2-mob.tr new file mode 100644 index 000000000..b45e39cb2 --- /dev/null +++ b/samples/ns2-mob.tr @@ -0,0 +1,7 @@ + +$node_(0) set X_ 0.0 +$node_(0) set Y_ 25.0 +$node_(0) set Z_ 0.0 +$ns_ at 3.0 "$node_(0) setdest 25 0 0" +$ns_ at 4.8 "$node_(0) setdest 0 0 0" +$ns_ at 5.0 "$node_(0) setdest 25 0 0" diff --git a/samples/sample-simulator.py b/samples/sample-simulator.py new file mode 100644 index 000000000..7a6c5b74f --- /dev/null +++ b/samples/sample-simulator.py @@ -0,0 +1,28 @@ +# -*- Mode:Python; -*- + +import ns3 as ns + + +class MyModel(object): + + def Start(self): + ns.Simulator.Schedule(ns.Seconds(10.0), self.DealWithEvent, ns.Simulator.Now().GetSeconds()) + + def DealWithEvent(self, value): + print "Member method received event at ", ns.Simulator.Now().GetSeconds(), \ + "s started at ", value, "s" + +def random_function(model): + print "random function received event at ", ns.Simulator.Now().GetSeconds(), "s" + model.Start() + + +def main(dummy_argv): + model = MyModel() + ns.Simulator.Schedule(ns.Seconds(10.0), random_function, model) + ns.Simulator.Run() + ns.Simulator.Destroy() + +if __name__ == '__main__': + import sys + main(sys.argv) diff --git a/samples/wscript b/samples/wscript index 8215128a9..d1c1e8fa1 100644 --- a/samples/wscript +++ b/samples/wscript @@ -19,6 +19,9 @@ def build(bld): obj = bld.create_ns3_program('main-test') obj.source = 'main-test.cc' + obj = bld.create_ns3_program('main-test-sync') + obj.source = 'main-test-sync.cc' + obj = bld.create_ns3_program('main-simple', ['node', 'internet-stack', 'onoff']) obj.source = 'main-simple.cc' @@ -39,4 +42,8 @@ def build(bld): ['core', 'simulator', 'mobility', 'wifi']) obj.source = 'main-propagation-loss.cc' + obj = bld.create_ns3_program('main-ns2-mob', + ['core', 'simulator', 'mobility', 'wifi']) + obj.source = 'main-ns2-mob.cc' + diff --git a/scratch/multiple-sources/simple-main.cc b/scratch/multiple-sources/simple-main.cc new file mode 100644 index 000000000..31488d2d1 --- /dev/null +++ b/scratch/multiple-sources/simple-main.cc @@ -0,0 +1,9 @@ + +void RunSimulation (void); + +int main (int argc, char *argv[]) +{ + RunSimulation (); + + return 0; +} diff --git a/scratch/multiple-sources/simple-simulation.cc b/scratch/multiple-sources/simple-simulation.cc new file mode 100644 index 000000000..8650842e2 --- /dev/null +++ b/scratch/multiple-sources/simple-simulation.cc @@ -0,0 +1,67 @@ +#include + +#include "ns3/core-module.h" +#include "ns3/helper-module.h" +#include "ns3/node-module.h" +#include "ns3/simulator-module.h" + +using namespace ns3; + +static void +GenerateTraffic (Ptr socket, uint32_t size) +{ + std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl; + socket->Send (Create (size)); + if (size > 0) + { + Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50); + } + else + { + socket->Close (); + } +} + +static void +SocketPrinter (Ptr socket) +{ + Ptr packet; + while (packet = socket->Recv ()) + { + std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet->GetSize () << std::endl; + } +} + +static void +PrintTraffic (Ptr socket) +{ + socket->SetRecvCallback (MakeCallback (&SocketPrinter)); +} + +void +RunSimulation (void) +{ + NodeContainer c; + c.Create (1); + + InternetStackHelper internet; + internet.Install (c); + + + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + Ptr sink = Socket::CreateSocket (c.Get (0), tid); + InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80); + sink->Bind (local); + + Ptr source = Socket::CreateSocket (c.Get (0), tid); + InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80); + source->Connect (remote); + + GenerateTraffic (source, 500); + PrintTraffic (sink); + + + Simulator::Run (); + + Simulator::Destroy (); +} diff --git a/scratch/simple.cc b/scratch/simple.cc new file mode 100644 index 000000000..92c6e5c36 --- /dev/null +++ b/scratch/simple.cc @@ -0,0 +1,74 @@ +#include + +#include "ns3/core-module.h" +#include "ns3/helper-module.h" +#include "ns3/node-module.h" +#include "ns3/simulator-module.h" + +using namespace ns3; + +static void +GenerateTraffic (Ptr socket, uint32_t size) +{ + std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl; + socket->Send (Create (size)); + if (size > 0) + { + Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50); + } + else + { + socket->Close (); + } +} + +static void +SocketPrinter (Ptr socket) +{ + Ptr packet; + while (packet = socket->Recv ()) + { + std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet->GetSize () << std::endl; + } +} + +static void +PrintTraffic (Ptr socket) +{ + socket->SetRecvCallback (MakeCallback (&SocketPrinter)); +} + +void +RunSimulation (void) +{ + NodeContainer c; + c.Create (1); + + InternetStackHelper internet; + internet.Install (c); + + + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + Ptr sink = Socket::CreateSocket (c.Get (0), tid); + InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80); + sink->Bind (local); + + Ptr source = Socket::CreateSocket (c.Get (0), tid); + InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80); + source->Connect (remote); + + GenerateTraffic (source, 500); + PrintTraffic (sink); + + + Simulator::Run (); + + Simulator::Destroy (); +} + +int main (int argc, char *argv[]) +{ + RunSimulation (); + + return 0; +} diff --git a/src/applications/onoff/onoff-application.cc b/src/applications/onoff/onoff-application.cc index c4f84277a..664d43e82 100644 --- a/src/applications/onoff/onoff-application.cc +++ b/src/applications/onoff/onoff-application.cc @@ -135,7 +135,7 @@ void OnOffApplication::StartApplication() // Called at time specified by Start m_socket->Connect (m_peer); } // Insure no pending event - StopApplication(); + CancelEvents (); // If we are not yet connected, there is nothing to do here // The ConnectionComplete upcall will start timers at that time //if (!m_connected) return; @@ -146,6 +146,21 @@ void OnOffApplication::StopApplication() // Called at time specified by Stop { NS_LOG_FUNCTION_NOARGS (); + CancelEvents (); + if(m_socket != 0) + { + m_socket->Close (); + } + else + { + NS_LOG_WARN("OnOffApplication found null socket to close in StopApplication"); + } +} + +void OnOffApplication::CancelEvents () +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_sendEvent.IsRunning ()) { // Cancel the pending send packet event // Calculate residual bits since last packet sent diff --git a/src/applications/onoff/onoff-application.h b/src/applications/onoff/onoff-application.h index ac79ff18b..c2344ec13 100644 --- a/src/applications/onoff/onoff-application.h +++ b/src/applications/onoff/onoff-application.h @@ -40,10 +40,25 @@ class RandomVariable; class Socket; /** + * \ingroup applications + * \defgroup onoff OnOffApplication + * + * This traffic generator follows an On/Off pattern: after + * Application::StartApplication + * is called, "On" and "Off" states alternate. The duration of each of + * these states is determined with the onTime and the offTime random + * variables. During the "Off" state, no traffic is generated. + * During the "On" state, cbr traffic is generated. This cbr traffic is + * characterized by the specified "data rate" and "packet size". + */ + /** + * \ingroup onoff + * * \brief Generate traffic to a single destination according to an * OnOff pattern. * - * This traffic follows an On/Off pattern: after Application::StartApplication + * This traffic generator follows an On/Off pattern: after + * Application::StartApplication * is called, "On" and "Off" states alternate. The duration of each of * these states is determined with the onTime and the offTime random * variables. During the "Off" state, no traffic is generated. @@ -68,6 +83,9 @@ private: virtual void StartApplication (void); // Called at time specified by Start virtual void StopApplication (void); // Called at time specified by Stop + //helpers + void CancelEvents (); + void Construct (Ptr n, const Address &remote, std::string tid, diff --git a/src/applications/packet-sink/packet-sink.cc b/src/applications/packet-sink/packet-sink.cc index d73ca1f03..507a0c371 100644 --- a/src/applications/packet-sink/packet-sink.cc +++ b/src/applications/packet-sink/packet-sink.cc @@ -33,7 +33,7 @@ using namespace std; namespace ns3 { -NS_LOG_COMPONENT_DEFINE ("PacketSinkApplication"); +NS_LOG_COMPONENT_DEFINE ("PacketSink"); NS_OBJECT_ENSURE_REGISTERED (PacketSink); TypeId @@ -58,15 +58,19 @@ PacketSink::GetTypeId (void) PacketSink::PacketSink () { + NS_LOG_FUNCTION (this); m_socket = 0; } PacketSink::~PacketSink() -{} +{ + NS_LOG_FUNCTION (this); +} void PacketSink::DoDispose (void) { + NS_LOG_FUNCTION (this); m_socket = 0; // chain up @@ -77,40 +81,44 @@ PacketSink::DoDispose (void) // Application Methods void PacketSink::StartApplication() // Called at time specified by Start { + NS_LOG_FUNCTION (this); // Create the socket if not already if (!m_socket) { m_socket = Socket::CreateSocket (GetNode(), m_tid); m_socket->Bind (m_local); - m_socket->Listen (0); + m_socket->Listen (); } m_socket->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this)); m_socket->SetAcceptCallback ( MakeNullCallback, const Address &> (), - MakeNullCallback, const Address&> (), - MakeCallback(&PacketSink::CloseConnection, this) ); + MakeCallback(&PacketSink::HandleAccept, this)); } void PacketSink::StopApplication() // Called at time specified by Stop { + NS_LOG_FUNCTION (this); + while(!m_socketList.empty()) //these are accepted sockets, close them + { + Ptr acceptedSocket = m_socketList.front(); + m_socketList.pop_front(); + acceptedSocket->Close(); + } if (m_socket) { + m_socket->Close (); m_socket->SetRecvCallback (MakeNullCallback > ()); } } void PacketSink::HandleRead (Ptr socket) { + NS_LOG_FUNCTION (this << socket); Ptr packet; - while (packet = socket->Recv ()) + Address from; + while (packet = socket->RecvFrom (from)) { - SocketRxAddressTag tag; - bool found; - found = packet->FindFirstMatchingTag (tag); - NS_ASSERT (found); - Address from = tag.GetAddress (); - // XXX packet->RemoveTag (tag); if (InetSocketAddress::IsMatchingType (from)) { InetSocketAddress address = InetSocketAddress::ConvertFrom (from); @@ -122,9 +130,11 @@ void PacketSink::HandleRead (Ptr socket) } } -void PacketSink::CloseConnection (Ptr socket) +void PacketSink::HandleAccept (Ptr s, const Address& from) { - socket->Close (); + NS_LOG_FUNCTION (this << s << from); + s->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this)); + m_socketList.push_back (s); } } // Namespace ns3 diff --git a/src/applications/packet-sink/packet-sink.h b/src/applications/packet-sink/packet-sink.h index 638309aad..f8a9a3c1a 100644 --- a/src/applications/packet-sink/packet-sink.h +++ b/src/applications/packet-sink/packet-sink.h @@ -34,6 +34,21 @@ class Socket; class Packet; /** + * \ingroup applications + * \defgroup packetsink PacketSink + * + * This application was written to complement OnOffApplication, but it + * is more general so a PacketSink name was selected. Functionally it is + * important to use in multicast situations, so that reception of the layer-2 + * multicast frames of interest are enabled, but it is also useful for + * unicast as an example of how you can write something simple to receive + * packets at the application layer. Also, if an IP stack generates + * ICMP Port Unreachable errors, receiving applications will be needed. + */ + +/** + * \ingroup packetsink + * * \brief Receive and consume traffic generated to an IP address and port * * This application was written to complement OnOffApplication, but it @@ -65,11 +80,14 @@ private: virtual void StartApplication (void); // Called at time specified by Start virtual void StopApplication (void); // Called at time specified by Stop - virtual void HandleRead (Ptr socket); + void HandleRead (Ptr socket); + void HandleAccept (Ptr, const Address& from); - virtual void CloseConnection (Ptr socket); + // In the case of TCP, each socket accept returns a new socket, so the + // listening socket is stored seperately from the accepted sockets + Ptr m_socket; // Listening socket + std::list > m_socketList; //the accepted sockets - Ptr m_socket; // Associated socket Address m_local; // Local address to bind to TypeId m_tid; // Protocol TypeId TracedCallback, const Address &> m_rxTrace; diff --git a/src/applications/udp-echo/udp-echo-client.cc b/src/applications/udp-echo/udp-echo-client.cc index 55f5bda6d..d92779aa3 100644 --- a/src/applications/udp-echo/udp-echo-client.cc +++ b/src/applications/udp-echo/udp-echo-client.cc @@ -47,8 +47,8 @@ UdpEchoClient::GetTypeId (void) TimeValue (Seconds (1.0)), MakeTimeAccessor (&UdpEchoClient::m_interval), MakeTimeChecker ()) - .AddAttribute ("RemoteIpv4", - "The Ipv4Address of the outbound packets", + .AddAttribute ("RemoteAddress", + "The destination Ipv4Address of the outbound packets", Ipv4AddressValue (), MakeIpv4AddressAccessor (&UdpEchoClient::m_peerAddress), MakeIpv4AddressChecker ()) @@ -154,14 +154,9 @@ UdpEchoClient::HandleRead (Ptr socket) { NS_LOG_FUNCTION (this << socket); Ptr packet; - while (packet = socket->Recv ()) + Address from; + while (packet = socket->RecvFrom (from)) { - SocketRxAddressTag tag; - bool found; - found = packet->FindFirstMatchingTag (tag); - NS_ASSERT (found); - Address from = tag.GetAddress (); - // XXX packet->RemoveTag (tag); if (InetSocketAddress::IsMatchingType (from)) { InetSocketAddress address = InetSocketAddress::ConvertFrom (from); diff --git a/src/applications/udp-echo/udp-echo-client.h b/src/applications/udp-echo/udp-echo-client.h index bfb1c3fcf..bea207918 100644 --- a/src/applications/udp-echo/udp-echo-client.h +++ b/src/applications/udp-echo/udp-echo-client.h @@ -30,6 +30,7 @@ class Socket; class Packet; /** + * \ingroup udpecho * \brief A Udp Echo client * * Every packet sent should be returned by the server and received here. diff --git a/src/applications/udp-echo/udp-echo-server.cc b/src/applications/udp-echo/udp-echo-server.cc index 3851a88b7..af7747c0a 100644 --- a/src/applications/udp-echo/udp-echo-server.cc +++ b/src/applications/udp-echo/udp-echo-server.cc @@ -95,22 +95,19 @@ void UdpEchoServer::HandleRead (Ptr socket) { Ptr packet; - while (packet = socket->Recv ()) + Address from; + while (packet = socket->RecvFrom (from)) { - SocketRxAddressTag tag; - bool found; - found = packet->FindFirstMatchingTag (tag); - NS_ASSERT (found); - Address from = tag.GetAddress (); - // XXX packet->RemoveTag (tag); if (InetSocketAddress::IsMatchingType (from)) { InetSocketAddress address = InetSocketAddress::ConvertFrom (from); NS_LOG_INFO ("Received " << packet->GetSize() << " bytes from " << address.GetIpv4()); + packet->RemoveAllTags (); + NS_LOG_LOGIC ("Echoing packet"); - socket->SendTo (packet, from); + socket->SendTo (packet, 0, from); } } } diff --git a/src/applications/udp-echo/udp-echo-server.h b/src/applications/udp-echo/udp-echo-server.h index 4e2b09fce..7715761c3 100644 --- a/src/applications/udp-echo/udp-echo-server.h +++ b/src/applications/udp-echo/udp-echo-server.h @@ -30,6 +30,12 @@ class Socket; class Packet; /** + * \ingroup applications + * \defgroup udpecho UdpEcho + */ + +/** + * \ingroup udpecho * \brief A Udp Echo server * * Every packet received is sent back. diff --git a/src/common/buffer.cc b/src/common/buffer.cc index 29f8c7d39..d00141f13 100644 --- a/src/common/buffer.cc +++ b/src/common/buffer.cc @@ -1105,6 +1105,35 @@ Buffer::Iterator::ReadU8 (void) #endif /* BUFFER_USE_INLINE */ +uint16_t +Buffer::Iterator::CalculateIpChecksum(uint16_t size) +{ + return CalculateIpChecksum(size, 0); +} + +uint16_t +Buffer::Iterator::CalculateIpChecksum(uint16_t size, uint32_t initialChecksum) +{ + /* see RFC 1071 to understand this code. */ + uint32_t sum = initialChecksum; + + for (int j = 0; j < size/2; j++) + sum += ReadU16 (); + + if (size & 1) + sum += ReadU8 (); + + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + return ~sum; +} + +uint32_t +Buffer::Iterator::GetSize (void) const +{ + return m_dataEnd - m_dataStart; +} + } // namespace ns3 diff --git a/src/common/buffer.h b/src/common/buffer.h index 65081f474..4c65518de 100644 --- a/src/common/buffer.h +++ b/src/common/buffer.h @@ -342,6 +342,27 @@ public: * bytes read. */ void Read (uint8_t *buffer, uint32_t size); + + /** + * \brief Calculate the checksum. + * \param size size of the buffer. + * \return checksum + */ + uint16_t CalculateIpChecksum(uint16_t size); + + /** + * \brief Calculate the checksum. + * \param size size of the buffer. + * \param initialChecksum initial value + * \return checksum + */ + uint16_t CalculateIpChecksum(uint16_t size, uint32_t initialChecksum); + + /** + * \returns the size of the underlying buffer we are iterating + */ + uint32_t GetSize (void) const; + private: friend class Buffer; Iterator (Buffer const*buffer); @@ -520,6 +541,7 @@ private: #ifdef BUFFER_USE_INLINE #include "ns3/assert.h" +#include namespace ns3 { diff --git a/src/common/data-rate.cc b/src/common/data-rate.cc index e7727dda0..61d6f6550 100644 --- a/src/common/data-rate.cc +++ b/src/common/data-rate.cc @@ -29,7 +29,10 @@ DoParse (const std::string s, uint64_t *v) std::string::size_type n = s.find_first_not_of("0123456789."); if (n != std::string::npos) { // Found non-numeric - double r = ::atof(s.substr(0, n).c_str()); + std::istringstream iss; + iss.str (s.substr(0, n)); + double r; + iss >> r; std::string trailer = s.substr(n, std::string::npos); if (trailer == "bps") { @@ -117,7 +120,9 @@ DoParse (const std::string s, uint64_t *v) } return true; } - *v = ::atoll(s.c_str()); + std::istringstream iss; + iss.str (s); + iss >> *v; return true; } diff --git a/src/common/error-model.cc b/src/common/error-model.cc index 77b5854ef..02bfac62d 100644 --- a/src/common/error-model.cc +++ b/src/common/error-model.cc @@ -178,7 +178,7 @@ bool RateErrorModel::DoCorrupt (Ptr p) { NS_LOG_FUNCTION_NOARGS (); - if (!m_enable) + if (!IsEnabled ()) { return false; } @@ -275,7 +275,7 @@ bool ListErrorModel::DoCorrupt (Ptr p) { NS_LOG_FUNCTION_NOARGS (); - if (!m_enable) + if (!IsEnabled ()) { return false; } diff --git a/src/common/error-model.h b/src/common/error-model.h index 825487750..69b04a9fa 100644 --- a/src/common/error-model.h +++ b/src/common/error-model.h @@ -72,12 +72,6 @@ class ErrorModel : public Object { public: static TypeId GetTypeId (void); - /** - * A factory method to generate a preconfigured default ErrorModel for use - * \return an ErrorModel smart pointer that is the default ErrorModel - * type defined - */ - static Ptr CreateDefault (void); ErrorModel (); virtual ~ErrorModel (); @@ -104,9 +98,6 @@ public: */ bool IsEnabled (void) const; -protected: - bool m_enable; - private: /* * These methods must be implemented by subclasses @@ -114,6 +105,7 @@ private: virtual bool DoCorrupt (Ptr) = 0; virtual void DoReset (void) = 0; + bool m_enable; }; enum ErrorUnit diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index 1b4704ab6..f8300c697 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -752,6 +752,32 @@ PacketMetadataTest::RunTests (void) p2 = p->CreateFragment(100, 100); p1->AddAtEnd (p2); + p = Create (); + ADD_HEADER (p, 10); + p1 = Create (); + ADD_HEADER (p1, 11); + REM_HEADER (p1, 11); + p->AddAtEnd (p1); + + p = Create (500); + CHECK_HISTORY (p, 1, 500); + ADD_HEADER (p, 10); + CHECK_HISTORY (p, 2, 10, 500); + REM_HEADER (p, 10); + CHECK_HISTORY (p, 1, 500); + p->RemoveAtEnd (10); + CHECK_HISTORY (p, 1, 490); + + p = Create (500); + CHECK_HISTORY (p, 1, 500); + ADD_TRAILER (p, 10); + CHECK_HISTORY (p, 2, 500, 10); + REM_TRAILER (p, 10); + CHECK_HISTORY (p, 1, 500); + p->RemoveAtStart (10); + CHECK_HISTORY (p, 1, 490); + + return result; } diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index daca275b3..810a854db 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -32,6 +32,7 @@ NS_LOG_COMPONENT_DEFINE ("PacketMetadata"); namespace ns3 { bool PacketMetadata::m_enable = false; +bool PacketMetadata::m_enableChecking = false; bool PacketMetadata::m_metadataSkipped = false; uint32_t PacketMetadata::m_maxSize = 0; uint16_t PacketMetadata::m_chunkUid = 0; @@ -59,6 +60,13 @@ PacketMetadata::Enable (void) m_enable = true; } +void +PacketMetadata::EnableChecking (void) +{ + Enable (); + m_enableChecking = true; +} + void PacketMetadata::ReserveCopy (uint32_t size) { @@ -630,13 +638,21 @@ PacketMetadata::RemoveHeader (const Header &header, uint32_t size) if ((item.typeUid & 0xfffffffe) != uid || item.size != size) { - NS_FATAL_ERROR ("Removing unexpected header."); + if (m_enableChecking) + { + NS_FATAL_ERROR ("Removing unexpected header."); + } + return; } else if (item.typeUid != uid && (extraItem.fragmentStart != 0 || extraItem.fragmentEnd != size)) { - NS_FATAL_ERROR ("Removing incomplete header."); + if (m_enableChecking) + { + NS_FATAL_ERROR ("Removing incomplete header."); + } + return; } if (m_head + read == m_used) { @@ -688,13 +704,21 @@ PacketMetadata::RemoveTrailer (const Trailer &trailer, uint32_t size) if ((item.typeUid & 0xfffffffe) != uid || item.size != size) { - NS_FATAL_ERROR ("Removing unexpected trailer."); + if (m_enableChecking) + { + NS_FATAL_ERROR ("Removing unexpected trailer."); + } + return; } else if (item.typeUid != uid && (extraItem.fragmentStart != 0 || extraItem.fragmentEnd != size)) { - NS_FATAL_ERROR ("Removing incomplete trailer."); + if (m_enableChecking) + { + NS_FATAL_ERROR ("Removing incomplete trailer."); + } + return; } if (m_tail + read == m_used) { @@ -726,6 +750,12 @@ PacketMetadata::AddAtEnd (PacketMetadata const&o) *this = o; return; } + if (o.m_head == 0xffff) + { + NS_ASSERT (o.m_tail == 0xffff); + // we have nothing to append. + return; + } NS_ASSERT (m_head != 0xffff && m_tail != 0xffff); // We read the current tail because we are going to append @@ -824,18 +854,13 @@ PacketMetadata::RemoveAtStart (uint32_t start) uint16_t written = fragment.AddBig (0xffff, fragment.m_tail, &item, &extraItem); fragment.UpdateTail (written); - current = item.next; - while (current != 0xffff) + while (current != 0xffff && current != m_tail) { + current = item.next; ReadItems (current, &item, &extraItem); written = fragment.AddBig (0xffff, fragment.m_tail, &item, &extraItem); fragment.UpdateTail (written); - if (current == m_tail) - { - break; - } - current = item.next; } *this = fragment; } @@ -892,18 +917,13 @@ PacketMetadata::RemoveAtEnd (uint32_t end) uint16_t written = fragment.AddBig (fragment.m_head, 0xffff, &item, &extraItem); fragment.UpdateHead (written); - current = item.prev; - while (current != 0xffff) + while (current != 0xffff && current != m_head) { + current = item.prev; ReadItems (current, &item, &extraItem); written = fragment.AddBig (fragment.m_head, 0xffff, &item, &extraItem); fragment.UpdateHead (written); - if (current == m_head) - { - break; - } - current = item.prev; } *this = fragment; } @@ -1005,9 +1025,10 @@ PacketMetadata::ItemIterator::Next (void) item.type = PacketMetadata::Item::HEADER; if (!item.isFragment) { - ns3::Buffer::Iterator j = m_buffer.Begin (); - j.Next (m_offset); - item.current = j; + ns3::Buffer tmp = m_buffer; + tmp.RemoveAtStart (m_offset); + tmp.RemoveAtEnd (tmp.GetSize () - item.currentSize); + item.current = tmp.Begin (); } } else if (tid.IsChildOf (Trailer::GetTypeId ())) @@ -1015,9 +1036,10 @@ PacketMetadata::ItemIterator::Next (void) item.type = PacketMetadata::Item::TRAILER; if (!item.isFragment) { - ns3::Buffer::Iterator j = m_buffer.End (); - j.Prev (m_buffer.GetSize () - (m_offset + smallItem.size)); - item.current = j; + ns3::Buffer tmp = m_buffer; + tmp.RemoveAtEnd (tmp.GetSize () - (m_offset + smallItem.size)); + tmp.RemoveAtStart (tmp.GetSize () - item.currentSize); + item.current = tmp.End (); } } else diff --git a/src/common/packet-metadata.h b/src/common/packet-metadata.h index 6358cb7de..a2d5228fc 100644 --- a/src/common/packet-metadata.h +++ b/src/common/packet-metadata.h @@ -125,6 +125,7 @@ public: }; static void Enable (void); + static void EnableChecking (void); inline PacketMetadata (uint32_t uid, uint32_t size); inline PacketMetadata (PacketMetadata const &o); @@ -137,6 +138,13 @@ public: void AddTrailer (Trailer const &trailer, uint32_t size); void RemoveTrailer (Trailer const &trailer, uint32_t size); + /** + * \param start the amount of stuff to remove from the start + * \param end the amount of stuff to remove from the end + * + * Calling this method is equivalent to calling RemoveAtStart (start) + * and then, RemoveAtEnd (end). + */ PacketMetadata CreateFragment (uint32_t start, uint32_t end) const; void AddAtEnd (PacketMetadata const&o); void AddPaddingAtEnd (uint32_t end); @@ -149,8 +157,6 @@ public: void Serialize (Buffer::Iterator i, uint32_t size) const; uint32_t Deserialize (Buffer::Iterator i); - static void PrintStats (void); - ItemIterator BeginItem (Buffer buffer) const; private: @@ -272,6 +278,7 @@ private: static DataFreeList m_freeList; static bool m_enable; + static bool m_enableChecking; // set to true when adding metadata to a packet is skipped because // m_enable is false; used to detect enabling of metadata in the diff --git a/src/common/packet.cc b/src/common/packet.cc index b2c2fd896..a5f5e3993 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -199,6 +199,13 @@ Packet::RemoveHeader (Header &header) m_metadata.RemoveHeader (header, deserialized); return deserialized; } +uint32_t +Packet::PeekHeader (Header &header) const +{ + NS_LOG_FUNCTION (this << &header); + uint32_t deserialized = header.Deserialize (m_buffer.Begin ()); + return deserialized; +} void Packet::AddTrailer (const Trailer &trailer) { @@ -224,6 +231,13 @@ Packet::RemoveTrailer (Trailer &trailer) m_metadata.RemoveTrailer (trailer, deserialized); return deserialized; } +uint32_t +Packet::PeekTrailer (Trailer &trailer) +{ + NS_LOG_FUNCTION (this << &trailer); + uint32_t deserialized = trailer.Deserialize (m_buffer.End ()); + return deserialized; +} void Packet::AddAtEnd (Ptr packet) @@ -282,6 +296,19 @@ Packet::PeekData (void) const return m_buffer.PeekData (); } +uint32_t +Packet::CopyData (uint8_t *buffer, uint32_t size) const +{ + Buffer::Iterator i = m_buffer.Begin (); + uint32_t cur = 0; + while (!i.IsEnd () && cur < size) + { + buffer[cur] = i.ReadU8 (); + cur++; + } + return cur; +} + uint32_t Packet::GetUid (void) const { @@ -443,11 +470,25 @@ Packet::BeginItem (void) const void Packet::EnableMetadata (void) +{ + NS_LOG_FUNCTION_NOARGS (); + EnableChecking (); +} + +void +Packet::EnablePrinting (void) { NS_LOG_FUNCTION_NOARGS (); PacketMetadata::Enable (); } +void +Packet::EnableChecking (void) +{ + NS_LOG_FUNCTION_NOARGS (); + PacketMetadata::EnableChecking (); +} + Buffer Packet::Serialize (void) const { @@ -727,10 +768,7 @@ struct Expected #define E(a,b,c) a,b,c #define CHECK(p, n, ...) \ - if (!DoCheck (p, __FILE__, __LINE__, n, __VA_ARGS__)) \ - { \ - result = false; \ - } + NS_TEST_ASSERT (DoCheck (p, __FILE__, __LINE__, n, __VA_ARGS__)) namespace ns3 { @@ -782,6 +820,8 @@ PacketTest::DoCheck (Ptr p, const char *file, int line, uint32_t n delete tag; j++; } + NS_TEST_ASSERT (!i.HasNext ()); + NS_TEST_ASSERT_EQUAL (j, expected.size ()); return result; } @@ -887,6 +927,36 @@ PacketTest::RunTests (void) CHECK (tmp, 1, E (20, 0, 100)); } + + { + Ptr tmp = Create (0); + tmp->AddHeader (ATestHeader<156> ()); + tmp->AddTag (ATestTag<20> ()); + CHECK (tmp, 1, E (20, 0, 156)); + tmp->RemoveAtStart (120); + CHECK (tmp, 1, E (20, 0, 36)); + Ptr a = Create (0); + a->AddAtEnd (tmp); + CHECK (a, 1, E (20, 0, 36)); + } + + { + Ptr tmp = Create (0); + tmp->AddTag (ATestTag<20> ()); + CHECK (tmp, 0, E (20, 0, 0)); + } + { + Ptr tmp = Create (1000); + tmp->AddTag (ATestTag<20> ()); + CHECK (tmp, 1, E (20, 0, 1000)); + tmp->RemoveAtStart (1000); + CHECK (tmp, 0, E (0,0,0)); + Ptr a = Create (10); + a->AddTag (ATestTag<10> ()); + CHECK (a, 1, E (10, 0, 10)); + tmp->AddAtEnd (a); + CHECK (tmp, 1, E (10, 0, 10)); + } return result; diff --git a/src/common/packet.h b/src/common/packet.h index f7bb58329..9b0aba9e9 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -30,6 +30,7 @@ #include "ns3/callback.h" #include "ns3/assert.h" #include "ns3/ptr.h" +#include "ns3/deprecated.h" namespace ns3 { @@ -187,7 +188,7 @@ public: uint32_t GetSize (void) const; /** * Add header to this packet. This method invokes the - * GetSerializedSize and Serialize + * Header::GetSerializedSize and Header::Serialize * methods to reserve space in the buffer and request the * header to serialize itself in the packet buffer. * @@ -196,15 +197,23 @@ public: void AddHeader (const Header & header); /** * Deserialize and remove the header from the internal buffer. - * This method invokes Deserialize. + * This method invokes Header::Deserialize. * * \param header a reference to the header to remove from the internal buffer. * \returns the number of bytes removed from the packet. */ uint32_t RemoveHeader (Header &header); + /** + * Deserialize but does _not_ remove the header from the internal buffer. + * This method invokes Header::Deserialize. + * + * \param header a reference to the header to read from the internal buffer. + * \returns the number of bytes read from the packet. + */ + uint32_t PeekHeader (Header &header) const; /** * Add trailer to this packet. This method invokes the - * GetSerializedSize and Serialize + * Trailer::GetSerializedSize and Trailer::Serialize * methods to reserve space in the buffer and request the trailer * to serialize itself in the packet buffer. * @@ -219,6 +228,14 @@ public: * \returns the number of bytes removed from the end of the packet. */ uint32_t RemoveTrailer (Trailer &trailer); + /** + * Deserialize but does _not_ remove a trailer from the internal buffer. + * This method invokes the Trailer::Deserialize method. + * + * \param trailer a reference to the trailer to read from the internal buffer. + * \returns the number of bytes read from the end of the packet. + */ + uint32_t PeekTrailer (Trailer &trailer); /** * \param os output stream in which the data should be printed. * @@ -263,6 +280,16 @@ public: */ uint8_t const *PeekData (void) const; + /** + * \param buffer a pointer to a byte buffer where the packet data + * should be copied. + * \param size the size of the byte buffer. + * \returns the number of bytes read from the packet + * + * No more than \b size bytes will be copied by this function. + */ + uint32_t CopyData (uint8_t *buffer, uint32_t size) const; + /** * A packet is allocated a new uid when it is created * empty or with zero-filled payload. @@ -294,13 +321,17 @@ public: PacketMetadata::ItemIterator BeginItem (void) const; + static void EnableMetadata (void) NS_DEPRECATED; + /** * By default, packets do not keep around enough metadata to * perform the operations requested by the Print methods. If you * want to be able to invoke any of the two ::Print methods, * you need to invoke this method at least once during the * simulation setup and before any packet is created. - * + */ + static void EnablePrinting (void); + /** * The packet metadata is also used to perform extensive * sanity checks at runtime when performing operations on a * Packet. For example, this metadata is used to verify that @@ -308,7 +339,7 @@ public: * was actually present at the front of the packet. These * errors will be detected and will abort the program. */ - static void EnableMetadata (void); + static void EnableChecking (void); /** * \returns a byte buffer @@ -416,6 +447,7 @@ std::ostream& operator<< (std::ostream& os, const Packet &packet); * - ns3::Packet::CreateFragment * - ns3::Packet::RemoveAtStart * - ns3::Packet::RemoveAtEnd + * - ns3::Packet::CopyData * * Dirty operations will always be slower than non-dirty operations, * sometimes by several orders of magnitude. However, even the diff --git a/src/common/tag-list.cc b/src/common/tag-list.cc index 13587c21d..fac9ef020 100644 --- a/src/common/tag-list.cc +++ b/src/common/tag-list.cc @@ -20,11 +20,13 @@ #include "tag-list.h" #include "ns3/log.h" #include +#include NS_LOG_COMPONENT_DEFINE ("TagList"); #define USE_FREE_LIST 1 #define FREE_LIST_SIZE 1000 +#define OFFSET_MAX (2147483647) namespace ns3 { @@ -70,10 +72,8 @@ TagList::Iterator::Next (void) struct Item item = Item (TagBuffer (m_current+16, m_end)); item.tid.SetUid (m_nextTid); item.size = m_nextSize; - item.start = m_nextStart; - item.end = m_nextEnd; - item.start = std::max (item.start, m_offsetStart); - item.end = std::min (item.end, m_offsetEnd); + item.start = std::max (m_nextStart, m_offsetStart); + item.end = std::min (m_nextEnd, m_offsetEnd); m_current += 4 + 4 + 4 + 4 + item.size; item.buf.TrimAtEnd (m_end - m_current); PrepareForNext (); @@ -89,7 +89,7 @@ TagList::Iterator::PrepareForNext (void) m_nextSize = buf.ReadU32 (); m_nextStart = buf.ReadU32 (); m_nextEnd = buf.ReadU32 (); - if (m_nextStart > m_offsetEnd || m_nextEnd < m_offsetStart) + if (m_nextStart >= m_offsetEnd || m_nextEnd <= m_offsetStart) { m_current += 4 + 4 + 4 + 4 + m_nextSize; } @@ -99,7 +99,7 @@ TagList::Iterator::PrepareForNext (void) } } } -TagList::Iterator::Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd) +TagList::Iterator::Iterator (uint8_t *start, uint8_t *end, int32_t offsetStart, int32_t offsetEnd) : m_current (start), m_end (end), m_offsetStart (offsetStart), @@ -158,7 +158,7 @@ TagList::~TagList () } TagBuffer -TagList::Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end) +TagList::Add (TypeId tid, uint32_t bufferSize, int32_t start, int32_t end) { NS_LOG_FUNCTION (this << tid << bufferSize << start << end); uint32_t spaceNeeded = m_used + bufferSize + 4 + 4 + 4 + 4; @@ -191,7 +191,7 @@ void TagList::Add (const TagList &o) { NS_LOG_FUNCTION (this << &o); - TagList::Iterator i = o.Begin (0, 0xffffffff); + TagList::Iterator i = o.BeginAll (); while (i.HasNext ()) { TagList::Iterator::Item item = i.Next (); @@ -210,7 +210,16 @@ TagList::RemoveAll (void) } TagList::Iterator -TagList::Begin (uint32_t offsetStart, uint32_t offsetEnd) const +TagList::BeginAll (void) const +{ + NS_LOG_FUNCTION (this); + // I am not totally sure but I might need to use + // INT32_MIN instead of zero below. + return Begin (0, OFFSET_MAX); +} + +TagList::Iterator +TagList::Begin (int32_t offsetStart, int32_t offsetEnd) const { NS_LOG_FUNCTION (this << offsetStart << offsetEnd); if (m_data == 0) @@ -224,10 +233,10 @@ TagList::Begin (uint32_t offsetStart, uint32_t offsetEnd) const } bool -TagList::IsDirtyAtEnd (uint32_t appendOffset) +TagList::IsDirtyAtEnd (int32_t appendOffset) { NS_LOG_FUNCTION (this << appendOffset); - TagList::Iterator i = Begin (0, 0xffffffff); + TagList::Iterator i = BeginAll (); while (i.HasNext ()) { TagList::Iterator::Item item = i.Next (); @@ -240,10 +249,10 @@ TagList::IsDirtyAtEnd (uint32_t appendOffset) } bool -TagList::IsDirtyAtStart (uint32_t prependOffset) +TagList::IsDirtyAtStart (int32_t prependOffset) { NS_LOG_FUNCTION (this << prependOffset); - TagList::Iterator i = Begin (0, 0xffffffff); + TagList::Iterator i = BeginAll (); while (i.HasNext ()) { TagList::Iterator::Item item = i.Next (); @@ -256,7 +265,7 @@ TagList::IsDirtyAtStart (uint32_t prependOffset) } void -TagList::AddAtEnd (int32_t adjustment, uint32_t appendOffset) +TagList::AddAtEnd (int32_t adjustment, int32_t appendOffset) { NS_LOG_FUNCTION (this << adjustment << appendOffset); if (adjustment == 0 && !IsDirtyAtEnd (appendOffset)) @@ -264,14 +273,14 @@ TagList::AddAtEnd (int32_t adjustment, uint32_t appendOffset) return; } TagList list; - TagList::Iterator i = Begin (0, 0xffffffff); + TagList::Iterator i = BeginAll (); while (i.HasNext ()) { TagList::Iterator::Item item = i.Next (); item.start += adjustment; item.end += adjustment; - if (item.start > appendOffset) + if (item.start >= appendOffset) { continue; } @@ -290,7 +299,7 @@ TagList::AddAtEnd (int32_t adjustment, uint32_t appendOffset) } void -TagList::AddAtStart (int32_t adjustment, uint32_t prependOffset) +TagList::AddAtStart (int32_t adjustment, int32_t prependOffset) { NS_LOG_FUNCTION (this << adjustment << prependOffset); if (adjustment == 0 && !IsDirtyAtStart (prependOffset)) @@ -298,14 +307,14 @@ TagList::AddAtStart (int32_t adjustment, uint32_t prependOffset) return; } TagList list; - TagList::Iterator i = Begin (0, 0xffffffff); + TagList::Iterator i = BeginAll (); while (i.HasNext ()) { TagList::Iterator::Item item = i.Next (); item.start += adjustment; item.end += adjustment; - if (item.end < prependOffset) + if (item.end <= prependOffset) { continue; } diff --git a/src/common/tag-list.h b/src/common/tag-list.h index 76a659e91..c21e515c6 100644 --- a/src/common/tag-list.h +++ b/src/common/tag-list.h @@ -76,8 +76,8 @@ public: { TypeId tid; uint32_t size; - uint32_t start; - uint32_t end; + int32_t start; + int32_t end; TagBuffer buf; Item (TagBuffer buf); private: @@ -89,16 +89,16 @@ public: uint32_t GetOffsetStart (void) const; private: friend class TagList; - Iterator (uint8_t *start, uint8_t *end, uint32_t offsetStart, uint32_t offsetEnd); + Iterator (uint8_t *start, uint8_t *end, int32_t offsetStart, int32_t offsetEnd); void PrepareForNext (void); uint8_t *m_current; uint8_t *m_end; - uint32_t m_offsetStart; - uint32_t m_offsetEnd; + int32_t m_offsetStart; + int32_t m_offsetEnd; uint32_t m_nextTid; uint32_t m_nextSize; - uint32_t m_nextStart; - uint32_t m_nextEnd; + int32_t m_nextStart; + int32_t m_nextEnd; }; TagList (); @@ -116,7 +116,7 @@ public: * * */ - TagBuffer Add (TypeId tid, uint32_t bufferSize, uint32_t start, uint32_t end); + TagBuffer Add (TypeId tid, uint32_t bufferSize, int32_t start, int32_t end); /** * \param o the other list of tags to aggregate. @@ -138,24 +138,25 @@ public: * in this list: the boundaries of each tag as reported by their start and * end offsets will be included within the input offsetStart and offsetEnd. */ - TagList::Iterator Begin (uint32_t offsetStart, uint32_t offsetEnd) const; + TagList::Iterator Begin (int32_t offsetStart, int32_t offsetEnd) const; /** * Adjust the offsets stored internally by the adjustment delta and * make sure that all offsets are smaller than appendOffset which represents * the location where new bytes have been added to the byte buffer. */ - void AddAtEnd (int32_t adjustment, uint32_t appendOffset); + void AddAtEnd (int32_t adjustment, int32_t appendOffset); /** * Adjust the offsets stored internally by the adjustment delta and * make sure that all offsets are bigger than prependOffset which represents * the location where new bytes have been added to the byte buffer. */ - void AddAtStart (int32_t adjustment, uint32_t prependOffset); + void AddAtStart (int32_t adjustment, int32_t prependOffset); private: - bool IsDirtyAtEnd (uint32_t appendOffset); - bool IsDirtyAtStart (uint32_t prependOffset); + bool IsDirtyAtEnd (int32_t appendOffset); + bool IsDirtyAtStart (int32_t prependOffset); + TagList::Iterator BeginAll (void) const; struct TagListData *Allocate (uint32_t size); void Deallocate (struct TagListData *data); diff --git a/src/contrib/config-store.cc b/src/contrib/config-store.cc index 55f9d7070..d4250bb50 100644 --- a/src/contrib/config-store.cc +++ b/src/contrib/config-store.cc @@ -8,6 +8,7 @@ #include #include #include +#include NS_LOG_COMPONENT_DEFINE ("ConfigStore"); diff --git a/src/contrib/contrib.h b/src/contrib/contrib.h index aec8ba6a2..127e09834 100644 --- a/src/contrib/contrib.h +++ b/src/contrib/contrib.h @@ -1,5 +1,18 @@ /** * \addtogroup contrib Contrib * + * The src/contrib directory is for contributed code that is being maintained + * by the authors, but is not yet part of the main tree. + * For instance, the developers may be requesting feedback on whether anyone + * thinks the contributed model is generally useful to maintain in the main + * tree, or may want feedback on the API or features. If you find the + * code in this directory useful, please let the ns-3 developers know. + * Code may migrate from this directory to the main tree, or may be + * removed due to lack of interest, for a later release. + * * - A class to generate graphs with gnuplot: ns3::Gnuplot and ns3::GnuplotDataset + * - A class to hold configuration data: ns3::ConfigStore and methods to allow the configuration to be read from and written to a file + * - A graphical editor of the config store: ns3::GtkConfigStore + * - An object that garbage collects events: ns3::EventGarbageCollector + * - An object that provides "quick and dirty" delay and jitter estimation: ns3::DelayJitterEstimation */ diff --git a/src/contrib/gnuplot.h b/src/contrib/gnuplot.h index da928307d..ff1b2b7fb 100644 --- a/src/contrib/gnuplot.h +++ b/src/contrib/gnuplot.h @@ -94,15 +94,6 @@ public: * Use this method with error bar style X or Y. */ void Add (double x, double y, double errorDelta); - /** - * \param x x coord to new data point - * \param y y coord to new data point - * \param errorDeltaX x delta for the new data point - * \param errorDeltaY y delta for the new data point - * - * Use this method with error bar style XY. - */ - void Add (double x, double y, double errorDeltaX, double errorDeltaY); private: friend class Gnuplot; struct Data { diff --git a/src/contrib/gtk-config-store.cc b/src/contrib/gtk-config-store.cc index 966900a03..996e08f88 100644 --- a/src/contrib/gtk-config-store.cc +++ b/src/contrib/gtk-config-store.cc @@ -65,7 +65,7 @@ void ModelCreator::Build (GtkTreeStore *treestore) { m_treestore = treestore; - m_iters.push_back (NULL); + m_iters.push_back (0); Iterate (); NS_ASSERT (m_iters.size () == 1); } @@ -177,13 +177,13 @@ cell_data_function_col_1 (GtkTreeViewColumn *col, { StringValue str; node->object->GetAttribute (node->name, str); - g_object_set(renderer, "text", str.Get ().c_str (), NULL); - g_object_set(renderer, "editable", TRUE, NULL); + g_object_set(renderer, "text", str.Get ().c_str (), (char*)0); + g_object_set(renderer, "editable", TRUE, (char*)0); } else { - g_object_set(renderer, "text", "", NULL); - g_object_set(renderer, "editable", FALSE, NULL); + g_object_set(renderer, "text", "", (char*)0); + g_object_set(renderer, "editable", FALSE, (char*)0); } } @@ -196,24 +196,24 @@ cell_data_function_col_0 (GtkTreeViewColumn *col, { ModelNode *node; gtk_tree_model_get (model, iter, COL_NODE, &node, -1); - g_object_set (renderer, "editable", FALSE, NULL); + g_object_set (renderer, "editable", FALSE, (char*)0); switch (node->type) { case ModelNode::NODE_OBJECT: - g_object_set(renderer, "text", node->object->GetInstanceTypeId ().GetName ().c_str (), NULL); + g_object_set(renderer, "text", node->object->GetInstanceTypeId ().GetName ().c_str (), (char*)0); break; case ModelNode::NODE_POINTER: - g_object_set(renderer, "text", node->name.c_str (), NULL); + g_object_set(renderer, "text", node->name.c_str (), (char*)0); break; case ModelNode::NODE_VECTOR: - g_object_set(renderer, "text", node->name.c_str (), NULL); + g_object_set(renderer, "text", node->name.c_str (), (char*)0); break; case ModelNode::NODE_VECTOR_ITEM: { std::stringstream oss; oss << node->index; - g_object_set(renderer, "text", oss.str ().c_str (), NULL); + g_object_set(renderer, "text", oss.str ().c_str (), (char*)0); } break; case ModelNode::NODE_ATTRIBUTE: - g_object_set(renderer, "text", node->name.c_str (), NULL); + g_object_set(renderer, "text", node->name.c_str (), (char*)0); break; } } @@ -239,8 +239,8 @@ get_col_number_from_tree_view_column (GtkTreeViewColumn *col) { GList *cols; int num; - g_return_val_if_fail ( col != NULL, -1 ); - g_return_val_if_fail ( col->tree_view != NULL, -1 ); + g_return_val_if_fail ( col != 0, -1 ); + g_return_val_if_fail ( col->tree_view != 0, -1 ); cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(col->tree_view)); num = g_list_index(cols, (gpointer) col); g_list_free(cols); @@ -260,12 +260,12 @@ cell_tooltip_callback (GtkWidget *widget, GtkTreeViewColumn * column; if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y, keyboard_tip, - &model, NULL, &iter)) + &model, 0, &iter)) { return FALSE; } if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), - x, y, NULL, &column, NULL, NULL)) + x, y, 0, &column, 0, 0)) { return FALSE; } @@ -349,8 +349,8 @@ create_view (GtkTreeStore *model) GtkWidget *view; view = gtk_tree_view_new(); - g_object_set (view, "has-tooltip", TRUE, NULL); - g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback, NULL); + g_object_set (view, "has-tooltip", TRUE, (char*)0); + g_signal_connect (view, "query-tooltip", (GCallback) cell_tooltip_callback, 0); gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); @@ -360,8 +360,8 @@ create_view (GtkTreeStore *model) gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start(col, renderer, TRUE); - gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_0, NULL, NULL); - g_object_set(renderer, "editable", FALSE, NULL); + gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_0, 0, 0); + g_object_set(renderer, "editable", FALSE, (char*)0); col = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col, "Attribute Value"); @@ -369,7 +369,7 @@ create_view (GtkTreeStore *model) renderer = gtk_cell_renderer_text_new(); g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, model); gtk_tree_view_column_pack_start(col, renderer, TRUE); - gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_1, NULL, NULL); + gtk_tree_view_column_set_cell_data_func(col, renderer, cell_data_function_col_1, 0, 0); gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL (model)); @@ -392,7 +392,7 @@ save_clicked (GtkButton *button, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); + (char *)0); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "config.txt"); @@ -426,7 +426,7 @@ load_clicked (GtkButton *button, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); + (char *)0); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { @@ -452,6 +452,7 @@ exit_clicked_callback (GtkButton *button, gpointer user_data) { gtk_main_quit (); + gtk_widget_hide (GTK_WIDGET (user_data)); } static gboolean @@ -460,6 +461,7 @@ delete_event_callback (GtkWidget *widget, gpointer user_data) { gtk_main_quit (); + gtk_widget_hide (GTK_WIDGET (user_data)); return TRUE; } @@ -475,7 +477,7 @@ clean_model_callback (GtkTreeModel *model, -1); delete node; gtk_tree_store_set (GTK_TREE_STORE (model), iter, - COL_NODE, NULL, + COL_NODE, (ModelNode*)0, -1); return FALSE; } @@ -494,9 +496,9 @@ GtkConfigStore::Configure (void) window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "ns-3 Object attributes."); - gtk_window_set_default_size (GTK_WINDOW (window), 400, 600); + gtk_window_set_default_size (GTK_WINDOW (window), 600, 600); - g_signal_connect (window, "delete_event", (GCallback)delete_event_callback, NULL); + g_signal_connect (window, "delete_event", (GCallback)delete_event_callback, window); GtkTreeStore *model = gtk_tree_store_new (COL_LAST, G_TYPE_POINTER); @@ -504,7 +506,7 @@ GtkConfigStore::Configure (void) creator.Build (model); view = create_view (model); - scroll = gtk_scrolled_window_new (NULL, NULL); + scroll = gtk_scrolled_window_new (0, 0); gtk_container_add (GTK_CONTAINER (scroll), view); GtkWidget *vbox = gtk_vbox_new (FALSE, 5); @@ -518,8 +520,8 @@ GtkConfigStore::Configure (void) GtkWidget *load = gtk_button_new_with_label ("Load"); g_signal_connect (load, "clicked", (GCallback) load_clicked, window); gtk_box_pack_end (GTK_BOX (hbox), load, FALSE, FALSE, 0); - GtkWidget *exit = gtk_button_new_with_label ("Exit"); - g_signal_connect (exit, "clicked", (GCallback) exit_clicked_callback, NULL); + GtkWidget *exit = gtk_button_new_with_label ("Run Simulation"); + g_signal_connect (exit, "clicked", (GCallback) exit_clicked_callback, window); gtk_box_pack_end (GTK_BOX (hbox), exit, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); @@ -530,7 +532,7 @@ GtkConfigStore::Configure (void) gtk_tree_model_foreach (GTK_TREE_MODEL (model), clean_model_callback, - NULL); + 0); gtk_widget_destroy (window); } diff --git a/src/contrib/gtk-config-store.h b/src/contrib/gtk-config-store.h index c1a16408a..9b7cf7bbf 100644 --- a/src/contrib/gtk-config-store.h +++ b/src/contrib/gtk-config-store.h @@ -3,6 +3,9 @@ namespace ns3 { +/** + * \brief A class that provides a GTK-based front end to ns3::ConfigStore + */ class GtkConfigStore { public: diff --git a/src/contrib/stats/basic-data-calculators.h b/src/contrib/stats/basic-data-calculators.h new file mode 100644 index 000000000..8968047ee --- /dev/null +++ b/src/contrib/stats/basic-data-calculators.h @@ -0,0 +1,189 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __BASIC_DATA_CALCULATORS_H__ +#define __BASIC_DATA_CALCULATORS_H__ + +#include "data-calculator.h" +#include "data-output-interface.h" + +namespace ns3 { + + //------------------------------------------------------------ + //-------------------------------------------- + template + class MinMaxAvgTotalCalculator : public DataCalculator { + public: + MinMaxAvgTotalCalculator(); + virtual ~MinMaxAvgTotalCalculator(); + + void Update(const T i); + + virtual void Output(DataOutputCallback &callback) const; + + protected: + virtual void DoDispose(void); + + uint32_t m_count; + T m_total, m_min, m_max; + + // end MinMaxAvgTotalCalculator + }; + + //---------------------------------------------- + template + MinMaxAvgTotalCalculator::MinMaxAvgTotalCalculator() + { + m_count = 0; + m_total = 0; + m_min = ~0; + m_max = 0; + } + + template + MinMaxAvgTotalCalculator::~MinMaxAvgTotalCalculator() + { + } + template + void + MinMaxAvgTotalCalculator::DoDispose(void) + { + DataCalculator::DoDispose(); + // MinMaxAvgTotalCalculator::DoDispose + } + + template + void + MinMaxAvgTotalCalculator::Update(const T i) + { + if (m_enabled) { + m_total += i; + + if (i < m_min) + m_min = i; + + if (i > m_max) + m_max = i; + + m_count++; + } + // end MinMaxAvgTotalCalculator::Update + } + template + void + MinMaxAvgTotalCalculator::Output(DataOutputCallback &callback) const + { + callback.OutputSingleton(m_key, "count", m_count); + if (m_count > 0) { + callback.OutputSingleton(m_key, "total", m_total); + callback.OutputSingleton(m_key, "average", m_total/m_count); + callback.OutputSingleton(m_key, "max", m_max); + callback.OutputSingleton(m_key, "min", m_min); + } + // end MinMaxAvgTotalCalculator::Output + } + + + + + //------------------------------------------------------------ + //-------------------------------------------- + template + class CounterCalculator : public DataCalculator { + public: + CounterCalculator(); + virtual ~CounterCalculator(); + + void Update(); + void Update(const T i); + + T GetCount() const; + + virtual void Output(DataOutputCallback &callback) const; + + protected: + virtual void DoDispose(void); + + T m_count; + + // end CounterCalculator + }; + + + //-------------------------------------------- + template + CounterCalculator::CounterCalculator() : + m_count(0) + { + } + + template + CounterCalculator::~CounterCalculator() + { + } + template + void + CounterCalculator::DoDispose(void) + { + DataCalculator::DoDispose(); + // CounterCalculator::DoDispose + } + + template + void + CounterCalculator::Update() + { + if (m_enabled) { + m_count++; + } + // end CounterCalculator::Update + } + + template + void + CounterCalculator::Update(const T i) + { + if (m_enabled) { + m_count += i; + } + // end CounterCalculator::Update + } + + template + T + CounterCalculator::GetCount() const + { + return m_count; + // end CounterCalculator::GetCount + } + + template + void + CounterCalculator::Output(DataOutputCallback &callback) const + { + callback.OutputSingleton(m_key, "count", m_count); + // end CounterCalculator::Output + } + + // end namespace ns3 +}; + + +#endif // __BASIC_DATA_CALCULATORS_H__ diff --git a/src/contrib/stats/data-calculator.cc b/src/contrib/stats/data-calculator.cc new file mode 100644 index 000000000..e96c6d591 --- /dev/null +++ b/src/contrib/stats/data-calculator.cc @@ -0,0 +1,110 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#include "ns3/log.h" +#include "ns3/simulator.h" + +#include "data-calculator.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("DataCalculator"); + + +//-------------------------------------------------------------- +//---------------------------------------------- +DataCalculator::DataCalculator() : + m_enabled(true) +{ + NS_LOG_FUNCTION_NOARGS(); +} + +DataCalculator::~DataCalculator() +{ + NS_LOG_FUNCTION_NOARGS(); +} + +void +DataCalculator::DoDispose(void) +{ + NS_LOG_FUNCTION_NOARGS(); + + Simulator::Cancel(m_startEvent); + Simulator::Cancel(m_stopEvent); + + Object::DoDispose(); + // DataCalculator::DoDispose +} + +//---------------------------------------------- +void +DataCalculator::SetKey(const std::string key) +{ + m_key = key; + // end DataCalculator::SetKey +} + +std::string +DataCalculator::GetKey() const +{ + return m_key; + // end DataCalculator::GetKey +} + +//---------------------------------------------- +void +DataCalculator::Enable() +{ + m_enabled = true; + // end DataCalculator::Enable +} + +void +DataCalculator::Disable() +{ + m_enabled = false; + // end DataCalculator::Disable +} + +bool +DataCalculator::GetEnabled() const +{ + return m_enabled; + // end DataCalculator::GetEnabled +} + +//---------------------------------------------- +void +DataCalculator::Start(const Time& startTime) +{ + + m_startEvent = Simulator::Schedule(startTime, + &DataCalculator::Enable, this); + + // end DataCalculator::Start +} + +void +DataCalculator::Stop(const Time& stopTime) +{ + m_stopEvent = Simulator::Schedule(stopTime, + &DataCalculator::Disable, this); + // end DataCalculator::Stop +} diff --git a/src/contrib/stats/data-calculator.h b/src/contrib/stats/data-calculator.h new file mode 100644 index 000000000..70ed3bb72 --- /dev/null +++ b/src/contrib/stats/data-calculator.h @@ -0,0 +1,70 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __DATA_CALCULATOR_H__ +#define __DATA_CALCULATOR_H__ + +#include "ns3/object.h" +#include "ns3/nstime.h" +#include "ns3/simulator.h" + +namespace ns3 { + + class DataOutputCallback; + + //------------------------------------------------------------ + //-------------------------------------------- + class DataCalculator : public Object { + public: + DataCalculator(); + virtual ~DataCalculator(); + + bool GetEnabled() const; + void Enable(); + void Disable(); + + void SetKey(const std::string key); + std::string GetKey() const; + + virtual void Start(const Time& startTime); + virtual void Stop(const Time& stopTime); + + virtual void Output(DataOutputCallback &callback) const = 0; + + protected: + bool m_enabled; // Descendant classes *must* check & respect m_enabled! + + std::string m_key; + + virtual void DoDispose(void); + + private: + EventId m_startEvent; + EventId m_stopEvent; + + // end class DataCalculator + }; + + + // end namespace ns3 +}; + + +#endif // __DATA_CALCULATOR_H__ diff --git a/src/contrib/stats/data-collector.cc b/src/contrib/stats/data-collector.cc new file mode 100644 index 000000000..7dd635db5 --- /dev/null +++ b/src/contrib/stats/data-collector.cc @@ -0,0 +1,131 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#include "ns3/object.h" +#include "ns3/log.h" + +#include "data-collector.h" +#include "data-calculator.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("DataCollector"); + +//-------------------------------------------------------------- +//---------------------------------------------- +DataCollector::DataCollector() { + NS_LOG_FUNCTION_NOARGS(); + // end DataCollector::DataCollector +} + +DataCollector::~DataCollector() { + NS_LOG_FUNCTION_NOARGS(); + // end DataCollector::~DataCollector +} + +void DataCollector::DoDispose() { + NS_LOG_FUNCTION_NOARGS(); + + m_calcList.clear(); + m_metadata.clear(); + + Object::DoDispose(); + // end DataCollector::DoDispose +} + +void +DataCollector::DescribeRun(std::string experiment, + std::string strategy, + std::string input, + std::string runID, + std::string description) +{ + + m_experimentLabel = experiment; + m_strategyLabel = strategy; + m_inputLabel = input; + m_runLabel = runID; + m_description = description; + + // end DataCollector::DescribeRun +} + +void +DataCollector::AddDataCalculator(Ptr datac) +{ + + m_calcList.push_back(datac); + + // end DataCollector::AddDataCalculator +} + +DataCalculatorList::iterator +DataCollector::DataCalculatorBegin() +{ + return m_calcList.begin(); + // end DataCollector::DataCalculatorBegin +} +DataCalculatorList::iterator +DataCollector::DataCalculatorEnd() +{ + return m_calcList.end(); + // end DataCollector::DataCalculatorEnd +} + +void +DataCollector::AddMetadata(std::string key, std::string value) +{ + std::pair blob(key, value); + m_metadata.push_back(blob); + // end DataCollector::AddMetadata +} +void +DataCollector::AddMetadata(std::string key, uint32_t value) +{ + std::stringstream st; + st << value; + + std::pair blob(key, st.str()); + m_metadata.push_back(blob); + // end DataCollector::AddMetadata +} +void +DataCollector::AddMetadata(std::string key, double value) +{ + std::stringstream st; + st << value; + + std::pair blob(key, st.str()); + m_metadata.push_back(blob); + // end DataCollector::AddMetadata +} + +MetadataList::iterator +DataCollector::MetadataBegin() +{ + return m_metadata.begin(); + // end DataCollector::MetadataBegin +} +MetadataList::iterator +DataCollector::MetadataEnd() +{ + return m_metadata.end(); + // end DataCollector::MetadataEnd +} diff --git a/src/contrib/stats/data-collector.h b/src/contrib/stats/data-collector.h new file mode 100644 index 000000000..ec46d02a3 --- /dev/null +++ b/src/contrib/stats/data-collector.h @@ -0,0 +1,84 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __DATA_COLLECTOR_H__ +#define __DATA_COLLECTOR_H__ + +#include +#include + +#include "ns3/object.h" + +namespace ns3 { + + class DataCalculator; + + //------------------------------------------------------------ + //-------------------------------------------- + typedef std::list > DataCalculatorList; + typedef std::list > MetadataList; + + class DataCollector : public Object { + public: + DataCollector(); + virtual ~DataCollector(); + + void DescribeRun(std::string experiment, + std::string strategy, + std::string input, + std::string runID, + std::string description = ""); + + std::string GetExperimentLabel() const { return m_experimentLabel; } + std::string GetStrategyLabel() const { return m_strategyLabel; } + std::string GetInputLabel() const { return m_inputLabel; } + std::string GetRunLabel() const { return m_runLabel; } + std::string GetDescription() const { return m_description; } + + void AddMetadata(std::string key, std::string value); + void AddMetadata(std::string key, double value); + void AddMetadata(std::string key, uint32_t value); + MetadataList::iterator MetadataBegin(); + MetadataList::iterator MetadataEnd(); + + void AddDataCalculator(Ptr datac); + DataCalculatorList::iterator DataCalculatorBegin(); + DataCalculatorList::iterator DataCalculatorEnd(); + + protected: + virtual void DoDispose(); + + private: + std::string m_experimentLabel; + std::string m_strategyLabel; + std::string m_inputLabel; + std::string m_runLabel; + std::string m_description; + + MetadataList m_metadata; + DataCalculatorList m_calcList; + + // end class DataCollector + }; + + // end namespace ns3 +}; + +#endif // __DATA_COLLECTOR_H__ diff --git a/src/contrib/stats/data-output-interface.cc b/src/contrib/stats/data-output-interface.cc new file mode 100644 index 000000000..2254008f0 --- /dev/null +++ b/src/contrib/stats/data-output-interface.cc @@ -0,0 +1,47 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#include "ns3/log.h" + +#include "data-output-interface.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("DataOutputInterface"); + + +//-------------------------------------------------------------- +//---------------------------------------------- +DataOutputInterface::DataOutputInterface() +{ + NS_LOG_FUNCTION_NOARGS(); +} +DataOutputInterface::~DataOutputInterface() +{ + NS_LOG_FUNCTION_NOARGS(); +} +void +DataOutputInterface::DoDispose() +{ + NS_LOG_FUNCTION_NOARGS(); + + Object::DoDispose(); + // end DataOutputInterface::DoDispose +} diff --git a/src/contrib/stats/data-output-interface.h b/src/contrib/stats/data-output-interface.h new file mode 100644 index 000000000..7ef26d271 --- /dev/null +++ b/src/contrib/stats/data-output-interface.h @@ -0,0 +1,76 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __DATA_OUTPUT_INTERFACE_H__ +#define __DATA_OUTPUT_INTERFACE_H__ + +#include "ns3/object.h" +#include "ns3/nstime.h" + +namespace ns3 { + + class DataCollector; + + //------------------------------------------------------------ + //-------------------------------------------- + class DataOutputInterface : public Object { + public: + DataOutputInterface(); + virtual ~DataOutputInterface(); + + virtual void Output(DataCollector &dc) = 0; + + protected: + virtual void DoDispose(); + + // end class DataOutputInterface + }; + + class DataOutputCallback { + public: + virtual ~DataOutputCallback() {} + + virtual void OutputSingleton(std::string key, + std::string variable, + int val) = 0; + + virtual void OutputSingleton(std::string key, + std::string variable, + uint32_t val) = 0; + + virtual void OutputSingleton(std::string key, + std::string variable, + double val) = 0; + + virtual void OutputSingleton(std::string key, + std::string variable, + std::string val) = 0; + + virtual void OutputSingleton(std::string key, + std::string variable, + Time val) = 0; + // end class DataOutputCallback + }; + + // end namespace ns3 +}; + + +#endif // __DATA_OUTPUT_INTERFACE_H__ diff --git a/src/contrib/stats/omnet-data-output.cc b/src/contrib/stats/omnet-data-output.cc new file mode 100644 index 000000000..50d86be52 --- /dev/null +++ b/src/contrib/stats/omnet-data-output.cc @@ -0,0 +1,155 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#include + +#include "ns3/log.h" +#include "ns3/nstime.h" + +#include "data-collector.h" +#include "data-calculator.h" +#include "omnet-data-output.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("OmnetDataOutput"); + + +//-------------------------------------------------------------- +//---------------------------------------------- +OmnetDataOutput::OmnetDataOutput() : + m_filePrefix("data") +{ + NS_LOG_FUNCTION_NOARGS(); +} +OmnetDataOutput::~OmnetDataOutput() +{ + NS_LOG_FUNCTION_NOARGS(); +} +void +OmnetDataOutput::DoDispose() +{ + NS_LOG_FUNCTION_NOARGS(); + + DataOutputInterface::DoDispose(); + // end OmnetDataOutput::DoDispose +} + +void +OmnetDataOutput::SetFilePrefix(const std::string prefix) +{ + m_filePrefix = prefix; +} +std::string +OmnetDataOutput::GetFilePrefix() const +{ + return m_filePrefix; +} + +//---------------------------------------------- +void +OmnetDataOutput::Output(DataCollector &dc) +{ + + std::ofstream scalarFile; + std::string fn = m_filePrefix + ".sca"; + scalarFile.open(fn.c_str(), std::ios_base::app); + + scalarFile << std::endl; + scalarFile << "run " << dc.GetRunLabel() << std::endl; + scalarFile << std::endl; + scalarFile << "attr experiment \"" << dc.GetExperimentLabel() + << "\"" << std::endl; + scalarFile << "attr strategy \"" << dc.GetStrategyLabel() + << "\"" << std::endl; + scalarFile << "attr input \"" << dc.GetInputLabel() + << "\"" << std::endl; + scalarFile << "attr description \"" << dc.GetDescription() + << "\"" << std::endl; + scalarFile << std::endl; + + for (MetadataList::iterator i = dc.MetadataBegin(); + i != dc.MetadataEnd(); i++) { + std::pair blob = (*i); + scalarFile << "attr \"" << blob.first << "\" \"" << blob.second << "\"" + << std::endl; + } + + scalarFile << std::endl; + + OmnetOutputCallback callback(&scalarFile); + + for (DataCalculatorList::iterator i = dc.DataCalculatorBegin(); + i != dc.DataCalculatorEnd(); i++) { + (*i)->Output(callback); + } + + scalarFile << std::endl << std::endl; + scalarFile.close(); + + // end OmnetDataOutput::Output +} + +OmnetDataOutput::OmnetOutputCallback::OmnetOutputCallback + (std::ostream *scalar) : + m_scalar(scalar) +{ +} + +void +OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key, + std::string variable, + int val) +{ + (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl; + // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton +} +void +OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key, + std::string variable, + uint32_t val) +{ + (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl; + // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton +} +void +OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key, + std::string variable, + double val) +{ + (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl; + // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton +} +void +OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key, + std::string variable, + std::string val) +{ + (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl; + // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton +} +void +OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key, + std::string variable, + Time val) +{ + (*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl; + // end OmnetDataOutput::OmnetOutputCallback::OutputSingleton +} diff --git a/src/contrib/stats/omnet-data-output.h b/src/contrib/stats/omnet-data-output.h new file mode 100644 index 000000000..0dec5201d --- /dev/null +++ b/src/contrib/stats/omnet-data-output.h @@ -0,0 +1,84 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __OMNET_DATA_OUTPUT_H__ +#define __OMNET_DATA_OUTPUT_H__ + +#include "ns3/nstime.h" + +#include "data-output-interface.h" + +namespace ns3 { + + + //------------------------------------------------------------ + //-------------------------------------------- + class OmnetDataOutput : public DataOutputInterface { + public: + OmnetDataOutput(); + virtual ~OmnetDataOutput(); + + virtual void Output(DataCollector &dc); + + void SetFilePrefix(const std::string prefix); + std::string GetFilePrefix() const; + + protected: + virtual void DoDispose(); + + private: + class OmnetOutputCallback : public DataOutputCallback { + public: + OmnetOutputCallback(std::ostream *scalar); + + void OutputSingleton(std::string key, + std::string variable, + int val); + + void OutputSingleton(std::string key, + std::string variable, + uint32_t val); + + void OutputSingleton(std::string key, + std::string variable, + double val); + + void OutputSingleton(std::string key, + std::string variable, + std::string val); + + void OutputSingleton(std::string key, + std::string variable, + Time val); + + private: + std::ostream *m_scalar; + // end class OmnetOutputCallback + }; + + std::string m_filePrefix; + // end class OmnetDataOutput + }; + + // end namespace ns3 +}; + + +#endif // __OMNET_DATA_OUTPUT_H__ diff --git a/src/contrib/stats/packet-data-calculators.cc b/src/contrib/stats/packet-data-calculators.cc new file mode 100644 index 000000000..d776bba46 --- /dev/null +++ b/src/contrib/stats/packet-data-calculators.cc @@ -0,0 +1,118 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#include "ns3/log.h" +#include "ns3/packet.h" +#include "ns3/mac48-address.h" + +#include "basic-data-calculators.h" +#include "packet-data-calculators.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("PacketDataCalculators"); + + +//-------------------------------------------------------------- +//---------------------------------------------- +PacketCounterCalculator::PacketCounterCalculator() +{ + NS_LOG_FUNCTION_NOARGS(); +} + +PacketCounterCalculator::~PacketCounterCalculator() +{ + NS_LOG_FUNCTION_NOARGS(); +} +void +PacketCounterCalculator::DoDispose(void) +{ + NS_LOG_FUNCTION_NOARGS(); + + CounterCalculator::DoDispose(); + // PacketCounterCalculator::DoDispose +} + +void +PacketCounterCalculator::PacketUpdate(std::string path, + Ptr packet) +{ + NS_LOG_FUNCTION_NOARGS(); + + CounterCalculator::Update(); + + // PacketCounterCalculator::Update +} +void +PacketCounterCalculator::FrameUpdate(std::string path, + Ptr packet, + Mac48Address realto) +{ + NS_LOG_FUNCTION_NOARGS(); + + CounterCalculator::Update(); + + // PacketCounterCalculator::Update +} + + + + +//-------------------------------------------------------------- +//---------------------------------------------- +PacketSizeMinMaxAvgTotalCalculator::PacketSizeMinMaxAvgTotalCalculator() +{ + NS_LOG_FUNCTION_NOARGS(); +} + +PacketSizeMinMaxAvgTotalCalculator::~PacketSizeMinMaxAvgTotalCalculator() +{ + NS_LOG_FUNCTION_NOARGS(); +} +void +PacketSizeMinMaxAvgTotalCalculator::DoDispose(void) +{ + NS_LOG_FUNCTION_NOARGS(); + + MinMaxAvgTotalCalculator::DoDispose(); + // end PacketSizeMinMaxAvgTotalCalculator::DoDispose +} + +void +PacketSizeMinMaxAvgTotalCalculator::PacketUpdate(std::string path, + Ptr packet) +{ + NS_LOG_FUNCTION_NOARGS(); + + MinMaxAvgTotalCalculator::Update(packet->GetSize()); + + // end PacketSizeMinMaxAvgTotalCalculator::Update +} +void +PacketSizeMinMaxAvgTotalCalculator::FrameUpdate(std::string path, + Ptr packet, + Mac48Address realto) +{ + NS_LOG_FUNCTION_NOARGS(); + + MinMaxAvgTotalCalculator::Update(packet->GetSize()); + + // end PacketSizeMinMaxAvgTotalCalculator::Update +} diff --git a/src/contrib/stats/packet-data-calculators.h b/src/contrib/stats/packet-data-calculators.h new file mode 100644 index 000000000..e65f85c36 --- /dev/null +++ b/src/contrib/stats/packet-data-calculators.h @@ -0,0 +1,68 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __PACKET_DATA_CALCULATORS_H__ +#define __PACKET_DATA_CALCULATORS_H__ + +#include "ns3/packet.h" +#include "ns3/mac48-address.h" + +#include "data-calculator.h" + +namespace ns3 { + + class PacketCounterCalculator : public CounterCalculator { + public: + PacketCounterCalculator(); + virtual ~PacketCounterCalculator(); + + void PacketUpdate(std::string path, Ptr packet); + void FrameUpdate(std::string path, Ptr packet, + Mac48Address realto); + + protected: + virtual void DoDispose(void); + + // end class PacketCounterCalculator + }; + + + class PacketSizeMinMaxAvgTotalCalculator : + public MinMaxAvgTotalCalculator { + public: + PacketSizeMinMaxAvgTotalCalculator(); + virtual ~PacketSizeMinMaxAvgTotalCalculator(); + + void PacketUpdate(std::string path, Ptr packet); + void FrameUpdate(std::string path, Ptr packet, + Mac48Address realto); + + protected: + virtual void DoDispose(void); + + // end class PacketSizeMinMaxAvgTotalCalculator + }; + + + // end namespace ns3 +}; + + +#endif // __PACKET_DATA_CALCULATORS_H__ diff --git a/src/contrib/stats/sqlite-data-output.cc b/src/contrib/stats/sqlite-data-output.cc new file mode 100644 index 000000000..68362bf33 --- /dev/null +++ b/src/contrib/stats/sqlite-data-output.cc @@ -0,0 +1,238 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#include + +#include + +#include "ns3/log.h" +#include "ns3/nstime.h" + +#include "data-collector.h" +#include "data-calculator.h" +#include "sqlite-data-output.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("SqliteDataOutput"); + + +//-------------------------------------------------------------- +//---------------------------------------------- +SqliteDataOutput::SqliteDataOutput() : + m_dbFile("data.db") +{ + NS_LOG_FUNCTION_NOARGS(); +} +SqliteDataOutput::~SqliteDataOutput() +{ + NS_LOG_FUNCTION_NOARGS(); +} +void +SqliteDataOutput::DoDispose() +{ + NS_LOG_FUNCTION_NOARGS(); + + DataOutputInterface::DoDispose(); + // end SqliteDataOutput::DoDispose +} + +void +SqliteDataOutput::SetDBFile(const std::string file) +{ + m_dbFile = file; +} +std::string +SqliteDataOutput::GetDBFile() const +{ + return m_dbFile; +} + +int +SqliteDataOutput::Exec(std::string exe) { + int res; + char **result; + int nrows, ncols; + char *errMsg = 0; + + NS_LOG_INFO("executing '" << exe << "'"); + + res = sqlite3_get_table(m_db, + exe.c_str(), + &result, &nrows, &ncols, + &errMsg); + + if (res != SQLITE_OK) { + NS_LOG_ERROR("sqlite3 error: \"" << errMsg << "\""); + /* + } else { + // std::cout << "nrows " << nrows << " ncols " << ncols << std::endl; + + if (nrows > 0) { + for (int i = 0; i < ncols; i++) { + std::cout << " " << result[i]; + } + std::cout << std::endl; + + for (int r = 1; r <= nrows; r++) { + for (int c = 0; c < ncols; c++) { + std::cout << " " << result[(r*ncols)+c]; + } + std::cout << std::endl; + } + std::cout << std::endl; + } + */ + } + + sqlite3_free_table(result); + return res; + + // end SqliteDataOutput::Exec +} + +//---------------------------------------------- +void +SqliteDataOutput::Output(DataCollector &dc) +{ + + if (sqlite3_open(m_dbFile.c_str(), &m_db)) { + NS_LOG_ERROR("Could not open sqlite3 database \"" << m_dbFile << "\""); + NS_LOG_ERROR("sqlite3 error \"" << sqlite3_errmsg(m_db) << "\""); + sqlite3_close(m_db); + // TODO: Better error reporting, management! + return; + } + + std::string run = dc.GetRunLabel(); + + Exec("create table if not exists Experiments (run, experiment, strategy, input, description text)"); + Exec("insert into Experiments (run,experiment,strategy,input,description) values ('" + + run + "', '" + + dc.GetExperimentLabel() + "', '" + + dc.GetStrategyLabel() + "', '" + + dc.GetInputLabel() + "', '" + + dc.GetDescription() + "')"); + + Exec("create table if not exists Metadata ( run text, key text, value)"); + + for (MetadataList::iterator i = dc.MetadataBegin(); + i != dc.MetadataEnd(); i++) { + std::pair blob = (*i); + Exec("insert into Metadata (run,key,value) values ('" + + run + "', '" + + blob.first + "', '" + + blob.second + "')"); + } + + SqliteOutputCallback callback(this, run); + for (DataCalculatorList::iterator i = dc.DataCalculatorBegin(); + i != dc.DataCalculatorEnd(); i++) { + (*i)->Output(callback); + } + + sqlite3_close(m_db); + + // end SqliteDataOutput::Output +} + +SqliteDataOutput::SqliteOutputCallback::SqliteOutputCallback + (Ptr owner, std::string run) : + m_owner(owner), + m_runLabel(run) +{ + + m_owner->Exec("create table if not exists Singletons ( run text, name text, variable text, value )"); + + // end SqliteDataOutput::SqliteOutputCallback::SqliteOutputCallback +} + +void +SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key, + std::string variable, + int val) +{ + + std::stringstream sstr; + sstr << "insert into Singletons (run,name,variable,value) values ('" << + m_runLabel << "', '" << + key << "', '" << + variable << "', " << + val << ")"; + m_owner->Exec(sstr.str()); + + // end SqliteDataOutput::SqliteOutputCallback::OutputSingleton +} +void +SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key, + std::string variable, + uint32_t val) +{ + std::stringstream sstr; + sstr << "insert into Singletons (run,name,variable,value) values ('" << + m_runLabel << "', '" << + key << "', '" << + variable << "', " << + val << ")"; + m_owner->Exec(sstr.str()); + // end SqliteDataOutput::SqliteOutputCallback::OutputSingleton +} +void +SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key, + std::string variable, + double val) +{ + std::stringstream sstr; + sstr << "insert into Singletons (run,name,variable,value) values ('" << + m_runLabel << "', '" << + key << "', '" << + variable << "', " << + val << ")"; + m_owner->Exec(sstr.str()); + // end SqliteDataOutput::SqliteOutputCallback::OutputSingleton +} +void +SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key, + std::string variable, + std::string val) +{ + std::stringstream sstr; + sstr << "insert into Singletons (run,name,variable,value) values ('" << + m_runLabel << "', '" << + key << "', '" << + variable << "', '" << + val << "')"; + m_owner->Exec(sstr.str()); + // end SqliteDataOutput::SqliteOutputCallback::OutputSingleton +} +void +SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key, + std::string variable, + Time val) +{ + std::stringstream sstr; + sstr << "insert into Singletons (run,name,variable,value) values ('" << + m_runLabel << "', '" << + key << "', '" << + variable << "', " << + val << ")"; + m_owner->Exec(sstr.str()); + // end SqliteDataOutput::SqliteOutputCallback::OutputSingleton +} diff --git a/src/contrib/stats/sqlite-data-output.h b/src/contrib/stats/sqlite-data-output.h new file mode 100644 index 000000000..60c118340 --- /dev/null +++ b/src/contrib/stats/sqlite-data-output.h @@ -0,0 +1,93 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __SQLITE_DATA_OUTPUT_H__ +#define __SQLITE_DATA_OUTPUT_H__ + +#include "ns3/nstime.h" + +#include "data-output-interface.h" + +#define STATS_HAS_SQLITE3 + +class sqlite3; + +namespace ns3 { + + //------------------------------------------------------------ + //-------------------------------------------- + class SqliteDataOutput : public DataOutputInterface { + public: + SqliteDataOutput(); + virtual ~SqliteDataOutput(); + + virtual void Output(DataCollector &dc); + + void SetDBFile(const std::string file); + std::string GetDBFile() const; + + protected: + virtual void DoDispose(); + + private: + class SqliteOutputCallback : public DataOutputCallback { + public: + SqliteOutputCallback(Ptr owner, std::string run); + + void OutputSingleton(std::string key, + std::string variable, + int val); + + void OutputSingleton(std::string key, + std::string variable, + uint32_t val); + + void OutputSingleton(std::string key, + std::string variable, + double val); + + void OutputSingleton(std::string key, + std::string variable, + std::string val); + + void OutputSingleton(std::string key, + std::string variable, + Time val); + + private: + Ptr m_owner; + std::string m_runLabel; + + // end class SqliteOutputCallback + }; + + + sqlite3 *m_db; + int Exec(std::string exe); + + std::string m_dbFile; + // end class SqliteDataOutput + }; + + // end namespace ns3 +}; + + +#endif // __SQLITE_DATA_OUTPUT_H__ diff --git a/src/contrib/stats/time-data-calculators.cc b/src/contrib/stats/time-data-calculators.cc new file mode 100644 index 000000000..768180862 --- /dev/null +++ b/src/contrib/stats/time-data-calculators.cc @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#include "ns3/log.h" +#include "ns3/nstime.h" + +#include "time-data-calculators.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("TimeDataCalculators"); + + +//-------------------------------------------------------------- +//---------------------------------------------- +TimeMinMaxAvgTotalCalculator::TimeMinMaxAvgTotalCalculator() +{ + m_count = 0; +} +TimeMinMaxAvgTotalCalculator::~TimeMinMaxAvgTotalCalculator() +{ +} +void +TimeMinMaxAvgTotalCalculator::DoDispose(void) +{ + DataCalculator::DoDispose(); + // TimeMinMaxAvgTotalCalculator::DoDispose +} + +void +TimeMinMaxAvgTotalCalculator::Update(const Time i) +{ + if (m_enabled) { + if (m_count) { + m_total += i; + + if (i < m_min) + m_min = i; + + if (i > m_max) + m_max = i; + + } else { + m_min = i; + m_max = i; + m_total = i; + } + m_count++; + + } + // end TimeMinMaxAvgTotalCalculator::Update +} +void +TimeMinMaxAvgTotalCalculator::Output(DataOutputCallback &callback) const +{ + callback.OutputSingleton(m_key, "count", m_count); + if (m_count > 0) { + callback.OutputSingleton(m_key, "total", m_total); + callback.OutputSingleton(m_key, "average", m_total/Scalar(m_count)); + callback.OutputSingleton(m_key, "max", m_max); + callback.OutputSingleton(m_key, "min", m_min); + } + // end TimeMinMaxAvgTotalCalculator::Output +} diff --git a/src/contrib/stats/time-data-calculators.h b/src/contrib/stats/time-data-calculators.h new file mode 100644 index 000000000..b6c56336c --- /dev/null +++ b/src/contrib/stats/time-data-calculators.h @@ -0,0 +1,62 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Drexel University + * + * 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: Joe Kopena (tjkopena@cs.drexel.edu) + */ + +#ifndef __TIME_DATA_CALCULATORS_H__ +#define __TIME_DATA_CALCULATORS_H__ + +#include "ns3/nstime.h" + +#include "data-calculator.h" +#include "data-output-interface.h" + +namespace ns3 { + + //------------------------------------------------------------ + //-------------------------------------------- + /** + * Unfortunately, templating the base MinMaxAvgTotalCalculator to + * operate over Time values isn't straightforward. The main issues + * are setting the maximum value, which can be worked around easily + * as it done here, and dividing to get the average, which is not as + * easily worked around. + */ + class TimeMinMaxAvgTotalCalculator : public DataCalculator { + public: + TimeMinMaxAvgTotalCalculator(); + virtual ~TimeMinMaxAvgTotalCalculator(); + + void Update(const Time i); + + virtual void Output(DataOutputCallback &callback) const; + + protected: + virtual void DoDispose(void); + + uint32_t m_count; + Time m_total, m_min, m_max; + + // end class TimeMinMaxAvgTotalCalculator + }; + + // end namespace ns3 +}; + + +#endif // __TIME_DATA_CALCULATORS_H__ diff --git a/src/contrib/stats/wscript b/src/contrib/stats/wscript new file mode 100644 index 000000000..3be5543e9 --- /dev/null +++ b/src/contrib/stats/wscript @@ -0,0 +1,40 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def configure(conf): + e = conf.create_library_configurator() + e.mandatory = False + e.name = 'sqlite3' + e.define = 'SQLITE3' + e.uselib = 'SQLITE3' + conf.env['SQLITE_STATS'] = e.run() + conf.report_optional_feature("SqliteDataOutput", "SQlite stats data output", + conf.env['SQLITE_STATS'], + "library 'sqlite3' not found") + + +def build(bld): + obj = bld.create_ns3_module('stats', ['node']) + obj.source = [ + 'data-calculator.cc', + 'packet-data-calculators.cc', + 'time-data-calculators.cc', + 'data-output-interface.cc', + 'omnet-data-output.cc', + 'data-collector.cc', + ] + headers = bld.create_obj('ns3header') + headers.module = 'stats' + headers.source = [ + 'data-calculator.h', + 'packet-data-calculators.h', + 'time-data-calculators.h', + 'basic-data-calculators.h', + 'data-output-interface.h', + 'omnet-data-output.h', + 'data-collector.h', + ] + + if bld.env()['SQLITE_STATS']: + headers.source.append('sqlite-data-output.h') + obj.source.append('sqlite-data-output.cc') + obj.uselib = 'SQLITE3' diff --git a/src/contrib/wscript b/src/contrib/wscript index 03f5b61a3..6775a7769 100644 --- a/src/contrib/wscript +++ b/src/contrib/wscript @@ -6,7 +6,11 @@ def configure(conf): check.uselib = 'GTK_CONFIG_STORE' check.mandatory = False conf.env['ENABLE_GTK_CONFIG_STORE'] = check.run() + conf.report_optional_feature("GtkConfigStore", "GtkConfigStore", + conf.env['ENABLE_GTK_CONFIG_STORE'], + "library 'gtk+-2.0 >= 2.12' not found") + conf.sub_config('stats') def build(bld): module = bld.create_ns3_module('contrib', ['simulator']) diff --git a/src/core/abort.h b/src/core/abort.h new file mode 100644 index 000000000..306058df3 --- /dev/null +++ b/src/core/abort.h @@ -0,0 +1,54 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef NS3_ABORT_H +#define NS3_ABORT_H + +#include "fatal-error.h" + +#define NS_ABORT_IF(cond) \ + do { \ + if (cond) \ + { \ + std::cerr << "file=" << __FILE__ << \ + ", line=" << __LINE__ << ", abort on=\""#cond << \ + "\"" << std::endl; \ + int *a = 0; \ + *a = 0; \ + } \ + } while (false) + +#define NS_ABORT_MSG_IF(cond, msg) \ + do { \ + if (cond) \ + { \ + std::cerr << "file=" << __FILE__ << \ + ", line=" << __LINE__ << ", abort on=\""#cond << \ + "\", msg=\"" << msg << "\"" << std::endl; \ + int *a = 0; \ + *a = 0; \ + } \ + } while (false) + +#define NS_ABORT_UNLESS(cond) \ + NS_ABORT_IF(!(cond)) + +#define NS_ABORT_MSG_UNLESS(cond, msg) \ + NS_ABORT_MSG_IF(!(cond),msg) + +#endif /* NS3_ABORT_H */ diff --git a/src/core/assert.h b/src/core/assert.h index 3dadf537c..235ad9db1 100644 --- a/src/core/assert.h +++ b/src/core/assert.h @@ -24,8 +24,6 @@ #include -#include "breakpoint.h" - /** * \ingroup core * \defgroup debugging Debugging @@ -49,8 +47,7 @@ * * At runtime, in debugging builds, if this condition is not * true, the program prints the source file, line number and - * unverified condition and halts in the ns3::AssertBreakpoint - * function. + * unverified condition and halts by dereferencing a null pointer. */ #define NS_ASSERT(condition) \ do \ @@ -60,7 +57,8 @@ std::cerr << "assert failed. file=" << __FILE__ << \ ", line=" << __LINE__ << ", cond=\""#condition << \ "\"" << std::endl; \ - NS_BREAKPOINT (); \ + int *a = 0; \ + *a = 0; \ } \ } \ while (false) @@ -73,7 +71,7 @@ * * At runtime, in debugging builds, if this condition is not * true, the program prints the message to output and - * halts in the ns3::AssertBreakpoint function. + * halts by dereferencing a null pointer. */ #define NS_ASSERT_MSG(condition, message) \ do \ @@ -81,7 +79,8 @@ if (!(condition)) \ { \ std::cerr << message << std::endl; \ - NS_BREAKPOINT (); \ + int *a = 0; \ + *a = 0; \ } \ } \ while (false) diff --git a/src/core/attribute-accessor-helper.h b/src/core/attribute-accessor-helper.h index f5e329dd9..cee4bae86 100644 --- a/src/core/attribute-accessor-helper.h +++ b/src/core/attribute-accessor-helper.h @@ -48,6 +48,12 @@ MakeAccessorHelper (T1 a1, T2 a2); namespace ns3 { +template +struct AccessorTrait +{ + typedef typename TypeTraits::ReferencedType>::NonConstType Result; +}; + template class AccessorHelper : public AttributeAccessor { @@ -100,7 +106,13 @@ DoMakeAccessorHelperOne (U T::*memberVariable) {} private: virtual bool DoSet (T *object, const V *v) const { - (object->*m_memberVariable) = U (v->Get ()); + typename AccessorTrait::Result tmp; + bool ok = v->GetAccessor (tmp); + if (!ok) + { + return false; + } + (object->*m_memberVariable) = tmp; return true; } virtual bool DoGet (const T *object, V *v) const { @@ -163,7 +175,13 @@ DoMakeAccessorHelperOne (void (T::*setter) (U)) {} private: virtual bool DoSet (T *object, const V *v) const { - (object->*m_setter) (U (v->Get ())); + typename AccessorTrait::Result tmp; + bool ok = v->GetAccessor (tmp); + if (!ok) + { + return false; + } + (object->*m_setter) (tmp); return true; } virtual bool DoGet (const T *object, V *v) const { @@ -196,7 +214,13 @@ DoMakeAccessorHelperTwo (void (T::*setter) (U), {} private: virtual bool DoSet (T *object, const W *v) const { - (object->*m_setter) (v->Get ()); + typename AccessorTrait::Result tmp; + bool ok = v->GetAccessor (tmp); + if (!ok) + { + return false; + } + (object->*m_setter) (tmp); return true; } virtual bool DoGet (const T *object, W *v) const { @@ -223,6 +247,55 @@ DoMakeAccessorHelperTwo (V (T::*getter) (void) const, return DoMakeAccessorHelperTwo (setter, getter); } +template +Ptr +DoMakeAccessorHelperTwo (bool (T::*setter) (U), + V (T::*getter) (void) const) +{ + class MemberMethod : public AccessorHelper + { + public: + MemberMethod (bool (T::*setter) (U), + V (T::*getter) (void) const) + : AccessorHelper (), + m_setter (setter), + m_getter (getter) + {} + private: + virtual bool DoSet (T *object, const W *v) const { + typename AccessorTrait::Result tmp; + bool ok = v->GetAccessor (tmp); + if (!ok) + { + return false; + } + ok = (object->*m_setter) (tmp); + return ok; + } + virtual bool DoGet (const T *object, W *v) const { + v->Set ((object->*m_getter) ()); + return true; + } + virtual bool HasGetter (void) const { + return true; + } + virtual bool HasSetter (void) const { + return true; + } + bool (T::*m_setter) (U); + V (T::*m_getter) (void) const; + }; + return Ptr (new MemberMethod (setter, getter), false); +} + +template +Ptr +DoMakeAccessorHelperTwo (bool (T::*getter) (void) const, + void (T::*setter) (U)) +{ + return DoMakeAccessorHelperTwo (setter, getter); +} + template Ptr MakeAccessorHelper (T1 a1) diff --git a/src/core/attribute-helper.h b/src/core/attribute-helper.h index 7e86578a5..8637e6776 100644 --- a/src/core/attribute-helper.h +++ b/src/core/attribute-helper.h @@ -117,6 +117,11 @@ MakeSimpleAttributeChecker (std::string name, std::string underlying) name##Value (const type &value); \ void Set (const type &value); \ type Get (void) const; \ + template \ + bool GetAccessor (T &value) const { \ + value = T (m_value); \ + return true; \ + } \ virtual Ptr Copy (void) const; \ virtual std::string SerializeToString (Ptr checker) const; \ virtual bool DeserializeFromString (std::string value, Ptr checker); \ @@ -220,17 +225,6 @@ MakeSimpleAttributeChecker (std::string name, std::string underlying) return MakeSimpleAttributeChecker (#type "Value", name); \ } \ - -/** - * \ingroup AttributeHelper - * \param type the name of the class - * - * This macro implements the conversion operators to and from - * instances of type Attribute. Typically invoked from xxx.cc. - */ -#define ATTRIBUTE_CONVERTER_IMPLEMENT(type) - - /** * \ingroup AttributeHelper * \param type the name of the class @@ -251,7 +245,6 @@ MakeSimpleAttributeChecker (std::string name, std::string underlying) */ #define ATTRIBUTE_HELPER_CPP(type) \ ATTRIBUTE_CHECKER_IMPLEMENT (type); \ - ATTRIBUTE_CONVERTER_IMPLEMENT (type); \ ATTRIBUTE_VALUE_IMPLEMENT (type); diff --git a/src/core/attribute-test.cc b/src/core/attribute-test.cc index 594051895..b0c3bf74f 100644 --- a/src/core/attribute-test.cc +++ b/src/core/attribute-test.cc @@ -29,6 +29,7 @@ #include "double.h" #include "object-vector.h" #include "traced-value.h" +#include "callback.h" #include "trace-source-accessor.h" #include "pointer.h" @@ -71,9 +72,13 @@ private: void NotifySourceValue (ValueClassTest old, ValueClassTest n) { m_gotValue = n; } + void NotifyCallbackValue (int8_t a) { + m_gotCbValue = a; + } int64_t m_got1; double m_got2; ValueClassTest m_gotValue; + int16_t m_gotCbValue; }; class Derived : public Object @@ -171,6 +176,10 @@ public: PointerValue (), MakePointerAccessor (&AttributeObjectTest::m_ptr), MakePointerChecker ()) + .AddAttribute ("Callback", "help text", + CallbackValue (), + MakeCallbackAccessor (&AttributeObjectTest::m_cbValue), + MakeCallbackChecker ()) ; return tid; @@ -187,6 +196,13 @@ public: m_cb (a,b,c); } + void InvokeCbValue (int8_t a) { + if (!m_cbValue.IsNull ()) + { + m_cbValue (a); + } + } + private: void DoSetTestB (bool v) { m_boolTestA = v; @@ -206,8 +222,9 @@ private: Ptr DoGetVector (uint32_t i) const { return m_vector2[i]; } - void DoSetIntSrc (int8_t v) { + bool DoSetIntSrc (int8_t v) { m_intSrc2 = v; + return true; } int8_t DoGetIntSrc (void) const { return m_intSrc2; @@ -223,6 +240,7 @@ private: RandomVariable m_random; std::vector > m_vector1; std::vector > m_vector2; + Callback m_cbValue; TracedValue m_intSrc1; TracedValue m_intSrc2; TracedCallback m_cb; @@ -491,6 +509,21 @@ AttributeTest::RunTests (void) derived = ptr.Get (); NS_TEST_ASSERT (derived != 0); + p = CreateObject (); + NS_TEST_ASSERT (p != 0); + m_gotCbValue = 1; + p->InvokeCbValue (2); + CallbackValue cbValue = MakeCallback (&AttributeTest::NotifyCallbackValue, this); + NS_TEST_ASSERT_EQUAL (m_gotCbValue, 1); + NS_TEST_ASSERT (p->SetAttributeFailSafe ("Callback", + cbValue)); + p->InvokeCbValue (2); + NS_TEST_ASSERT_EQUAL (m_gotCbValue, 2); + NS_TEST_ASSERT (p->SetAttributeFailSafe ("Callback", + CallbackValue (MakeNullCallback ()))); + p->InvokeCbValue (3); + NS_TEST_ASSERT_EQUAL (m_gotCbValue, 2); + return result; } diff --git a/src/core/boolean.h b/src/core/boolean.h index eb15d9506..3fb6096a9 100644 --- a/src/core/boolean.h +++ b/src/core/boolean.h @@ -42,6 +42,8 @@ public: BooleanValue (bool value); void Set (bool value); bool Get (void) const; + template + bool GetAccessor (T &v) const; operator bool () const; @@ -52,6 +54,13 @@ private: bool m_value; }; +template +bool BooleanValue::GetAccessor (T &v) const +{ + v = T (m_value); + return true; +} + std::ostream & operator << (std::ostream &os, const BooleanValue &value); ATTRIBUTE_CHECKER_DEFINE (Boolean); diff --git a/src/core/callback.cc b/src/core/callback.cc new file mode 100644 index 000000000..bc5223cd8 --- /dev/null +++ b/src/core/callback.cc @@ -0,0 +1,38 @@ +#include "callback.h" + +namespace ns3 { + +CallbackValue::CallbackValue () + : m_value () +{} +CallbackValue::CallbackValue (const CallbackBase &base) + : m_value (base) +{} +CallbackValue::~CallbackValue () +{} +void +CallbackValue::Set (CallbackBase base) +{ + m_value = base; +} +Ptr +CallbackValue::Copy (void) const +{ + return Create (m_value); +} +std::string +CallbackValue::SerializeToString (Ptr checker) const +{ + std::ostringstream oss; + oss << PeekPointer (m_value.GetImpl ()); + return oss.str (); +} +bool +CallbackValue::DeserializeFromString (std::string value, Ptr checker) +{ + return false; +} + +ATTRIBUTE_CHECKER_IMPLEMENT (Callback); + +} // namespace ns3 diff --git a/src/core/callback.h b/src/core/callback.h index 40afbd1a6..4a8b15bcb 100644 --- a/src/core/callback.h +++ b/src/core/callback.h @@ -25,6 +25,9 @@ #include "fatal-error.h" #include "empty.h" #include "type-traits.h" +#include "attribute.h" +#include "attribute-helper.h" +#include namespace ns3 { @@ -84,6 +87,7 @@ public: delete this; } } + uint32_t GetReferenceCount (void) const { return m_count; } virtual bool IsEqual (Ptr other) const = 0; private: mutable uint32_t m_count; @@ -397,7 +401,11 @@ private: return static_cast *> (PeekPointer (m_impl)); } bool DoCheckType (Ptr other) const { - if (dynamic_cast *> (PeekPointer (other)) != 0) + if (other != 0 && dynamic_cast *> (PeekPointer (other)) != 0) + { + return true; + } + else if (other == 0) { return true; } @@ -751,9 +759,45 @@ Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), AR Create > (fnPtr, a); return Callback (impl); } +} // namespace ns3 +namespace ns3 { -}; // namespace ns3 +class CallbackValue : public AttributeValue +{ +public: + CallbackValue (); + CallbackValue (const CallbackBase &base); + virtual ~CallbackValue (); + void Set (CallbackBase base); + template + bool GetAccessor (T &value) const; + virtual Ptr Copy (void) const; + virtual std::string SerializeToString (Ptr checker) const; + virtual bool DeserializeFromString (std::string value, Ptr checker); +private: + CallbackBase m_value; +}; + +ATTRIBUTE_ACCESSOR_DEFINE(Callback); +ATTRIBUTE_CHECKER_DEFINE (Callback); + +} // namespace ns3 + +namespace ns3 { + +template +bool CallbackValue::GetAccessor (T &value) const +{ + if (value.CheckType (m_value)) + { + value.Assign (m_value); + return true; + } + return false; +} + +} // namespace ns3 #endif /* CALLBACK_H */ diff --git a/src/core/config.cc b/src/core/config.cc index db12d72a4..0b42ad0b9 100644 --- a/src/core/config.cc +++ b/src/core/config.cc @@ -30,6 +30,100 @@ NS_LOG_COMPONENT_DEFINE ("Config"); namespace ns3 { +namespace Config { + +MatchContainer::MatchContainer () +{} +MatchContainer::MatchContainer (const std::vector > &objects, + const std::vector &contexts, + std::string path) + : m_objects (objects), + m_contexts (contexts), + m_path (path) +{} +MatchContainer::Iterator +MatchContainer::Begin (void) const +{ + return m_objects.begin (); +} +MatchContainer::Iterator +MatchContainer::End (void) const +{ + return m_objects.end (); +} +uint32_t +MatchContainer::GetN (void) const +{ + return m_objects.size (); +} +Ptr +MatchContainer::Get (uint32_t i) const +{ + return m_objects[i]; +} +std::string +MatchContainer::GetMatchedPath (uint32_t i) const +{ + return m_contexts[i]; +} +std::string +MatchContainer::GetPath (void) const +{ + return m_path; +} + +void +MatchContainer::Set (std::string name, const AttributeValue &value) +{ + for (Iterator tmp = Begin (); tmp != End (); ++tmp) + { + Ptr object = *tmp; + object->SetAttribute (name, value); + } +} +void +MatchContainer::Connect (std::string name, const CallbackBase &cb) +{ + NS_ASSERT (m_objects.size () == m_contexts.size ()); + for (uint32_t i = 0; i < m_objects.size (); ++i) + { + Ptr object = m_objects[i]; + std::string ctx = m_contexts[i] + name; + object->TraceConnect (name, ctx, cb); + } +} +void +MatchContainer::ConnectWithoutContext (std::string name, const CallbackBase &cb) +{ + for (Iterator tmp = Begin (); tmp != End (); ++tmp) + { + Ptr object = *tmp; + object->TraceConnectWithoutContext (name, cb); + } +} +void +MatchContainer::Disconnect (std::string name, const CallbackBase &cb) +{ + NS_ASSERT (m_objects.size () == m_contexts.size ()); + for (uint32_t i = 0; i < m_objects.size (); ++i) + { + Ptr object = m_objects[i]; + std::string ctx = m_contexts[i] + name; + object->TraceDisconnect (name, ctx, cb); + } +} +void +MatchContainer::DisconnectWithoutContext (std::string name, const CallbackBase &cb) +{ + for (Iterator tmp = Begin (); tmp != End (); ++tmp) + { + Ptr object = *tmp; + object->TraceDisconnectWithoutContext (name, cb); + } +} + +} // namespace Config + class ArrayMatcher { public: @@ -125,20 +219,40 @@ public: void Resolve (Ptr root); private: + void Canonicalize (void); void DoResolve (std::string path, Ptr root); void DoArrayResolve (std::string path, const ObjectVectorValue &vector); - void DoResolveOne (Ptr object, std::string name); - std::string GetResolvedPath (std::string name) const; - virtual void DoOne (Ptr object, std::string path, std::string name) = 0; + void DoResolveOne (Ptr object); + std::string GetResolvedPath (void) const; + virtual void DoOne (Ptr object, std::string path) = 0; std::vector m_workStack; std::string m_path; }; Resolver::Resolver (std::string path) : m_path (path) -{} +{ + Canonicalize (); +} Resolver::~Resolver () {} +void +Resolver::Canonicalize (void) +{ + // ensure that we start and end with a '/' + std::string::size_type tmp = m_path.find ("/"); + if (tmp != 0) + { + // no slash at start + m_path = "/" + m_path; + } + tmp = m_path.find_last_of ("/"); + if (tmp != (m_path.size () - 1)) + { + // no slash at end + m_path = m_path + "/"; + } +} void Resolver::Resolve (Ptr root) @@ -147,40 +261,34 @@ Resolver::Resolve (Ptr root) } std::string -Resolver::GetResolvedPath (std::string name) const +Resolver::GetResolvedPath (void) const { - std::string fullPath = ""; + std::string fullPath = "/"; for (std::vector::const_iterator i = m_workStack.begin (); i != m_workStack.end (); i++) { - fullPath += "/" + *i; + fullPath += *i + "/"; } - fullPath += "/" + name; return fullPath; } void -Resolver::DoResolveOne (Ptr object, std::string name) +Resolver::DoResolveOne (Ptr object) { - NS_LOG_DEBUG ("resolved="< root) const ObjectVectorChecker *vectorChecker = dynamic_cast (PeekPointer (info.checker)); if (vectorChecker != 0) { - NS_LOG_DEBUG ("GetAttribute(vector)="< obj); void UnregisterRootNamespaceObject (Ptr obj); @@ -298,110 +403,86 @@ public: Ptr GetRootNamespaceObject (uint32_t i) const; private: + void ParsePath (std::string path, std::string *root, std::string *leaf) const; typedef std::vector > Roots; Roots m_roots; }; +void +ConfigImpl::ParsePath (std::string path, std::string *root, std::string *leaf) const +{ + std::string::size_type slash = path.find_last_of ("/"); + NS_ASSERT (slash != std::string::npos); + *root = path.substr (0, slash); + *leaf = path.substr (slash+1, path.size ()-(slash+1)); + NS_LOG_FUNCTION (path << *root << *leaf); +} + void ConfigImpl::Set (std::string path, const AttributeValue &value) { - class SetResolver : public Resolver - { - public: - SetResolver (std::string path, const AttributeValue &value) - : Resolver (path), - m_value (value.Copy ()) {} - private: - virtual void DoOne (Ptr object, std::string path, std::string name) { - object->SetAttribute (name, *m_value); - } - Ptr m_value; - } resolver = SetResolver (path, value); - for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++) - { - resolver.Resolve (*i); - } + std::string root, leaf; + ParsePath (path, &root, &leaf); + Config::MatchContainer container = LookupMatches (root); + container.Set (leaf, value); } void ConfigImpl::ConnectWithoutContext (std::string path, const CallbackBase &cb) { - class ConnectResolver : public Resolver - { - public: - ConnectResolver (std::string path, const CallbackBase &cb) - : Resolver (path), - m_cb (cb) {} - private: - virtual void DoOne (Ptr object, std::string path, std::string name) { - object->TraceConnectWithoutContext (name, m_cb); - } - CallbackBase m_cb; - } resolver = ConnectResolver (path, cb); - for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++) - { - resolver.Resolve (*i); - } + std::string root, leaf; + ParsePath (path, &root, &leaf); + Config::MatchContainer container = LookupMatches (root); + container.ConnectWithoutContext (leaf, cb); } void ConfigImpl::DisconnectWithoutContext (std::string path, const CallbackBase &cb) { - class DisconnectResolver : public Resolver - { - public: - DisconnectResolver (std::string path, const CallbackBase &cb) - : Resolver (path), - m_cb (cb) {} - private: - virtual void DoOne (Ptr object, std::string path, std::string name) { - object->TraceDisconnectWithoutContext (name, m_cb); - } - CallbackBase m_cb; - } resolver = DisconnectResolver (path, cb); - for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++) - { - resolver.Resolve (*i); - } + std::string root, leaf; + ParsePath (path, &root, &leaf); + Config::MatchContainer container = LookupMatches (root); + container.DisconnectWithoutContext (leaf, cb); } void ConfigImpl::Connect (std::string path, const CallbackBase &cb) { - class ConnectWithContextResolver : public Resolver - { - public: - ConnectWithContextResolver (std::string path, const CallbackBase &cb) - : Resolver (path), - m_cb (cb) {} - private: - virtual void DoOne (Ptr object, std::string path, std::string name) { - object->TraceConnect (name, path, m_cb); - } - CallbackBase m_cb; - } resolver = ConnectWithContextResolver (path, cb); - for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++) - { - resolver.Resolve (*i); - } + std::string root, leaf; + ParsePath (path, &root, &leaf); + Config::MatchContainer container = LookupMatches (root); + container.Connect (leaf, cb); } void ConfigImpl::Disconnect (std::string path, const CallbackBase &cb) { - class DisconnectWithContextResolver : public Resolver + std::string root, leaf; + ParsePath (path, &root, &leaf); + Config::MatchContainer container = LookupMatches (root); + container.Disconnect (leaf, cb); +} + +Config::MatchContainer +ConfigImpl::LookupMatches (std::string path) +{ + NS_LOG_FUNCTION (path); + class LookupMatchesResolver : public Resolver { public: - DisconnectWithContextResolver (std::string path, const CallbackBase &cb) - : Resolver (path), - m_cb (cb) {} - private: - virtual void DoOne (Ptr object, std::string path, std::string name) { - object->TraceDisconnect (name, path, m_cb); + LookupMatchesResolver (std::string path) + : Resolver (path) + {} + virtual void DoOne (Ptr object, std::string path) { + m_objects.push_back (object); + m_contexts.push_back (path); } - CallbackBase m_cb; - } resolver = DisconnectWithContextResolver (path, cb); + std::vector > m_objects; + std::vector m_contexts; + } resolver = LookupMatchesResolver (path); for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++) { resolver.Resolve (*i); } + return Config::MatchContainer (resolver.m_objects, resolver.m_contexts, path); } + void ConfigImpl::RegisterRootNamespaceObject (Ptr obj) { @@ -472,6 +553,10 @@ Disconnect (std::string path, const CallbackBase &cb) { Singleton::Get ()->Disconnect (path, cb); } +Config::MatchContainer LookupMatches (std::string path) +{ + return Singleton::Get ()->LookupMatches (path); +} void RegisterRootNamespaceObject (Ptr obj) { diff --git a/src/core/config.h b/src/core/config.h index 256b491ef..9da9b03b9 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -22,6 +22,7 @@ #include "ptr.h" #include +#include namespace ns3 { @@ -110,6 +111,35 @@ void Connect (std::string path, const CallbackBase &cb); */ void Disconnect (std::string path, const CallbackBase &cb); +class MatchContainer +{ +public: + typedef std::vector >::const_iterator Iterator; + MatchContainer (); + MatchContainer (const std::vector > &objects, + const std::vector &contexts, + std::string path); + + MatchContainer::Iterator Begin (void) const; + MatchContainer::Iterator End (void) const; + uint32_t GetN (void) const; + Ptr Get (uint32_t i) const; + std::string GetMatchedPath (uint32_t i) const; + std::string GetPath (void) const; + + void Set (std::string name, const AttributeValue &value); + void Connect (std::string name, const CallbackBase &cb); + void ConnectWithoutContext (std::string name, const CallbackBase &cb); + void Disconnect (std::string name, const CallbackBase &cb); + void DisconnectWithoutContext (std::string name, const CallbackBase &cb); +private: + std::vector > m_objects; + std::vector m_contexts; + std::string m_path; +}; + +MatchContainer LookupMatches (std::string path); + /** * \param obj a new root object * diff --git a/src/core/deprecated.h b/src/core/deprecated.h new file mode 100644 index 000000000..63ff10f95 --- /dev/null +++ b/src/core/deprecated.h @@ -0,0 +1,10 @@ +#ifndef NS3_DEPRECATED_H +#define NS3_DEPRECATED_H + +#ifdef __GNUC__ +#define NS_DEPRECATED __attribute__ ((deprecated)) +#else +#define NS_DEPRECATED +#endif + +#endif /* NS3_DEPRECATED_H */ diff --git a/src/core/double.h b/src/core/double.h index 1ed54ecdd..d21b97847 100644 --- a/src/core/double.h +++ b/src/core/double.h @@ -23,6 +23,7 @@ #include "attribute.h" #include "attribute-helper.h" #include +#include namespace ns3 { diff --git a/src/core/enum.cc b/src/core/enum.cc index 58cc9fcc8..0e1d7812d 100644 --- a/src/core/enum.cc +++ b/src/core/enum.cc @@ -39,7 +39,6 @@ EnumValue::Get (void) const { return m_v; } - Ptr EnumValue::Copy (void) const { diff --git a/src/core/enum.h b/src/core/enum.h index d9eeb521f..b3baf2cd7 100644 --- a/src/core/enum.h +++ b/src/core/enum.h @@ -41,6 +41,8 @@ public: EnumValue (int v); void Set (int v); int Get (void) const; + template + bool GetAccessor (T &v) const; virtual Ptr Copy (void) const; virtual std::string SerializeToString (Ptr checker) const; @@ -50,6 +52,13 @@ private: int m_v; }; +template +bool EnumValue::GetAccessor (T &v) const +{ + v = T (m_v); + return true; +} + class EnumChecker : public AttributeChecker { public: diff --git a/src/core/fatal-error.h b/src/core/fatal-error.h index 8e896cf2f..05711780c 100644 --- a/src/core/fatal-error.h +++ b/src/core/fatal-error.h @@ -20,7 +20,6 @@ #ifndef FATAL_ERROR_H #define FATAL_ERROR_H -#include "breakpoint.h" #include /** @@ -30,15 +29,17 @@ * \param msg message to output when this macro is hit. * * When this macro is hit at runtime, the user-specified - * error message is output and the program is halted by calling - * the NS_BREAKPOINT macro. This macro is enabled unconditionally - * in all builds, including debug and optimized builds. + * error message is output and the program is halted by + * dereferencing a null pointer. This macro is enabled + * unconditionally in all builds, including debug and + * optimized builds. */ #define NS_FATAL_ERROR(msg) \ do \ { \ std::cerr << msg << std::endl; \ - NS_BREAKPOINT (); \ + int *a = 0; \ + *a = 0; \ } \ while (false) diff --git a/src/core/int-to-type.h b/src/core/int-to-type.h index 240fe8a71..612820cf9 100644 --- a/src/core/int-to-type.h +++ b/src/core/int-to-type.h @@ -11,7 +11,7 @@ namespace ns3 { template struct IntToType { - enum {value = v}; + enum v_e {value = v}; }; } // namespace ns3 diff --git a/src/core/integer.h b/src/core/integer.h index 8ac78e47d..2bb8125a9 100644 --- a/src/core/integer.h +++ b/src/core/integer.h @@ -23,6 +23,7 @@ #include "attribute.h" #include "attribute-helper.h" #include +#include namespace ns3 { diff --git a/src/core/log.cc b/src/core/log.cc index ec9fad101..cc050bfd0 100644 --- a/src/core/log.cc +++ b/src/core/log.cc @@ -17,13 +17,13 @@ * * Author: Mathieu Lacage */ +#include "log.h" #ifdef NS3_LOG_ENABLE #include #include #include -#include "log.h" #include "assert.h" #include "ns3/core-config.h" #include "fatal-error.h" @@ -368,4 +368,34 @@ ParameterLogger::ParameterLogger (std::ostream &os) } // namespace ns3 -#endif // NS3_LOG_ENABLE +#else // NS3_LOG_ENABLE + +namespace ns3 { + +void +LogComponentEnable (char const *name, enum LogLevel level) +{ + +} + +void +LogComponentEnableAll (enum LogLevel level) +{ + +} + +void +LogComponentDisable (char const *name, enum LogLevel level) +{ + +} + +void +LogComponentDisableAll (enum LogLevel level) +{ + +} + +} // namespace ns3 + +#endif diff --git a/src/core/log.h b/src/core/log.h index f2565d71a..4f62eb47e 100644 --- a/src/core/log.h +++ b/src/core/log.h @@ -24,6 +24,85 @@ #include #include +namespace ns3 { + +enum LogLevel { + LOG_NONE = 0x00000000, // no logging + + LOG_ERROR = 0x00000001, // serious error messages only + LOG_LEVEL_ERROR = 0x00000001, + + LOG_WARN = 0x00000002, // warning messages + LOG_LEVEL_WARN = 0x00000003, + + LOG_DEBUG = 0x00000004, // rare ad-hoc debug messages + LOG_LEVEL_DEBUG = 0x00000007, + + LOG_INFO = 0x00000008, // informational messages (e.g., banners) + LOG_LEVEL_INFO = 0x0000000f, + + LOG_FUNCTION = 0x00000010, // function tracing + LOG_LEVEL_FUNCTION = 0x0000001f, + + LOG_LOGIC = 0x00000020, // control flow tracing within functions + LOG_LEVEL_LOGIC = 0x0000003f, + + LOG_ALL = 0x3fffffff, // print everything + LOG_LEVEL_ALL = LOG_ALL, + + LOG_PREFIX_FUNC = 0x80000000, // prefix all trace prints with function + LOG_PREFIX_TIME = 0x40000000 // prefix all trace prints with simulation time +}; + +/** + * \param name a log component name + * \param level a logging level + * \ingroup logging + * + * Enable the logging output associated with that log component. + * The logging output can be later disabled with a call + * to ns3::LogComponentDisable. + * + * Same as running your program with the NS_LOG environment + * variable set as NS_LOG='name=level' + */ +void LogComponentEnable (char const *name, enum LogLevel level); + +/** + * \param level a logging level + * \ingroup logging + * + * Enable the logging output for all registered log components. + * + * Same as running your program with the NS_LOG environment + * variable set as NS_LOG='*=level' + */ +void LogComponentEnableAll (enum LogLevel level); + + +/** + * \param name a log component name + * \param level a logging level + * \ingroup logging + * + * Disable the logging output associated with that log component. + * The logging output can be later re-enabled with a call + * to ns3::LogComponentEnable. + */ +void LogComponentDisable (char const *name, enum LogLevel level); + +/** + * \param level a logging level + * \ingroup logging + * + * Disable all logging for all components. + */ +void LogComponentDisableAll (enum LogLevel level); + + +} // namespace ns3 + + #ifdef NS3_LOG_ENABLE @@ -72,7 +151,7 @@ #define NS_LOG_APPEND_TIME_PREFIX \ if (g_log.IsEnabled (ns3::LOG_PREFIX_TIME)) \ { \ - LogTimePrinter printer = LogGetTimePrinter (); \ + ns3::LogTimePrinter printer = ns3::LogGetTimePrinter (); \ if (printer != 0) \ { \ (*printer) (std::clog); \ @@ -190,19 +269,19 @@ * Component:Function (aNumber, anotherNumber) * \endcode */ -#define NS_LOG_FUNCTION(parameters) \ - do \ - { \ - if (g_log.IsEnabled (ns3::LOG_FUNCTION)) \ - { \ - NS_LOG_APPEND_TIME_PREFIX; \ - NS_LOG_APPEND_CONTEXT; \ - std::clog << g_log.Name () << ":" \ - << __FUNCTION__ << "("; \ - ParameterLogger (std::clog) << parameters; \ - std::clog << ")" << std::endl; \ - } \ - } \ +#define NS_LOG_FUNCTION(parameters) \ + do \ + { \ + if (g_log.IsEnabled (ns3::LOG_FUNCTION)) \ + { \ + NS_LOG_APPEND_TIME_PREFIX; \ + NS_LOG_APPEND_CONTEXT; \ + std::clog << g_log.Name () << ":" \ + << __FUNCTION__ << "("; \ + ns3::ParameterLogger (std::clog) << parameters; \ + std::clog << ")" << std::endl; \ + } \ + } \ while (false) @@ -230,79 +309,6 @@ namespace ns3 { -enum LogLevel { - LOG_NONE = 0x00000000, // no logging - - LOG_ERROR = 0x00000001, // serious error messages only - LOG_LEVEL_ERROR = 0x00000001, - - LOG_WARN = 0x00000002, // warning messages - LOG_LEVEL_WARN = 0x00000003, - - LOG_DEBUG = 0x00000004, // rare ad-hoc debug messages - LOG_LEVEL_DEBUG = 0x00000007, - - LOG_INFO = 0x00000008, // informational messages (e.g., banners) - LOG_LEVEL_INFO = 0x0000000f, - - LOG_FUNCTION = 0x00000010, // function tracing - LOG_LEVEL_FUNCTION = 0x0000001f, - - LOG_LOGIC = 0x00000020, // control flow tracing within functions - LOG_LEVEL_LOGIC = 0x0000003f, - - LOG_ALL = 0x3fffffff, // print everything - LOG_LEVEL_ALL = LOG_ALL, - - LOG_PREFIX_FUNC = 0x80000000, // prefix all trace prints with function - LOG_PREFIX_TIME = 0x40000000 // prefix all trace prints with simulation time -}; - -/** - * \param name a log component name - * \param level a logging level - * \ingroup logging - * - * Enable the logging output associated with that log component. - * The logging output can be later disabled with a call - * to ns3::LogComponentDisable. - * - * Same as running your program with the NS_LOG environment - * variable set as NS_LOG='name=level' - */ -void LogComponentEnable (char const *name, enum LogLevel level); - -/** - * \param level a logging level - * \ingroup logging - * - * Enable the logging output for all registered log components. - * - * Same as running your program with the NS_LOG environment - * variable set as NS_LOG='*=level' - */ -void LogComponentEnableAll (enum LogLevel level); - - -/** - * \param name a log component name - * \param level a logging level - * \ingroup logging - * - * Disable the logging output associated with that log component. - * The logging output can be later re-enabled with a call - * to ns3::LogComponentEnable. - */ -void LogComponentDisable (char const *name, enum LogLevel level); - -/** - * \param level a logging level - * \ingroup logging - * - * Disable all logging for all components. - */ -void LogComponentDisableAll (enum LogLevel level); - /** * \ingroup logging @@ -373,10 +379,6 @@ public: #define NS_LOG_UNCOND(msg) #define LogComponentPrintList -#define LogComponentEnable(name,level) -#define LogComponentDisable(name,level) -#define LogComponentEnableAll(level) -#define LogComponentDisableAll(level) #define LogRegisterTimePrinter(printer) #define LogSetTimePrinter(printer) diff --git a/src/core/object.cc b/src/core/object.cc index 4a1c98dad..9640d158b 100644 --- a/src/core/object.cc +++ b/src/core/object.cc @@ -95,6 +95,11 @@ Object::Object (const Object &o) m_disposed (false), m_next (this) {} +uint32_t +Object::GetReferenceCount (void) const +{ + return m_count; +} void Object::Construct (const AttributeList &attributes) { @@ -108,7 +113,7 @@ Object::DoGetObject (TypeId tid) const const Object *currentObject = this; do { NS_ASSERT (currentObject != 0); - TypeId cur = currentObject->m_tid; + TypeId cur = currentObject->GetInstanceTypeId (); while (cur != tid && cur != Object::GetTypeId ()) { cur = cur.GetParent (); @@ -141,10 +146,11 @@ Object::AggregateObject (Ptr o) NS_ASSERT (CheckLoose ()); NS_ASSERT (o->CheckLoose ()); - if (DoGetObject (o->m_tid)) + if (DoGetObject (o->GetInstanceTypeId ())) { NS_FATAL_ERROR ("Object::AggregateObject(): " - "Multiple aggregation of objects of type " << o->m_tid.GetName ()); + "Multiple aggregation of objects of type " << + o->GetInstanceTypeId ().GetName ()); } Object *other = PeekPointer (o); diff --git a/src/core/object.h b/src/core/object.h index dcaf97e36..225ef652a 100644 --- a/src/core/object.h +++ b/src/core/object.h @@ -112,6 +112,12 @@ public: * dangerous. */ inline void Unref (void) const; + + /** + * Get the reference count of the object. Normally not needed; for language bindings. + */ + uint32_t GetReferenceCount (void) const; + /** * \returns a pointer to the requested interface or zero if it could not be found. */ @@ -192,6 +198,10 @@ private: friend Ptr CopyObject (Ptr object); template friend Ptr CopyObject (Ptr object); + // The following friend method declaration is used only + // by our python bindings to call the protected ObjectBase::Construct + // method. + friend void PythonCompleteConstruct (Ptr object, TypeId typeId, const AttributeList &attributes); friend class ObjectFactory; friend class AggregateIterator; @@ -369,7 +379,7 @@ template Ptr CopyObject (Ptr object) { Ptr p = Ptr (new T (*PeekPointer (object)), false); - NS_ASSERT (p->m_tid == object->m_tid); + NS_ASSERT (p->GetInstanceTypeId () == object->GetInstanceTypeId ()); return p; } @@ -377,7 +387,7 @@ template Ptr CopyObject (Ptr object) { Ptr p = Ptr (new T (*PeekPointer (object)), false); - NS_ASSERT (p->m_tid == object->m_tid); + NS_ASSERT (p->GetInstanceTypeId () == object->GetInstanceTypeId ()); return p; } diff --git a/src/core/pointer.h b/src/core/pointer.h index 5fcb28718..4b0e4d671 100644 --- a/src/core/pointer.h +++ b/src/core/pointer.h @@ -50,6 +50,9 @@ public: template Ptr Get (void) const; + template + bool GetAccessor (Ptr &v) const; + template operator Ptr () const; @@ -61,23 +64,6 @@ private: Ptr m_value; }; -template -Ptr -MakePointerAccessor (Ptr T::*memberVariable); -template -Ptr -MakePointerAccessor (void (T::*setter) (Ptr)); -template -Ptr -MakePointerAccessor (Ptr (T::*getter) (void) const); -template -Ptr -MakePointerAccessor (void (T::*setter) (Ptr), - Ptr (T::*getter) (void) const); -template -Ptr -MakePointerAccessor (Ptr (T::*getter) (void) const, - void (T::*setter) (Ptr)); class PointerChecker : public AttributeChecker { @@ -142,57 +128,8 @@ class APointerChecker : public PointerChecker } }; -/******************************************************** - * The Accessor associated to - * PointerValue - ********************************************************/ - -template -class PointerAccessor : public AttributeAccessor -{ -public: - virtual ~PointerAccessor () {} - virtual bool Set (ObjectBase * object, const AttributeValue &val) const { - T *obj = dynamic_cast (object); - if (obj == 0) - { - return false; - } - const PointerValue *value = dynamic_cast (&val); - if (value == 0) - { - return false; - } - Ptr ptr = dynamic_cast (PeekPointer (value->GetObject ())); - if (ptr == 0) - { - return false; - } - DoSet (obj, ptr); - return true; - } - virtual bool Get (const ObjectBase * object, AttributeValue &val) const { - const T *obj = dynamic_cast (object); - if (obj == 0) - { - return false; - } - PointerValue *value = dynamic_cast (&val); - if (value == 0) - { - return false; - } - value->Set (DoGet (obj)); - return true; - } -private: - virtual void DoSet (T *object, Ptr value) const = 0; - virtual Ptr DoGet (const T *object) const = 0; -}; - } // namespace internal - template PointerValue::PointerValue (const Ptr &object) { @@ -220,112 +157,21 @@ PointerValue::operator Ptr () const return Get (); } - -template -Ptr -MakePointerAccessor (Ptr T::*memberVariable) +template +bool +PointerValue::GetAccessor (Ptr &v) const { - struct MemberVariable : public internal::PointerAccessor - { - Ptr T::*m_memberVariable; - virtual void DoSet (T *object, Ptr value) const { - (object->*m_memberVariable) = value; - } - virtual Ptr DoGet (const T *object) const { - return object->*m_memberVariable; - } - virtual bool HasGetter (void) const { - return true; - } - virtual bool HasSetter (void) const { - return true; - } - } *spec = new MemberVariable (); - spec->m_memberVariable = memberVariable; - return Ptr (spec, false); -} - -template -Ptr -MakePointerAccessor (void (T::*setter) (Ptr)) -{ - struct MemberMethod : public internal::PointerAccessor - { - void (T::*m_setter) (Ptr); - virtual void DoSet (T *object, Ptr value) const { - (object->*m_setter) (value); - } - virtual Ptr DoGet (const T *object) const { - return 0; - //return (object->*m_getter) (); - } - virtual bool HasGetter (void) const { + Ptr ptr = dynamic_cast (PeekPointer (m_value)); + if (ptr == 0) + { return false; } - virtual bool HasSetter (void) const { - return true; - } - } *spec = new MemberMethod (); - spec->m_setter = setter; - return Ptr (spec, false); + v = ptr; + return true; } -template -Ptr -MakePointerAccessor (Ptr (T::*getter) (void) const) -{ - struct MemberMethod : public internal::PointerAccessor - { - Ptr (T::*m_getter) (void) const; - virtual void DoSet (T *object, Ptr value) const { - //(object->*m_setter) (value); - } - virtual Ptr DoGet (const T *object) const { - return (object->*m_getter) (); - } - virtual bool HasGetter (void) const { - return true; - } - virtual bool HasSetter (void) const { - return false; - } - } *spec = new MemberMethod (); - spec->m_getter = getter; - return Ptr (spec, false); -} -template -Ptr -MakePointerAccessor (void (T::*setter) (Ptr), - Ptr (T::*getter) (void) const) -{ - return MakePointerAccessor (getter, setter); -} -template -Ptr -MakePointerAccessor (Ptr (T::*getter) (void) const, - void (T::*setter) (Ptr)) -{ - struct MemberMethod : public internal::PointerAccessor - { - void (T::*m_setter) (Ptr); - Ptr (T::*m_getter) (void) const; - virtual void DoSet (T *object, Ptr value) const { - (object->*m_setter) (value); - } - virtual Ptr DoGet (const T *object) const { - return (object->*m_getter) (); - } - virtual bool HasGetter (void) const { - return true; - } - virtual bool HasSetter (void) const { - return true; - } - } *spec = new MemberMethod (); - spec->m_setter = setter; - spec->m_getter = getter; - return Ptr (spec, false); -} + +ATTRIBUTE_ACCESSOR_DEFINE (Pointer); template Ptr diff --git a/src/core/ptr.cc b/src/core/ptr.cc index 3c852821a..41e0539ed 100644 --- a/src/core/ptr.cc +++ b/src/core/ptr.cc @@ -249,8 +249,8 @@ PtrTest::RunTests (void) Ptr p4 = CallTestConst (p1); Ptr p5 = p4; //p4 = p5; You cannot make a const pointer be a non-const pointer. - // but if you use const_pointer_cast, you can. - p4 = const_pointer_cast (p5); + // but if you use ConstCast, you can. + p4 = ConstCast (p5); p5 = p1; Ptr p; if (p == 0) diff --git a/src/core/ptr.h b/src/core/ptr.h index 2bcbf3c60..4861ceb4b 100644 --- a/src/core/ptr.h +++ b/src/core/ptr.h @@ -341,13 +341,38 @@ bool operator < (const Ptr &lhs, const Ptr &rhs) return PeekPointer (lhs) < PeekPointer (rhs); } +template +bool operator <= (const Ptr &lhs, const Ptr &rhs) +{ + return PeekPointer (lhs) <= PeekPointer (rhs); +} + +template +bool operator > (const Ptr &lhs, const Ptr &rhs) +{ + return PeekPointer (lhs) > PeekPointer (rhs); +} + +template +bool operator >= (const Ptr &lhs, const Ptr &rhs) +{ + return PeekPointer (lhs) >= PeekPointer (rhs); +} + template Ptr -const_pointer_cast (Ptr const&p) +ConstCast (Ptr const&p) { return Ptr (const_cast (PeekPointer (p))); } +template +Ptr +DynamicCast (Ptr const&p) +{ + return Ptr (dynamic_cast (PeekPointer (p))); +} + /**************************************************** * Member method implementations. diff --git a/src/core/random-variable.cc b/src/core/random-variable.cc index 336a2a119..86c7d5f5b 100644 --- a/src/core/random-variable.cc +++ b/src/core/random-variable.cc @@ -196,7 +196,12 @@ void RandomVariableBase::GetRandomSeeds(uint32_t seeds[6]) { for (int i = 0; i < 6; ++i) { - read(RandomVariableBase::devRandom, &seeds[i], sizeof(seeds[i])); + ssize_t bytes_read = read (RandomVariableBase::devRandom, + &seeds[i], sizeof (seeds[i])); + if (bytes_read != sizeof (seeds[i])) + { + NS_FATAL_ERROR ("Read from /dev/random failed"); + } } if (RngStream::CheckSeed(seeds)) break; // Got a valid one } @@ -1012,7 +1017,7 @@ NormalVariableImpl::NormalVariableImpl(double m, double v, double b/*=INFINITE_V NormalVariableImpl::NormalVariableImpl(const NormalVariableImpl& c) : RandomVariableBase(c), m_mean(c.m_mean), m_variance(c.m_variance), - m_bound(c.m_bound) { } + m_bound(c.m_bound), m_nextValid(false) { } double NormalVariableImpl::GetValue() { @@ -1033,7 +1038,8 @@ double NormalVariableImpl::GetValue() } while(1) { // See Simulation Modeling and Analysis p. 466 (Averill Law) - // for algorithm + // for algorithm; basically a Box-Muller transform: + // http://en.wikipedia.org/wiki/Box-Muller_transform double u1 = m_generator->RandU01(); double u2 = m_generator->RandU01();; double v1 = 2 * u1 - 1; @@ -1043,11 +1049,21 @@ double NormalVariableImpl::GetValue() { // Got good pair double y = sqrt((-2 * log(w))/w); m_next = m_mean + v2 * y * sqrt(m_variance); - if (fabs(m_next) > m_bound) m_next = m_bound * (m_next)/fabs(m_next); - m_nextValid = true; + //if next is in bounds, it is valid + m_nextValid = fabs(m_next-m_mean) <= m_bound; double x1 = m_mean + v1 * y * sqrt(m_variance); - if (fabs(x1) > m_bound) x1 = m_bound * (x1)/fabs(x1); - return x1; + //if x1 is in bounds, return it + if (fabs(x1-m_mean) <= m_bound) + { + return x1; + } + //otherwise try and return m_next if it is valid + else if (m_nextValid) + { + m_nextValid = false; + return m_next; + } + //otherwise, just run this loop again } } } @@ -1072,7 +1088,8 @@ double NormalVariableImpl::GetSingleValue(double m, double v, double b) } while(1) { // See Simulation Modeling and Analysis p. 466 (Averill Law) - // for algorithm + // for algorithm; basically a Box-Muller transform: + // http://en.wikipedia.org/wiki/Box-Muller_transform double u1 = m_static_generator->RandU01(); double u2 = m_static_generator->RandU01();; double v1 = 2 * u1 - 1; @@ -1082,11 +1099,21 @@ double NormalVariableImpl::GetSingleValue(double m, double v, double b) { // Got good pair double y = sqrt((-2 * log(w))/w); m_static_next = m + v2 * y * sqrt(v); - if (fabs(m_static_next) > b) m_static_next = b * (m_static_next)/fabs(m_static_next); - m_static_nextValid = true; + //if next is in bounds, it is valid + m_static_nextValid = fabs(m_static_next-m) <= b;; double x1 = m + v1 * y * sqrt(v); - if (fabs(x1) > b) x1 = b * (x1)/fabs(x1); - return x1; + //if x1 is in bounds, return it + if (fabs(x1-m) <= b) + { + return x1; + } + //otherwise try and return m_next if it is valid + else if (m_static_nextValid) + { + m_static_nextValid = false; + return m_static_next; + } + //otherwise, just run this loop again } } } @@ -1094,10 +1121,18 @@ double NormalVariableImpl::GetSingleValue(double m, double v, double b) NormalVariable::NormalVariable() : RandomVariable (NormalVariableImpl ()) {} +NormalVariable::NormalVariable(double m, double v) + : RandomVariable (NormalVariableImpl (m, v)) +{} NormalVariable::NormalVariable(double m, double v, double b) : RandomVariable (NormalVariableImpl (m, v, b)) {} double +NormalVariable::GetSingleValue(double m, double v) +{ + return NormalVariableImpl::GetSingleValue (m, v); +} +double NormalVariable::GetSingleValue(double m, double v, double b) { return NormalVariableImpl::GetSingleValue (m, v, b); diff --git a/src/core/random-variable.h b/src/core/random-variable.h index 4abb36bdb..a311a2bbc 100644 --- a/src/core/random-variable.h +++ b/src/core/random-variable.h @@ -490,27 +490,43 @@ public: class NormalVariable : public RandomVariable { public: - static const double INFINITE_VALUE; /** * Constructs an normal random variable with a mean * value of 0 and variance of 1. */ NormalVariable(); + /** + * \brief Construct a normal random variable with specified mean and variance. + * \param m Mean value + * \param v Variance + */ + NormalVariable(double m, double v); + /** * \brief Construct a normal random variable with specified mean and variance * \param m Mean value * \param v Variance - * \param b Bound. The NormalVariable is bounded within +-bound. + * \param b Bound. The NormalVariable is bounded symetrically about the mean + * [mean-bound,mean+bound] */ - NormalVariable(double m, double v, double b = INFINITE_VALUE); + NormalVariable(double m, double v, double b); + /** * \param m Mean value * \param v Variance - * \param b Bound. The NormalVariable is bounded within +-bound. + * \return A random number from a distribution specified by m, and v. + */ + static double GetSingleValue(double m, double v); + + /** + * \param m Mean value + * \param v Variance + * \param b Bound. The NormalVariable is bounded symetrically about the mean + * [mean-bound,mean+bound] * \return A random number from a distribution specified by m,v, and b. */ - static double GetSingleValue(double m, double v, double b = INFINITE_VALUE); + static double GetSingleValue(double m, double v, double b); }; /** diff --git a/src/core/ref-count-base.cc b/src/core/ref-count-base.cc index d376894f6..06abf7c22 100644 --- a/src/core/ref-count-base.cc +++ b/src/core/ref-count-base.cc @@ -43,4 +43,10 @@ RefCountBase::~RefCountBase () { } +uint32_t +RefCountBase::GetReferenceCount (void) const +{ + return m_count; +} + } // namespace ns3 diff --git a/src/core/ref-count-base.h b/src/core/ref-count-base.h index 4ce8440c9..08e9946fa 100644 --- a/src/core/ref-count-base.h +++ b/src/core/ref-count-base.h @@ -50,14 +50,20 @@ public: * conjunction with the Ptr template which would make calling Ref * unecessary and dangerous. */ - inline void Ref () const; + inline void Ref (void) const; /** * Decrement the reference count. This method should not be called * by user code. RefCountBase instances are expected to be used in * conjunction with the Ptr template which would make calling Ref * unecessary and dangerous. */ - inline void Unref () const; + inline void Unref (void) const; + + /** + * Get the reference count of the object. Normally not needed; for language bindings. + */ + uint32_t GetReferenceCount (void) const; + private: // Note we make this mutable so that the const methods can still // change it. @@ -70,15 +76,16 @@ namespace ns3 { // Implementation of the in-line methods void -RefCountBase::Ref () const +RefCountBase::Ref (void) const { m_count++; } void -RefCountBase::Unref () const +RefCountBase::Unref (void) const { - if (--m_count == 0) + m_count--; + if (m_count == 0) { // All references removed, ok to delete delete this; } diff --git a/src/core/string.cc b/src/core/string.cc index fbd70e2be..ae5619244 100644 --- a/src/core/string.cc +++ b/src/core/string.cc @@ -3,7 +3,6 @@ namespace ns3 { ATTRIBUTE_CHECKER_IMPLEMENT_WITH_NAME (String, "std::string"); -ATTRIBUTE_CONVERTER_IMPLEMENT (String); ATTRIBUTE_VALUE_IMPLEMENT_WITH_NAME (std::string, String); } // namespace ns3 diff --git a/src/core/system-condition.h b/src/core/system-condition.h new file mode 100644 index 000000000..eb3d78b0e --- /dev/null +++ b/src/core/system-condition.h @@ -0,0 +1,106 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 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; + * + * 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 SYSTEM_CONDITION_H +#define SYSTEM_CONDITION_H + +#include "ptr.h" + +namespace ns3 { + +class SystemConditionPrivate; + +/** + * @brief A class which provides a relatively platform-independent + * conditional-wait thread synchronization primitive. + * + * It is often desirable to have a mechanism by which a thread can suspend its + * execution and relinquish the process until some condition to becomes true. + * We provide platform-independent access to this OS-dependent capability with + * the SystemCondition class. + * + * There are two ways to tell the underlying primitive that the condition has + * become true: Signal and Broadcast. Signal will only wake up one thread + * waiting on the condition (according to the OS scheduling policy); + * Broadcast will wake up all of the threads waiting on the condition + * (cf. "The Thundering Herd"). + * + * In order to wait for the underlying condition, you also have two + * alternatives: Wait and TimedWait. The Wait call will wait forever for the + * condition to become true; but the TimedWait has a timeout. + * + * The condition underlying this class is a simple boolean variable. It is + * set to false in each call to Wait and TimedWait. It is set to true in each + * call to Signal and Broadcast. This is a fairly simple-minded condition + * designed for + * + * A typical use case will be to call Wait() or TimedWait() in one thread + * context and put the processor to sleep until an event happens somewhere + * else that + */ +class SystemCondition +{ +public: + SystemCondition (); + ~SystemCondition (); + + /** + * Set the value of the underlying condition. + */ + void SetCondition (bool condition); + + /** + * Get the value of the underlying condition. + */ + bool GetCondition (void); + + /** + * Release one thread if waiting for the condition to be true. If you want + * a waiting thread to return, you should have done a SetCondition (true) + * prior to calling. + */ + void Signal (void); + + /** + * Release all threads waiting for the condition to be true. If you want + * all waiting threads to return, you should have done a SetCondition (true) + * prior to calling. + */ + void Broadcast (void); + + /** + * Wait, possibly forever, for the condition to be true. + */ + void Wait (void); + + /** + * Wait a maximum of ns nanoseconds for the condition to be true. If the + * wait times out, return true else return false. + */ + bool TimedWait (uint64_t ns); + + +private: + SystemConditionPrivate * m_priv; +}; + +} //namespace ns3 + +#endif /* SYSTEM_CONDITION_H */ + + diff --git a/src/core/system-mutex.h b/src/core/system-mutex.h new file mode 100644 index 000000000..2bb411ab0 --- /dev/null +++ b/src/core/system-mutex.h @@ -0,0 +1,120 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SYSTEM_MUTEX_H +#define SYSTEM_MUTEX_H + +#include "ptr.h" + +namespace ns3 { + +class SystemMutexPrivate; + +/** + * @brief A class which provides a relatively platform-independent Mutual + * Exclusion thread synchronization primitive. + * + * When more than one thread needs to access a shared resource (data structure + * or device), the system needs to provide a way to serialize access to the + * resource. An operating system will typically provide a Mutual Exclusion + * primitive to provide that capability. We provide plattorm-independent + * access to the OS-dependent capability with the SystemMutex class. + * + * There are two operations: Lock and Unlock. Lock allows an executing + * SystemThread to attempt to acquire ownership of the Mutual Exclusion + * object. If the SystemMutex object is not owned by another thread, then + * ownership is granted to the calling SystemThread and Lock returns + * immediately, However, if the SystemMutex is already owned by another + * SystemThread, the calling SystemThread is blocked until the current owner + * releases the SystemMutex by calling Unlock. + * + * @see CriticalSection + */ +class SystemMutex +{ +public: + SystemMutex (); + ~SystemMutex (); + + /** + * Acquire ownership of the Mutual Exclusion object. + */ + void Lock (); + + /** + * Release ownership of the Mutual Exclusion object. + */ + void Unlock (); + +private: + SystemMutexPrivate * m_priv; +}; + +/** + * @brief A class which provides a simple way to implement a Critical Section. + * + * When more than one SystemThread needs to access a shared resource, we + * conrol access by acquiring a SystemMutex. The CriticalSection class uses + * the C++ scoping rules to automatically perform the required Lock and Unlock + * operations to implement a Critical Section. + * + * If one wants to treat an entire method call as a critical section, one would + * do something like, + * + * Class::Method () + * { + * CriticalSection cs (mutex); + * ... + * } + * + * In this case, the critical section is entered when the CriticalSection + * object is created, and the critical section is exited when the + * CriticalSection object goes out of scope at the end of the method. + * + * Finer granularity is achieved by using local scope blocks. + * + * Class::Method () + * { + * ... + * { + * CriticalSection cs (mutex); + * } + * ... + * } + * + * Here, the critical section is entered partway through the method when the + * CriticalSection object is created in the local scope block (the braces). + * The critical section is exited when the CriticalSection object goes out of + * scope at the end of block. + * + * @see SystemMutex + */ +class CriticalSection +{ +public: + CriticalSection (SystemMutex &mutex); + ~CriticalSection (); +private: + SystemMutex &m_mutex; +}; + +} //namespace ns3 + +#endif /* SYSTEM_MUTEX_H */ diff --git a/src/core/system-thread.h b/src/core/system-thread.h new file mode 100644 index 000000000..480eb2f63 --- /dev/null +++ b/src/core/system-thread.h @@ -0,0 +1,198 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SYSTEM_THREAD_H +#define SYSTEM_THREAD_H + +#include "callback.h" + +namespace ns3 { + +class SystemThreadImpl; + +/** + * @brief A class which provides a relatively platform-independent thread + * primitive. + * + * This class allows for creation of multiple threads of execution in a + * process. The exact implementation of the thread functionality is + * operating system dependent, but typically in ns-3 one is using an + * environment in which Posix Threads are supported (either navively or + * in the case of Windows via Cygwin's implementation of pthreads on the + * Win32 API. In either case we expect that these will be kernel-level + * threads and therefore a system with multiple CPUs will see truly concurrent + * execution. + * + * Synchronization between threads is provided via the SystemMutex class. + */ +class SystemThread +{ +public: + /** + * @brief Create a SystemThread object. + * + * A system thread object is not created running. A thread of execution + * must be explicitly started by calling the Start method. When the + * Start method is called, it will spawn a thread of execution and cause + * that thread to call out into the callback function provided here as + * a parameter. + * + * Like all ns-3 callbacks, the provided callback may refer to a function + * or a method of an object depending on how the MakeCallback function is + * used. + * + * The most common use is expected to be creating a thread of execution in + * a method. In this case you would use code similar to, + * + * MyClass myObject; + * Ptr st = Create ( + * MakeCallback (&MyClass::MyMethod, &myObject)); + * st->Start (); + * + * The SystemThread is passed a callback that calls out to the function + * MyClass::MyMethod. When this function is called, it is called as an + * object method on the myObject object. Essentially what you are doing + * is asking the SystemThread to call object->MyMethod () in a new thread + * of execution. + * + * Remember that if you are invoking a callback on an object that is + * managed by a smart pointer, you need to call PeekPointer. + * + * Ptr myPtr = Create (); + * Ptr st = Create ( + * MakeCallback (&MyClass::MyMethod, PeekPointer (myPtr))); + * st->Start (); + * + * Just like any thread, you can synchronize with its termination. The + * method provided to do this is Join (). If you call Join() you will block + * until the SystemThread run method returns. + * + * @warning The SystemThread uses SIGALRM to wake threads that are possibly + * blocked on IO. + * @see Shutdown + * + * @warning I've made the system thread class look like a normal ns3 object + * with smart pointers, and living in the heap. This makes it very easy to + * manage threads from a single master thread context. You should be very + * aware though that I have not made Ptr multithread safe! This means that + * if you pass Ptr around in a multithreaded environment, it is + * possible that the reference count will get messed up since it is not an + * atomic operation. CREATE AND MANAGE YOUR THREADS IN ONE PLACE -- LEAVE + * THE PTR THERE. + */ + SystemThread(Callback callback); + + /** + * @brief Destroy a SystemThread object. + * + */ + ~SystemThread(); + + /** + * Increment the reference count. This method should not be called + * by user code. Object instances are expected to be used in conjunction + * of the Ptr template which would make calling Ref unecessary and + * dangerous. + */ + inline void Ref (void) const; + + /** + * Decrement the reference count. This method should not be called + * by user code. Object instances are expected to be used in conjunction + * of the Ptr template which would make calling Ref unecessary and + * dangerous. + */ + inline void Unref (void) const; + + /** + * @brief Start a thread of execution, running the provided callback. + */ + void Start (void); + + /** + * @brief Suspend the caller until the thread of execution, running the + * provided callback, finishes. + */ + void Join (void); + + /** + * @brief Indicates to a managed thread doing cooperative multithreading that + * its managing thread wants it to exit. + * + * It is often the case that we want a thread to be off doing work until such + * time as its job is done (typically when the simulation is done). We then + * want the thread to exit itself. This method provides a consistent way for + * the managing thread to communicate with the managed thread. After the + * manager thread calls this method, the Break() method will begin returning + * true, telling the managed thread to exit. + * + * This alone isn't really enough to merit these events, but in Unix, if a + * worker thread is doing blocking IO, it will need to be woken up from that + * read somehow. This method also provides that functionality, by sending a + * SIGALRM signal to the possibly blocked thread. + * + * @warning Uses SIGALRM to notifiy threads possibly blocked on IO. Beware + * if you are using signals. + * @see Break + */ + void Shutdown (void); + + /** + * @brief Indicates to a thread doing cooperative multithreading that + * its managing thread wants it to exit. + * + * It is often the case that we want a thread to be off doing work until such + * time as its job is done. We then want the thread to exit itself. This + * method allows a thread to query whether or not it should be running. + * Typically, the worker thread is running in a forever-loop, and will need to + * "break" out of that loop to exit -- thus the name. + * + * @see Shutdown + * @returns true if thread is expected to exit (break out of the forever-loop) + */ + bool Break (void); + +private: + SystemThreadImpl * m_impl; + mutable uint32_t m_count; + bool m_break; +}; + + void +SystemThread::Ref (void) const +{ + m_count++; +} + + void +SystemThread::Unref (void) const +{ + m_count--; + if (m_count == 0) + { + delete this; + } +} + +} //namespace ns3 + +#endif /* SYSTEM_THREAD_H */ + + diff --git a/src/core/type-id.h b/src/core/type-id.h index 48455f06f..423983be4 100644 --- a/src/core/type-id.h +++ b/src/core/type-id.h @@ -44,7 +44,7 @@ class TraceSourceAccessor; class TypeId { public: - enum { + enum AttributeFlag { /** * The attribute can be read */ @@ -96,7 +96,7 @@ public: * No two instances can share the same name. The name is expected to be * the full c++ typename of associated c++ object. */ - TypeId (const char * name); + explicit TypeId (const char * name); /** * \returns the parent of this TypeId diff --git a/src/core/uid-manager.cc b/src/core/uid-manager.cc deleted file mode 100644 index 494845b4b..000000000 --- a/src/core/uid-manager.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- 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 - */ -#include "uid-manager.h" -#include "fatal-error.h" -#include "assert.h" - - -namespace ns3 { - - -uint32_t -UidManager::Allocate (std::string name) -{ - for (NameList::iterator i = m_nameList.begin (); i != m_nameList.end (); i++) - { - if ((*i) == name) - { - NS_FATAL_ERROR ("Trying to allocate twice the same uid: " << name); - } - } - m_nameList.push_back (name); - return m_nameList.size (); -} - -uint32_t -UidManager::LookupByName (std::string name) -{ - uint32_t j = 0; - for (NameList::iterator i = m_nameList.begin (); i != m_nameList.end (); i++) - { - j++; - if ((*i) == name) - { - return j; - } - } - return 0; -} - -std::string -UidManager::LookupByUid (uint32_t uid) -{ - NS_ASSERT (uid > 0); - NS_ASSERT (m_nameList.size () >= uid); - return m_nameList[uid-1]; -} - -} // namespace ns3 diff --git a/src/core/uinteger.h b/src/core/uinteger.h index c67709272..881f103bf 100644 --- a/src/core/uinteger.h +++ b/src/core/uinteger.h @@ -23,6 +23,7 @@ #include "attribute.h" #include "attribute-helper.h" #include +#include namespace ns3 { diff --git a/src/core/unix-system-condition.cc b/src/core/unix-system-condition.cc new file mode 100644 index 000000000..133dc18ed --- /dev/null +++ b/src/core/unix-system-condition.cc @@ -0,0 +1,220 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 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; + * + * 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 +#include +#include +#include "fatal-error.h" +#include "system-condition.h" +#include "log.h" + +NS_LOG_COMPONENT_DEFINE ("SystemCondition"); + +namespace ns3 { + +class SystemConditionPrivate { +public: + static const uint64_t NS_PER_SEC = (uint64_t)1000000000; + + SystemConditionPrivate (); + ~SystemConditionPrivate (); + + void SetCondition (bool condition); + bool GetCondition (void); + void Signal (void); + void Broadcast (void); + void Wait (void); + bool TimedWait (uint64_t ns); + +private: + pthread_mutex_t m_mutex; + pthread_cond_t m_cond; + bool m_condition; +}; + +SystemConditionPrivate::SystemConditionPrivate () +{ + NS_LOG_FUNCTION_NOARGS (); + + m_condition = false; + + pthread_mutexattr_t mAttr; + pthread_mutexattr_init (&mAttr); +// +// Linux and OS X (at least) have, of course chosen different names for the +// error checking flags just to make life difficult. +// +#if defined (PTHREAD_MUTEX_ERRORCHECK_NP) + pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK_NP); +#else + pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK); +#endif + pthread_mutex_init (&m_mutex, &mAttr); + + pthread_condattr_t cAttr; + pthread_condattr_init (&cAttr); + pthread_condattr_setpshared (&cAttr, PTHREAD_PROCESS_PRIVATE); + pthread_cond_init (&m_cond, &cAttr); +} + +SystemConditionPrivate::~SystemConditionPrivate() +{ + NS_LOG_FUNCTION_NOARGS (); + pthread_mutex_destroy (&m_mutex); + pthread_cond_destroy (&m_cond); +} + + void +SystemConditionPrivate::SetCondition (bool condition) +{ + NS_LOG_FUNCTION_NOARGS (); + m_condition = condition; +} + + bool +SystemConditionPrivate::GetCondition (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return m_condition; +} + + void +SystemConditionPrivate::Signal (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + pthread_mutex_lock (&m_mutex); + pthread_cond_signal (&m_cond); + pthread_mutex_unlock (&m_mutex); +} + + void +SystemConditionPrivate::Broadcast (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + pthread_mutex_lock (&m_mutex); + pthread_cond_broadcast (&m_cond); + pthread_mutex_unlock (&m_mutex); +} + + void +SystemConditionPrivate::Wait (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + pthread_mutex_lock (&m_mutex); + m_condition = false; + while (m_condition == false) + { + pthread_cond_wait (&m_cond, &m_mutex); + } + pthread_mutex_unlock (&m_mutex); +} + + bool +SystemConditionPrivate::TimedWait (uint64_t ns) +{ + NS_LOG_FUNCTION_NOARGS (); + + struct timespec ts; + ts.tv_sec = ns / NS_PER_SEC; + ts.tv_nsec = ns % NS_PER_SEC; + + struct timeval tv; + gettimeofday(&tv, NULL); + + ts.tv_sec += tv.tv_sec; + ts.tv_nsec += tv.tv_usec * 1000; + if (ts.tv_nsec > (int64_t)NS_PER_SEC) + { + ++ts.tv_sec; + ts.tv_nsec %= NS_PER_SEC; + } + + int rc; + + pthread_mutex_lock (&m_mutex); + while (m_condition == false) + { + rc = pthread_cond_timedwait (&m_cond, &m_mutex, &ts); + if (rc == ETIMEDOUT) + { + pthread_mutex_unlock (&m_mutex); + return true; + } + } + pthread_mutex_unlock (&m_mutex); + return false; +} + +SystemCondition::SystemCondition() + : m_priv (new SystemConditionPrivate ()) +{ + NS_LOG_FUNCTION_NOARGS (); +} + +SystemCondition::~SystemCondition () +{ + NS_LOG_FUNCTION_NOARGS (); + delete m_priv; +} + + void +SystemCondition::SetCondition (bool condition) +{ + NS_LOG_FUNCTION_NOARGS (); + m_priv->SetCondition (condition); +} + + bool +SystemCondition::GetCondition (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return m_priv->GetCondition (); +} + + void +SystemCondition::Signal (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_priv->Signal (); +} + + void +SystemCondition::Broadcast (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_priv->Broadcast (); +} + + void +SystemCondition::Wait (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_priv->Wait (); +} + + bool +SystemCondition::TimedWait (uint64_t ns) +{ + NS_LOG_FUNCTION_NOARGS (); + return m_priv->TimedWait (ns); +} + +} // namespace ns3 diff --git a/src/core/unix-system-mutex.cc b/src/core/unix-system-mutex.cc new file mode 100644 index 000000000..9a01a3a33 --- /dev/null +++ b/src/core/unix-system-mutex.cc @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include +#include +#include +#include "fatal-error.h" +#include "system-mutex.h" +#include "log.h" + +NS_LOG_COMPONENT_DEFINE ("SystemMutex"); + +namespace ns3 { + +class SystemMutexPrivate { +public: + SystemMutexPrivate (); + ~SystemMutexPrivate (); + + void Lock (void); + void Unlock (void); +private: + pthread_mutex_t m_mutex; +}; + +SystemMutexPrivate::SystemMutexPrivate () +{ + NS_LOG_FUNCTION_NOARGS (); + + pthread_mutexattr_t attr; + pthread_mutexattr_init (&attr); +// +// Make this an error checking mutex. This will check to see if the current +// thread already owns the mutex before trying to lock it. Instead of +// deadlocking it returns an error. It will also check to make sure a thread +// has previously called pthread_mutex_lock when it calls pthread_mutex_unlock. +// +// Linux and OS X (at least) have, of course chosen different names for the +// error checking flags just to make life difficult. +// +#if defined (PTHREAD_MUTEX_ERRORCHECK_NP) + pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP); +#else + pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK); +#endif + pthread_mutex_init (&m_mutex, &attr); +} + +SystemMutexPrivate::~SystemMutexPrivate() +{ + NS_LOG_FUNCTION_NOARGS (); + pthread_mutex_destroy (&m_mutex); +} + + void +SystemMutexPrivate::Lock (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + int rc = pthread_mutex_lock (&m_mutex); + if (rc != 0) + { + NS_FATAL_ERROR ("SystemMutexPrivate::Lock()" + "pthread_mutex_lock failed: " << rc << " = \"" << + strerror(rc) << "\""); + } +} + + void +SystemMutexPrivate::Unlock (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + int rc = pthread_mutex_unlock (&m_mutex); + if (rc != 0) + { + NS_FATAL_ERROR ("SystemMutexPrivate::Unlock()" + "pthread_mutex_unlock failed: " << rc << " = \"" << + strerror(rc) << "\""); + } +} + +SystemMutex::SystemMutex() + : m_priv (new SystemMutexPrivate ()) +{ + NS_LOG_FUNCTION_NOARGS (); +} + +SystemMutex::~SystemMutex() +{ + NS_LOG_FUNCTION_NOARGS (); + delete m_priv; +} + + void +SystemMutex::Lock() +{ + NS_LOG_FUNCTION_NOARGS (); + m_priv->Lock (); +} + + void +SystemMutex::Unlock() +{ + NS_LOG_FUNCTION_NOARGS (); + m_priv->Unlock (); +} + +CriticalSection::CriticalSection (SystemMutex &mutex) + : m_mutex(mutex) +{ + NS_LOG_FUNCTION_NOARGS (); + m_mutex.Lock (); +} + +CriticalSection::~CriticalSection () +{ + NS_LOG_FUNCTION_NOARGS (); + m_mutex.Unlock (); +} + +} // namespace ns3 diff --git a/src/core/unix-system-thread.cc b/src/core/unix-system-thread.cc new file mode 100644 index 000000000..16eb5ff43 --- /dev/null +++ b/src/core/unix-system-thread.cc @@ -0,0 +1,184 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include +#include +#include +#include "fatal-error.h" +#include "system-thread.h" +#include "log.h" + +NS_LOG_COMPONENT_DEFINE ("SystemThread"); + +namespace ns3 { + +// +// Private implementation class for the SystemThread class. The deal is +// that we export the SystemThread class to the user. The header just +// declares a class and its members. There is a forward declaration for +// a private implementation class there and a member declaration. Thus +// there is no knowledge of the implementation in the exported header. +// +// We provide an implementation class for each operating system. This is +// the Unix implementation of the SystemThread. +// +// In order to use the SystemThread, you will include "system-thread.h" and +// get the implementation by linking unix-system-thread.cc (if you are running +// a Posix system). +// +class SystemThreadImpl +{ +public: + SystemThreadImpl (Callback callback); + + void Start (void); + void Join (void); + void Shutdown (void); + bool Break (void); + +private: + static void *DoRun (void *arg); + Callback m_callback; + pthread_t m_thread; + bool m_break; + void * m_ret; +}; + +SystemThreadImpl::SystemThreadImpl (Callback callback) + : m_callback (callback) +{ + NS_LOG_FUNCTION_NOARGS (); + // Make sure we have a SIGALRM handler which does not terminate + // our process. + struct sigaction act; + act.sa_flags = 0; + sigemptyset (&act.sa_mask); + act.sa_handler = SIG_IGN; + sigaction (SIGALRM, &act, 0); +} + + void +SystemThreadImpl::Start (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + int rc = pthread_create (&m_thread, NULL, &SystemThreadImpl::DoRun, + (void *)this); + + if (rc) + { + NS_FATAL_ERROR ("pthread_create failed: " << rc << "=\"" << + strerror(rc) << "\"."); + } +} + + void +SystemThreadImpl::Join (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + void *thread_return; + int rc = pthread_join (m_thread, &thread_return); + if (rc) + { + NS_FATAL_ERROR ("pthread_join failed: " << rc << "=\"" << + strerror(rc) << "\"."); + } +} + + void +SystemThreadImpl::Shutdown (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + m_break = true; + + // send a SIGALRM signal on the target thread to make sure that it + // will unblock. + pthread_kill (m_thread, SIGALRM); +} + + bool +SystemThreadImpl::Break (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + return m_break; +} + + void * +SystemThreadImpl::DoRun (void *arg) +{ + NS_LOG_FUNCTION_NOARGS (); + + SystemThreadImpl *self = static_cast (arg); + self->m_callback (); + + return 0; +} + +// +// Remember that we just export the delcaration of the SystemThread class to +// the user. There is no code to implement the SystemThread methods. We +// have to do that here. We just vector the calls to our implementation +// class above. +// +SystemThread::SystemThread (Callback callback) + : m_impl (new SystemThreadImpl (callback)), + m_count (1) +{ + NS_LOG_FUNCTION_NOARGS (); +} + +SystemThread::~SystemThread() +{ + NS_LOG_FUNCTION_NOARGS (); + delete m_impl; +} + + void +SystemThread::Start (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_impl->Start (); +} + + void +SystemThread::Join (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_impl->Join (); +} + + void +SystemThread::Shutdown (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_impl->Shutdown (); +} + + bool +SystemThread::Break (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return m_impl->Break (); +} + +} // namespace ns3 diff --git a/src/core/wscript b/src/core/wscript index bf7ca3b5d..586b0ee95 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -21,10 +21,24 @@ def configure(conf): e.define = 'HAVE_SIGNAL_H' e.run() + e = conf.create_library_configurator() + e.mandatory = False + e.name = 'rt' + e.define = 'HAVE_RT' + e.uselib = 'RT' + e.run() + + e = conf.create_header_configurator() + e.mandatory = False + e.name = 'pthread.h' + e.define = 'HAVE_PTHREAD_H' + conf.env['ENABLE_THREADING'] = e.run() + conf.report_optional_feature("Threading", "Threading Primitives", + conf.env['ENABLE_THREADING'], + " include not detected") + conf.write_config_header('ns3/core-config.h') - - def build(bld): core = bld.create_ns3_module('core') core.source = [ @@ -40,7 +54,6 @@ def build(bld): 'test.cc', 'random-variable.cc', 'rng-stream.cc', - 'uid-manager.cc', 'command-line.cc', 'type-name.cc', 'type-traits-test.cc', @@ -59,17 +72,10 @@ def build(bld): 'traced-callback.cc', 'trace-source-accessor.cc', 'config.cc', + 'callback.cc', ] + core.uselib = 'RT' - if sys.platform == 'win32': - core.source.extend([ - 'win32-system-wall-clock-ms.cc', - ]) - else: - core.source.extend([ - 'unix-system-wall-clock-ms.cc', - ]) - headers = bld.create_obj('ns3header') headers.module = 'core' headers.source = [ @@ -110,5 +116,28 @@ def build(bld): 'trace-source-accessor.h', 'config.h', 'object-vector.h', + 'deprecated.h', + 'abort.h', ] + if sys.platform == 'win32': + core.source.extend([ + 'win32-system-wall-clock-ms.cc', + ]) + else: + core.source.extend([ + 'unix-system-wall-clock-ms.cc', + ]) + + if bld.env()['ENABLE_THREADING']: + core.source.extend([ + 'unix-system-thread.cc', + 'unix-system-mutex.cc', + 'unix-system-condition.cc', + ]) + headers.source.extend([ + 'system-mutex.h', + 'system-thread.h', + 'system-condition.h', + ]) + diff --git a/src/devices/bridge/bridge-channel.cc b/src/devices/bridge/bridge-channel.cc new file mode 100644 index 000000000..e5eac7a54 --- /dev/null +++ b/src/devices/bridge/bridge-channel.cc @@ -0,0 +1,83 @@ +/* -*- 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 + * + * Author: Gustavo Carneiro + */ + +#include "ns3/log.h" +#include "bridge-channel.h" + +NS_LOG_COMPONENT_DEFINE ("BridgeChannel"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (BridgeChannel); + +TypeId +BridgeChannel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::BridgeChannel") + .SetParent (); + return tid; +} + +BridgeChannel::BridgeChannel () + : Channel ("BridgeChannel") +{ + NS_LOG_FUNCTION_NOARGS (); +} + +BridgeChannel::~BridgeChannel () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +void +BridgeChannel::AddChannel (Ptr bridgedChannel) +{ + m_bridgedChannels.push_back (bridgedChannel); +} + +uint32_t +BridgeChannel::GetNDevices (void) const +{ + uint32_t ndevices = 0; + for (std::vector< Ptr >::const_iterator iter = m_bridgedChannels.begin (); + iter != m_bridgedChannels.end (); iter++) + { + ndevices += (*iter)->GetNDevices (); + } + return ndevices; +} + + +Ptr +BridgeChannel::GetDevice (uint32_t i) const +{ + uint32_t ndevices = 0; + for (std::vector< Ptr >::const_iterator iter = m_bridgedChannels.begin (); + iter != m_bridgedChannels.end (); iter++) + { + if ((i - ndevices) < (*iter)->GetNDevices ()) + { + return (*iter)->GetDevice (i - ndevices); + } + ndevices += (*iter)->GetNDevices (); + } + return NULL; +} + + +} // namespace ns3 diff --git a/src/devices/bridge/bridge-channel.h b/src/devices/bridge/bridge-channel.h new file mode 100644 index 000000000..34ba227bf --- /dev/null +++ b/src/devices/bridge/bridge-channel.h @@ -0,0 +1,56 @@ +/* -*- 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 + * + * Author: Gustavo Carneiro + */ +#ifndef BRIDGE_CHANNEL_H +#define BRIDGE_CHANNEL_H + +#include "ns3/net-device.h" +#include "ns3/channel.h" +#include + +namespace ns3 { + +/** + * \ingroup bridge + * + * \brief Virtual channel implementation for bridges (BridgeNetDevice). + * + * Just like BridgeNetDevice aggregates multiple NetDevices, + * BridgeChannel aggregates multiple channels and make them appear as + * a single channel to upper layers. + */ +class BridgeChannel : public Channel +{ +public: + static TypeId GetTypeId (void); + BridgeChannel (); + virtual ~BridgeChannel (); + + void AddChannel (Ptr bridgedChannel); + + // virtual methods implementation, from Channel + virtual uint32_t GetNDevices (void) const; + virtual Ptr GetDevice (uint32_t i) const; + +private: + std::vector< Ptr > m_bridgedChannels; + +}; + +} // namespace ns3 + +#endif /* BRIDGE_CHANNEL_H */ diff --git a/src/devices/bridge/bridge-net-device.cc b/src/devices/bridge/bridge-net-device.cc new file mode 100644 index 000000000..1a7e561ff --- /dev/null +++ b/src/devices/bridge/bridge-net-device.cc @@ -0,0 +1,393 @@ +/* -*- 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 + * + * Author: Gustavo Carneiro + */ +#include "bridge-net-device.h" +#include "ns3/node.h" +#include "ns3/channel.h" +#include "ns3/packet.h" +#include "ns3/log.h" +#include "ns3/boolean.h" +#include "ns3/simulator.h" + +NS_LOG_COMPONENT_DEFINE ("BridgeNetDevice"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (BridgeNetDevice); + + +TypeId +BridgeNetDevice::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::BridgeNetDevice") + .SetParent () + .AddConstructor () + .AddAttribute ("EnableLearning", + "Enable the learning mode of the Learning Bridge", + BooleanValue (true), + MakeBooleanAccessor (&BridgeNetDevice::m_enableLearning), + MakeBooleanChecker ()) + .AddAttribute ("ExpirationTime", + "Time it takes for learned MAC state entry to expire.", + TimeValue (Seconds (30)), + MakeTimeAccessor (&BridgeNetDevice::m_expirationTime), + MakeTimeChecker ()) + ; + return tid; +} + + +BridgeNetDevice::BridgeNetDevice () + : m_node (0), + m_name (""), + m_ifIndex (0), + m_mtu (0xffff) +{ + m_channel = CreateObject (); +} + +void +BridgeNetDevice::ReceiveFromDevice (Ptr incomingPort, Ptr packet, uint16_t protocol, + Address const &src, Address const &dst, PacketType packetType) +{ + NS_LOG_FUNCTION_NOARGS (); + NS_LOG_DEBUG ("UID is " << packet->GetUid ()); + + Mac48Address src48 = Mac48Address::ConvertFrom (src); + Mac48Address dst48 = Mac48Address::ConvertFrom (dst); + + if (!m_promiscRxCallback.IsNull ()) + { + m_promiscRxCallback (this, packet, protocol, src, dst, packetType); + } + + switch (packetType) + { + case PACKET_HOST: + if (dst48 == m_address) + { + m_rxCallback (this, packet, protocol, src); + } + break; + + case PACKET_BROADCAST: + case PACKET_MULTICAST: + m_rxCallback (this, packet, protocol, src); + ForwardBroadcast (incomingPort, packet, protocol, src48, dst48); + break; + + case PACKET_OTHERHOST: + ForwardUnicast (incomingPort, packet, protocol, src48, dst48); + break; + } +} + +void +BridgeNetDevice::ForwardUnicast (Ptr incomingPort, Ptr packet, + uint16_t protocol, Mac48Address src, Mac48Address dst) +{ + NS_LOG_DEBUG ("LearningBridgeForward (incomingPort=" << incomingPort->GetName () + << ", packet=" << packet << ", protocol="< outPort = GetLearnedState (dst); + if (outPort != NULL && outPort != incomingPort) + { + NS_LOG_LOGIC ("Learning bridge state says to use port `" << outPort->GetName () << "'"); + outPort->SendFrom (packet->Copy (), src, dst, protocol); + } + else + { + NS_LOG_LOGIC ("No learned state: send through all ports"); + for (std::vector< Ptr >::iterator iter = m_ports.begin (); + iter != m_ports.end (); iter++) + { + Ptr port = *iter; + if (port != incomingPort) + { + NS_LOG_LOGIC ("LearningBridgeForward (" << src << " => " << dst << "): " << incomingPort->GetName () + << " --> " << port->GetName () + << " (UID " << packet->GetUid () << ")."); + port->SendFrom (packet->Copy (), src, dst, protocol); + } + } + } +} + +void +BridgeNetDevice::ForwardBroadcast (Ptr incomingPort, Ptr packet, + uint16_t protocol, Mac48Address src, Mac48Address dst) +{ + NS_LOG_DEBUG ("LearningBridgeForward (incomingPort=" << incomingPort->GetName () + << ", packet=" << packet << ", protocol="< >::iterator iter = m_ports.begin (); + iter != m_ports.end (); iter++) + { + Ptr port = *iter; + if (port != incomingPort) + { + NS_LOG_LOGIC ("LearningBridgeForward (" << src << " => " << dst << "): " << incomingPort->GetName () + << " --> " << port->GetName () + << " (UID " << packet->GetUid () << ")."); + port->SendFrom (packet->Copy (), src, dst, protocol); + } + } +} + +void BridgeNetDevice::Learn (Mac48Address source, Ptr port) +{ + if (m_enableLearning) + { + LearnedState &state = m_learnState[source]; + state.associatedPort = port; + state.expirationTime = Simulator::Now () + m_expirationTime; + } +} + +Ptr BridgeNetDevice::GetLearnedState (Mac48Address source) +{ + if (m_enableLearning) + { + Time now = Simulator::Now (); + std::map::iterator iter = + m_learnState.find (source); + if (iter != m_learnState.end ()) + { + LearnedState &state = iter->second; + if (state.expirationTime > now) + { + return state.associatedPort; + } + else + { + m_learnState.erase (iter); + } + } + } + return NULL; +} + +void +BridgeNetDevice::AddBridgePort (Ptr bridgePort) +{ + NS_ASSERT (bridgePort != this); + if (!Mac48Address::IsMatchingType (bridgePort->GetAddress ())) + { + NS_FATAL_ERROR ("Device does not support eui 48 addresses: cannot be added to bridge."); + } + if (!bridgePort->SupportsSendFrom ()) + { + NS_FATAL_ERROR ("Device does not support SendFrom: cannot be added to bridge."); + } + if (m_address == Mac48Address ()) + { + m_address = Mac48Address::ConvertFrom (bridgePort->GetAddress ()); + } + + NS_LOG_DEBUG ("RegisterProtocolHandler for " << bridgePort->GetName ()); + m_node->RegisterProtocolHandler (MakeCallback (&BridgeNetDevice::ReceiveFromDevice, this), + 0, bridgePort, true); + m_ports.push_back (bridgePort); + m_channel->AddChannel (bridgePort->GetChannel ()); +} + +void +BridgeNetDevice::SetName(const std::string name) +{ + m_name = name; +} + +std::string +BridgeNetDevice::GetName(void) const +{ + return m_name; +} + +void +BridgeNetDevice::SetIfIndex(const uint32_t index) +{ + m_ifIndex = index; +} + +uint32_t +BridgeNetDevice::GetIfIndex(void) const +{ + return m_ifIndex; +} + +Ptr +BridgeNetDevice::GetChannel (void) const +{ + return m_channel; +} + +Address +BridgeNetDevice::GetAddress (void) const +{ + return m_address; +} + +bool +BridgeNetDevice::SetMtu (const uint16_t mtu) +{ + m_mtu = mtu; + return true; +} + +uint16_t +BridgeNetDevice::GetMtu (void) const +{ + return m_mtu; +} + + +bool +BridgeNetDevice::IsLinkUp (void) const +{ + return true; +} + + +void +BridgeNetDevice::SetLinkChangeCallback (Callback callback) +{} + + +bool +BridgeNetDevice::IsBroadcast (void) const +{ + return true; +} + + +Address +BridgeNetDevice::GetBroadcast (void) const +{ + return Mac48Address ("ff:ff:ff:ff:ff:ff"); +} + +bool +BridgeNetDevice::IsMulticast (void) const +{ + return true; +} + + +Address +BridgeNetDevice::GetMulticast (void) const +{ + return Mac48Address ("01:00:5e:00:00:00"); +} + + +Address +BridgeNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const +{ + NS_LOG_FUNCTION (this << multicastGroup); + Mac48Address multicast = Mac48Address::GetMulticast (multicastGroup); + return multicast; +} + + +bool +BridgeNetDevice::IsPointToPoint (void) const +{ + return false; +} + + +bool +BridgeNetDevice::Send (Ptr packet, const Address& dest, uint16_t protocolNumber) +{ + for (std::vector< Ptr >::iterator iter = m_ports.begin (); + iter != m_ports.end (); iter++) + { + Ptr port = *iter; + port->SendFrom (packet, m_address, dest, protocolNumber); + } + + return true; +} + +bool +BridgeNetDevice::SendFrom (Ptr packet, const Address& src, const Address& dest, uint16_t protocolNumber) +{ + for (std::vector< Ptr >::iterator iter = m_ports.begin (); + iter != m_ports.end (); iter++) + { + Ptr port = *iter; + port->SendFrom (packet, src, dest, protocolNumber); + } + + return true; +} + + +Ptr +BridgeNetDevice::GetNode (void) const +{ + return m_node; +} + + +void +BridgeNetDevice::SetNode (Ptr node) +{ + m_node = node; +} + + +bool +BridgeNetDevice::NeedsArp (void) const +{ + return true; +} + + +void +BridgeNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) +{ + m_rxCallback = cb; +} + +void +BridgeNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb) +{ + m_promiscRxCallback = cb; +} + +bool +BridgeNetDevice::SupportsSendFrom () const +{ + return true; +} + + +void +BridgeNetDevice::DoDispose (void) +{ + m_node = 0; + NetDevice::DoDispose (); +} + + + +} // namespace ns3 diff --git a/src/devices/bridge/bridge-net-device.h b/src/devices/bridge/bridge-net-device.h new file mode 100644 index 000000000..ed232cce9 --- /dev/null +++ b/src/devices/bridge/bridge-net-device.h @@ -0,0 +1,146 @@ +/* -*- 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 + * + * Author: Gustavo Carneiro + */ +#ifndef BRIDGE_NET_DEVICE_H +#define BRIDGE_NET_DEVICE_H + +#include "ns3/net-device.h" +#include "ns3/mac48-address.h" +#include "ns3/nstime.h" +#include "ns3/bridge-channel.h" +#include +#include +#include + +namespace ns3 { + +class Node; + +/** + * \ingroup devices + * \defgroup bridge Bridge + * + * \brief a virtual net device that bridges multiple LAN segments + * + * The BridgeNetDevice object is a "virtual" netdevice that aggregates + * multiple "real" netdevices and implements the data plane forwarding + * part of IEEE 802.1D. By adding a BridgeNetDevice to a Node, it + * will act as a "bridge", or "switch", to multiple LAN segments. + * + * By default the bridge netdevice implements a "learning bridge" + * algorithm (see 802.1D), where incoming unicast frames from one port + * may occasionally be forwarded throughout all other ports, but + * usually they are forwarded only to a single correct output port. + * + * \attention The Spanning Tree Protocol part of 802.1D is not + * implemented. Therefore, you have to be careful not to create + * bridging loops, or else the network will collapse. + * + * \attention Bridging is designed to work only with NetDevices + * modelling IEEE 802-style technologies, such as CsmaNetDevice and + * WifiNetDevice. + * + * \attention If including a WifiNetDevice in a bridge, the wifi + * device must be in Access Point mode. Adhoc mode is not supported + * with bridging. + */ + +/** + * \ingroup bridge + * \brief a virtual net device that bridges multiple LAN segments + */ +class BridgeNetDevice : public NetDevice +{ +public: + static TypeId GetTypeId (void); + BridgeNetDevice (); + + /** \brief Add a 'port' to a bridge device + * + * This method adds a new bridge port to a BridgeNetDevice, so that + * the new bridge port NetDevice becomes part of the bridge and L2 + * frames start being forwarded to/from this NetDevice. + * + * \attention The netdevice that is being added as bridge port must + * _not_ have an IP address. In order to add IP connectivity to a + * bridging node you must enable IP on the BridgeNetDevice itself, + * never on its port netdevices. + */ + void AddBridgePort (Ptr bridgePort); + + // inherited from NetDevice base class. + virtual void SetName(const std::string name); + virtual std::string GetName(void) const; + virtual void SetIfIndex(const uint32_t index); + virtual uint32_t GetIfIndex(void) const; + virtual Ptr GetChannel (void) const; + virtual Address GetAddress (void) const; + virtual bool SetMtu (const uint16_t mtu); + virtual uint16_t GetMtu (void) const; + virtual bool IsLinkUp (void) const; + virtual void SetLinkChangeCallback (Callback callback); + virtual bool IsBroadcast (void) const; + virtual Address GetBroadcast (void) const; + virtual bool IsMulticast (void) const; + virtual Address GetMulticast (void) const; + virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const; + virtual bool IsPointToPoint (void) const; + virtual bool Send (Ptr packet, const Address& dest, uint16_t protocolNumber); + virtual bool SendFrom (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); + virtual Ptr GetNode (void) const; + virtual void SetNode (Ptr node); + virtual bool NeedsArp (void) const; + virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); + virtual void SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb); + virtual bool SupportsSendFrom () const; + +protected: + virtual void DoDispose (void); + + void ReceiveFromDevice (Ptr device, Ptr packet, uint16_t protocol, + Address const &source, Address const &destination, PacketType packetType); + void ForwardUnicast (Ptr incomingPort, Ptr packet, + uint16_t protocol, Mac48Address src, Mac48Address dst); + void ForwardBroadcast (Ptr incomingPort, Ptr packet, + uint16_t protocol, Mac48Address src, Mac48Address dst); + void Learn (Mac48Address source, Ptr port); + Ptr GetLearnedState (Mac48Address source); + +private: + NetDevice::ReceiveCallback m_rxCallback; + NetDevice::PromiscReceiveCallback m_promiscRxCallback; + + Mac48Address m_address; + Time m_expirationTime; // time it takes for learned MAC state to expire + struct LearnedState + { + Ptr associatedPort; + Time expirationTime; + }; + std::map m_learnState; + Ptr m_node; + Ptr m_channel; + std::string m_name; + std::vector< Ptr > m_ports; + uint32_t m_ifIndex; + uint16_t m_mtu; + bool m_enableLearning; +}; + +} // namespace ns3 + +#endif /* BRIDGE_NET_DEVICE_H */ diff --git a/src/devices/bridge/waf b/src/devices/bridge/waf new file mode 100755 index 000000000..4283ec141 --- /dev/null +++ b/src/devices/bridge/waf @@ -0,0 +1 @@ +exec "`dirname "$0"`"/../../../waf "$@" diff --git a/src/devices/bridge/wscript b/src/devices/bridge/wscript new file mode 100644 index 000000000..fec55457e --- /dev/null +++ b/src/devices/bridge/wscript @@ -0,0 +1,14 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_module('bridge', ['node']) + obj.source = [ + 'bridge-net-device.cc', + 'bridge-channel.cc', + ] + headers = bld.create_obj('ns3header') + headers.module = 'bridge' + headers.source = [ + 'bridge-net-device.h', + 'bridge-channel.h', + ] diff --git a/src/devices/csma/backoff.cc b/src/devices/csma/backoff.cc index e01355efa..e249104fa 100644 --- a/src/devices/csma/backoff.cc +++ b/src/devices/csma/backoff.cc @@ -22,7 +22,7 @@ namespace ns3 { -Backoff::Backoff() +Backoff::Backoff () { m_slotTime = MicroSeconds(1); m_minSlots = 1; @@ -33,8 +33,7 @@ Backoff::Backoff() ResetBackoffTime(); } -Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots, - uint32_t ceiling, uint32_t maxRetries) +Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots, uint32_t ceiling, uint32_t maxRetries) { m_slotTime = slotTime; m_minSlots = minSlots; @@ -50,32 +49,42 @@ Backoff::GetBackoffTime (void) uint32_t ceiling; if ((m_ceiling > 0) &&(m_numBackoffRetries > m_ceiling)) - ceiling = m_ceiling; + { + ceiling = m_ceiling; + } else - ceiling = m_numBackoffRetries; + { + ceiling = m_numBackoffRetries; + } uint32_t minSlot = m_minSlots; - uint32_t maxSlot = (uint32_t)pow(2, ceiling) - 1; + uint32_t maxSlot = (uint32_t)pow (2, ceiling) - 1; if (maxSlot > m_maxSlots) - maxSlot = m_maxSlots; + { + maxSlot = m_maxSlots; + } - uint32_t backoffSlots = - (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot); + uint32_t backoffSlots = (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot); backoff = Scalar(backoffSlots) * m_slotTime; return (backoff); } -void Backoff::ResetBackoffTime (void) +void +Backoff::ResetBackoffTime (void) { m_numBackoffRetries = 0; } -bool Backoff::MaxRetriesReached(void) { +bool +Backoff::MaxRetriesReached (void) +{ return (m_numBackoffRetries >= m_maxRetries); } -void Backoff::IncrNumRetries(void) { +void +Backoff::IncrNumRetries (void) +{ m_numBackoffRetries++; } diff --git a/src/devices/csma/backoff.h b/src/devices/csma/backoff.h index adf270076..d15de4452 100644 --- a/src/devices/csma/backoff.h +++ b/src/devices/csma/backoff.h @@ -36,49 +36,63 @@ namespace ns3 { 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. + /** + * Minimum number of backoff slots (when multiplied by m_slotTime, determines minimum backoff time) + */ + uint32_t m_minSlots; - Backoff(); - Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots, - uint32_t ceiling, uint32_t maxRetries); + /** + * Maximim number of backoff slots (when multiplied by m_slotTime, determines maximum backoff time) + */ + uint32_t m_maxSlots; + + /** + * Caps the exponential function when the number of retries reaches m_ceiling. + */ + uint32_t m_ceiling; + + /** + * Maximum number of transmission retries before the packet is dropped. + */ + uint32_t m_maxRetries; + + /** + * Length of one slot. A slot time, it usually the packet transmission time, if the packet size is fixed. + */ + Time m_slotTime; + + Backoff (void); + 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(); + void ResetBackoffTime (void); + /** * \return True if the maximum number of retries has been reached */ - bool MaxRetriesReached(); + bool MaxRetriesReached (void); + /** * Increments the number of retries by 1. */ - void IncrNumRetries(); + void IncrNumRetries (void); private: - uint32_t m_numBackoffRetries; // Number of times that the - // transmitter has tried to - // unsuccessfully transmit the current - // packet + + /** + * Number of times that the transmitter has tried to unsuccessfully transmit the current packet. + */ + uint32_t m_numBackoffRetries; }; }; // namespace ns3 diff --git a/src/devices/csma/csma-channel.cc b/src/devices/csma/csma-channel.cc index 9809daa4e..ab2a83bf3 100644 --- a/src/devices/csma/csma-channel.cc +++ b/src/devices/csma/csma-channel.cc @@ -37,8 +37,7 @@ CsmaChannel::GetTypeId (void) .SetParent () .AddConstructor () .AddAttribute ("DataRate", - "The transmission data rate to be provided to devices " - "connected to the channel", + "The transmission data rate to be provided to devices connected to the channel", DataRateValue (DataRate (0xffffffff)), MakeDataRateAccessor (&CsmaChannel::m_bps), MakeDataRateChecker ()) @@ -126,16 +125,15 @@ CsmaChannel::Detach (uint32_t deviceId) { if (!m_deviceList[deviceId].active) { - NS_LOG_WARN ("CsmaChannel::Detach(): " - "Device is already detached (" << deviceId << ")"); + NS_LOG_WARN ("CsmaChannel::Detach(): Device is already detached (" << deviceId << ")"); return false; } m_deviceList[deviceId].active = false; + if ((m_state == TRANSMITTING) && (m_currentSrc == deviceId)) { - NS_LOG_WARN ("CsmaChannel::Detach(): Device is currently" << - "transmitting (" << deviceId << ")"); + NS_LOG_WARN ("CsmaChannel::Detach(): Device is currently" << "transmitting (" << deviceId << ")"); } return true; @@ -178,8 +176,7 @@ CsmaChannel::TransmitStart (Ptr p, uint32_t srcId) if (!IsActive(srcId)) { - NS_LOG_ERROR ("CsmaChannel::TransmitStart(): " - "Seclected source is not currently attached to network"); + NS_LOG_ERROR ("CsmaChannel::TransmitStart(): Seclected source is not currently attached to network"); return false; } @@ -209,8 +206,7 @@ CsmaChannel::TransmitEnd() if (!IsActive (m_currentSrc)) { - NS_LOG_ERROR ("CsmaChannel::TransmitEnd(): " - "Seclected source was detached before the end of the transmission"); + NS_LOG_ERROR ("CsmaChannel::TransmitEnd(): Seclected source was detached before the end of the transmission"); retVal = false; } @@ -232,12 +228,14 @@ CsmaChannel::PropagationCompleteEvent() NS_LOG_LOGIC ("Receive"); std::vector::iterator it; + uint32_t devId = 0; for (it = m_deviceList.begin (); it < m_deviceList.end(); it++) { if (it->IsActive ()) { - it->devicePtr->Receive (m_currentPkt->Copy ()); + it->devicePtr->Receive (m_currentPkt->Copy (), m_deviceList[m_currentSrc].devicePtr); } + devId++; } m_state = IDLE; } @@ -257,10 +255,6 @@ CsmaChannel::GetNumActDevices (void) 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 { diff --git a/src/devices/csma/csma-channel.h b/src/devices/csma/csma-channel.h index f2771ccb9..ff92825b3 100644 --- a/src/devices/csma/csma-channel.h +++ b/src/devices/csma/csma-channel.h @@ -32,39 +32,37 @@ class Packet; 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); + /** - * \brief CsmaNetDevice Record - * - * Stores the information related to each net device that is - * connected to the channel. + * \return If the net device pointed to by the devicePtr is active + * and ready to RX/TX. */ - class CsmaDeviceRec { - public: - Ptr< CsmaNetDevice > devicePtr; /// Pointer to the net device - bool active; /// Is net device enabled to TX/RX + bool IsActive(); +}; - 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 */ }; - /** - * 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. * diff --git a/src/devices/csma/csma-net-device.cc b/src/devices/csma/csma-net-device.cc index faaddc7d6..391027d46 100644 --- a/src/devices/csma/csma-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -27,6 +27,7 @@ #include "ns3/error-model.h" #include "ns3/enum.h" #include "ns3/boolean.h" +#include "ns3/uinteger.h" #include "ns3/pointer.h" #include "ns3/trace-source-accessor.h" #include "csma-net-device.h" @@ -38,24 +39,28 @@ namespace ns3 { NS_OBJECT_ENSURE_REGISTERED (CsmaNetDevice); -TypeId + TypeId CsmaNetDevice::GetTypeId (void) { static TypeId tid = TypeId ("ns3::CsmaNetDevice") .SetParent () .AddConstructor () .AddAttribute ("Address", - "The address of this device.", + "The MAC address of this device.", Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")), MakeMac48AddressAccessor (&CsmaNetDevice::m_address), MakeMac48AddressChecker ()) + .AddAttribute ("FrameSize", + "The maximum size of a packet sent over this device.", + UintegerValue (DEFAULT_FRAME_SIZE), + MakeUintegerAccessor (&CsmaNetDevice::SetFrameSize, + &CsmaNetDevice::GetFrameSize), + MakeUintegerChecker ()) .AddAttribute ("EncapsulationMode", "The link-layer encapsulation type to use.", - EnumValue (LLC), - MakeEnumAccessor (&CsmaNetDevice::m_encapMode), - MakeEnumChecker (ETHERNET_V1, "EthernetV1", - IP_ARP, "IpArp", - RAW, "Raw", + EnumValue (DIX), + MakeEnumAccessor (&CsmaNetDevice::SetEncapsulationMode), + MakeEnumChecker (DIX, "Dix", LLC, "Llc")) .AddAttribute ("SendEnable", "Enable or disable the transmitter section of the device.", @@ -78,7 +83,7 @@ CsmaNetDevice::GetTypeId (void) MakePointerAccessor (&CsmaNetDevice::m_queue), MakePointerChecker ()) .AddTraceSource ("Rx", - "Trace source to fire on reception of a MAC packet.", + "The trace source to fire on reception of a MAC packet.", MakeTraceSourceAccessor (&CsmaNetDevice::m_rxTrace)) .AddTraceSource ("Drop", "Trace source to fire on when a MAC packet is dropped.", @@ -89,13 +94,23 @@ CsmaNetDevice::GetTypeId (void) CsmaNetDevice::CsmaNetDevice () : m_name (""), - m_linkUp (false), - m_mtu (0xffff) + m_linkUp (false) { NS_LOG_FUNCTION (this); m_txMachineState = READY; m_tInterframeGap = Seconds (0); m_channel = 0; + + // + // We would like to let the attribute system take care of initializing the packet encapsulation stuff, but we also don't want to + // get caught up in initialization order changes. So we'll get the three problem variables into a consistent state here before the + // attribute calls, and then depend on the semantics of the setters to preserve a consistent state. This really doesn't have to be + // the same set of values as the initial values set by the attributes, but it does have to be a consistent set. That is, you can + // just change the ddfault encapsulation mode above without having to change it here. We keep it the same for GP. + // + m_encapMode = DIX; + m_frameSize = DEFAULT_FRAME_SIZE; + m_mtu = MtuFromFrameSize (m_frameSize); } CsmaNetDevice::~CsmaNetDevice() @@ -113,23 +128,153 @@ CsmaNetDevice::DoDispose () NetDevice::DoDispose (); } + uint32_t +CsmaNetDevice::MtuFromFrameSize (uint32_t frameSize) +{ + NS_LOG_FUNCTION (frameSize); + + NS_ASSERT_MSG (frameSize <= std::numeric_limits::max (), + "CsmaNetDevice::MtuFromFrameSize(): Frame size should be derived from 16-bit quantity: " << frameSize); + + uint32_t newSize; + + switch (m_encapMode) + { + case DIX: + newSize = frameSize - ETHERNET_OVERHEAD; + break; + case LLC: + { + LlcSnapHeader llc; + + NS_ASSERT_MSG ((uint32_t)(frameSize - ETHERNET_OVERHEAD) >= llc.GetSerializedSize (), + "CsmaNetDevice::MtuFromFrameSize(): Given frame size too small to support LLC mode"); + newSize = frameSize - ETHERNET_OVERHEAD - llc.GetSerializedSize (); + } + break; + case ILLEGAL: + default: + NS_FATAL_ERROR ("CsmaNetDevice::MtuFromFrameSize(): Unknown packet encapsulation mode"); + return 0; + } + + return newSize; +} + + uint32_t +CsmaNetDevice::FrameSizeFromMtu (uint32_t mtu) +{ + NS_LOG_FUNCTION (mtu); + + uint32_t newSize; + + switch (m_encapMode) + { + case DIX: + newSize = mtu + ETHERNET_OVERHEAD; + break; + case LLC: + { + LlcSnapHeader llc; + newSize = mtu + ETHERNET_OVERHEAD + llc.GetSerializedSize (); + } + break; + case ILLEGAL: + default: + NS_FATAL_ERROR ("CsmaNetDevice::FrameSizeFromMtu(): Unknown packet encapsulation mode"); + return 0; + } + + return newSize; +} + + void +CsmaNetDevice::SetEncapsulationMode (enum EncapsulationMode mode) +{ + NS_LOG_FUNCTION (mode); + + m_encapMode = mode; + m_mtu = MtuFromFrameSize (m_frameSize); + + NS_LOG_LOGIC ("m_encapMode = " << m_encapMode); + NS_LOG_LOGIC ("m_frameSize = " << m_frameSize); + NS_LOG_LOGIC ("m_mtu = " << m_mtu); +} + + CsmaNetDevice::EncapsulationMode +CsmaNetDevice::GetEncapsulationMode (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return m_encapMode; +} + + bool +CsmaNetDevice::SetMtu (uint16_t mtu) +{ + NS_LOG_FUNCTION (mtu); + + uint32_t newFrameSize = FrameSizeFromMtu (mtu); + + if (newFrameSize > std::numeric_limits::max ()) + { + NS_LOG_WARN ("CsmaNetDevice::SetMtu(): Frame size overflow, MTU not set."); + return false; + } + + m_frameSize = newFrameSize; + m_mtu = mtu; + + NS_LOG_LOGIC ("m_encapMode = " << m_encapMode); + NS_LOG_LOGIC ("m_frameSize = " << m_frameSize); + NS_LOG_LOGIC ("m_mtu = " << m_mtu); + + return true; +} + + uint16_t +CsmaNetDevice::GetMtu (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_mtu; +} + + void +CsmaNetDevice::SetFrameSize (uint16_t frameSize) +{ + NS_LOG_FUNCTION (frameSize); + + m_frameSize = frameSize; + m_mtu = MtuFromFrameSize (frameSize); + + NS_LOG_LOGIC ("m_encapMode = " << m_encapMode); + NS_LOG_LOGIC ("m_frameSize = " << m_frameSize); + NS_LOG_LOGIC ("m_mtu = " << m_mtu); +} + + uint16_t +CsmaNetDevice::GetFrameSize (void) const +{ + return m_frameSize; +} + void CsmaNetDevice::SetAddress (Mac48Address self) { + NS_LOG_FUNCTION (self); m_address = self; } void CsmaNetDevice::SetSendEnable (bool sendEnable) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (sendEnable); m_sendEnable = sendEnable; } void CsmaNetDevice::SetReceiveEnable (bool receiveEnable) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (receiveEnable); m_receiveEnable = receiveEnable; } @@ -137,32 +282,27 @@ CsmaNetDevice::SetReceiveEnable (bool receiveEnable) CsmaNetDevice::IsSendEnabled (void) { NS_LOG_FUNCTION_NOARGS (); - return (m_sendEnable); + return m_sendEnable; } bool CsmaNetDevice::IsReceiveEnabled (void) { NS_LOG_FUNCTION_NOARGS (); - return (m_receiveEnable); + return m_receiveEnable; } void CsmaNetDevice::SetInterframeGap (Time t) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (t); m_tInterframeGap = t; } void -CsmaNetDevice::SetBackoffParams ( - Time slotTime, - uint32_t minSlots, - uint32_t maxSlots, - uint32_t ceiling, - uint32_t maxRetries) +CsmaNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots, uint32_t ceiling, uint32_t maxRetries) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (slotTime << minSlots << maxSlots << ceiling << maxRetries); m_backoff.m_slotTime = slotTime; m_backoff.m_minSlots = minSlots; m_backoff.m_maxSlots = maxSlots; @@ -171,47 +311,55 @@ CsmaNetDevice::SetBackoffParams ( } void -CsmaNetDevice::AddHeader ( - Ptr p, - Mac48Address dest, - uint16_t protocolNumber) +CsmaNetDevice::AddHeader (Ptr p, Mac48Address source, Mac48Address dest, uint16_t protocolNumber) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (p << source << dest << protocolNumber); - if (m_encapMode == RAW) - { - return; - } - - Mac48Address source = Mac48Address::ConvertFrom (GetAddress ()); EthernetHeader header (false); header.SetSource (source); header.SetDestination (dest); EthernetTrailer trailer; + NS_LOG_LOGIC ("p->GetSize () = " << p->GetSize ()); + NS_LOG_LOGIC ("m_encapMode = " << m_encapMode); + NS_LOG_LOGIC ("m_mtu = " << m_mtu); + NS_LOG_LOGIC ("m_frameSize = " << m_frameSize); + uint16_t lengthType = 0; switch (m_encapMode) { - case ETHERNET_V1: - lengthType = p->GetSize () + header.GetSerializedSize () + - trailer.GetSerializedSize (); - break; - case IP_ARP: + case DIX: + NS_LOG_LOGIC ("Encapsulating packet as DIX (type interpretation)"); + // + // This corresponds to the type interpretation of the lengthType field as in the old Ethernet Blue Book. + // lengthType = protocolNumber; break; - case LLC: { - lengthType = p->GetSize () + header.GetSerializedSize () + - trailer.GetSerializedSize (); - LlcSnapHeader llc; - llc.SetType (protocolNumber); - p->AddHeader (llc); - } break; - case RAW: - NS_ASSERT (false); + case LLC: + { + NS_LOG_LOGIC ("Encapsulating packet as LLC (length interpretation)"); + + LlcSnapHeader llc; + llc.SetType (protocolNumber); + p->AddHeader (llc); + // + // This corresponds to the length interpretation of the lengthType field, + // but with an LLC/SNAP header added to the payload as in IEEE 802.2 + // + lengthType = p->GetSize (); + NS_ASSERT_MSG (lengthType <= m_frameSize - 18, + "CsmaNetDevice::AddHeader(): 802.3 Length/Type field with LLC/SNAP: " + "length interpretation must not exceed device frame size minus overhead"); + } + break; + case ILLEGAL: + default: + NS_FATAL_ERROR ("CsmaNetDevice::AddHeader(): Unknown packet encapsulation mode"); break; } + NS_LOG_LOGIC ("header.SetLengthType (" << lengthType << ")"); header.SetLengthType (lengthType); p->AddHeader (header); @@ -222,11 +370,7 @@ CsmaNetDevice::AddHeader ( bool CsmaNetDevice::ProcessHeader (Ptr p, uint16_t & param) { - NS_LOG_FUNCTION_NOARGS (); - if (m_encapMode == RAW) - { - return true; - } + NS_LOG_FUNCTION (p << param); EthernetTrailer trailer; @@ -244,17 +388,19 @@ CsmaNetDevice::ProcessHeader (Ptr p, uint16_t & param) switch (m_encapMode) { - case ETHERNET_V1: - case IP_ARP: + case DIX: param = header.GetLengthType (); break; - case LLC: { - LlcSnapHeader llc; - p->RemoveHeader (llc); - param = llc.GetType (); - } break; - case RAW: - NS_ASSERT (false); + case LLC: + { + LlcSnapHeader llc; + p->RemoveHeader (llc); + param = llc.GetType (); + } + break; + case ILLEGAL: + default: + NS_FATAL_ERROR ("CsmaNetDevice::ProcessHeader(): Unknown packet encapsulation mode"); break; } return true; @@ -264,20 +410,21 @@ CsmaNetDevice::ProcessHeader (Ptr p, uint16_t & param) CsmaNetDevice::TransmitStart () { NS_LOG_FUNCTION_NOARGS (); + NS_LOG_LOGIC ("m_currentPkt=" << m_currentPkt); NS_LOG_LOGIC ("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. -// + // + // 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); + "Must be READY to transmit. Tx state is: " << m_txMachineState); -// -// Only transmit if send side of net device is enabled -// + // + // Only transmit if send side of net device is enabled + // if (IsSendEnabled () == false) { return; @@ -285,16 +432,16 @@ CsmaNetDevice::TransmitStart () if (m_channel->GetState () != IDLE) { -// -// The channel is busy -- backoff and rechedule TransmitStart () -// + // + // The channel is busy -- backoff and rechedule TransmitStart () + // m_txMachineState = BACKOFF; if (m_backoff.MaxRetriesReached ()) { -// -// Too many retries, abort transmission of packet -// + // + // Too many retries, abort transmission of packet + // TransmitAbort (); } else @@ -302,38 +449,33 @@ CsmaNetDevice::TransmitStart () m_backoff.IncrNumRetries (); Time backoffTime = m_backoff.GetBackoffTime (); - NS_LOG_LOGIC ("Channel busy, backing off for " << - backoffTime.GetSeconds () << " sec"); + NS_LOG_LOGIC ("Channel busy, backing off for " << backoffTime.GetSeconds () << " sec"); - Simulator::Schedule (backoffTime, &CsmaNetDevice::TransmitStart, - this); + Simulator::Schedule (backoffTime, &CsmaNetDevice::TransmitStart, this); } } else { -// -// The channel is free, transmit the packet -// + // + // The channel is free, transmit the packet + // m_txMachineState = BUSY; Time tEvent = Seconds (m_bps.CalculateTxTime (m_currentPkt->GetSize ())); - NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << - tEvent.GetSeconds () << "sec"); + NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << tEvent.GetSeconds () << "sec"); - Simulator::Schedule (tEvent, &CsmaNetDevice::TransmitCompleteEvent, - this); + Simulator::Schedule (tEvent, &CsmaNetDevice::TransmitCompleteEvent, this); if (m_channel->TransmitStart (m_currentPkt, m_deviceId) == false) { - NS_LOG_WARN ("Channel transmit start did not work at " << - tEvent.GetSeconds () << "sec"); + NS_LOG_WARN ("Channel transmit start did not work at " << tEvent.GetSeconds () << "sec"); m_txMachineState = READY; } else { -// -// Transmission succeeded, reset the backoff time parameters. -// + // + // Transmission succeeded, reset the backoff time parameters. + // m_backoff.ResetBackoffTime (); } } @@ -344,19 +486,18 @@ CsmaNetDevice::TransmitStart () CsmaNetDevice::TransmitAbort (void) { NS_LOG_FUNCTION_NOARGS (); + NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt->GetUid () << ")"); -// -// Since we were transmitting a packet, that packet had better be on the -// transmit queue. -// + // + // Since we were transmitting a packet, that packet had better be on the transmit queue. + // m_currentPkt = m_queue->Dequeue (); - NS_ASSERT_MSG (m_currentPkt != 0, "No Packet on queue during" - "CsmaNetDevice::TransmitAbort()"); + NS_ASSERT_MSG (m_currentPkt != 0, "No Packet on queue during CsmaNetDevice::TransmitAbort()"); -// -// The last one failed. Let's try to transmit the next one (if there) -// + // + // The last one failed. Let's try to transmit the next one (if there) + // m_backoff.ResetBackoffTime (); m_txMachineState = READY; TransmitStart (); @@ -366,12 +507,13 @@ CsmaNetDevice::TransmitAbort (void) CsmaNetDevice::TransmitCompleteEvent (void) { NS_LOG_FUNCTION_NOARGS (); -// -// 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. -// + + // + // 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"); NS_ASSERT (m_channel->GetState () == TRANSMITTING); m_txMachineState = GAP; @@ -379,26 +521,27 @@ CsmaNetDevice::TransmitCompleteEvent (void) NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt->GetUid () << ")"); m_channel->TransmitEnd (); - NS_LOG_LOGIC ("Schedule TransmitReadyEvent in " - << m_tInterframeGap.GetSeconds () << "sec"); + NS_LOG_LOGIC ("Schedule TransmitReadyEvent in " << m_tInterframeGap.GetSeconds () << "sec"); - Simulator::Schedule (m_tInterframeGap, &CsmaNetDevice::TransmitReadyEvent, - this); + Simulator::Schedule (m_tInterframeGap, &CsmaNetDevice::TransmitReadyEvent, this); } void CsmaNetDevice::TransmitReadyEvent (void) { NS_LOG_FUNCTION_NOARGS (); -// -// 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. -// + + // + // 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; @@ -406,13 +549,12 @@ CsmaNetDevice::TransmitReadyEvent (void) else { m_currentPkt = m_queue->Dequeue (); - NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitReadyEvent():" - " IsEmpty false but no Packet on queue?"); + NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitReadyEvent(): IsEmpty false but no Packet on queue?"); TransmitStart (); } } -bool + bool CsmaNetDevice::Attach (Ptr ch) { NS_LOG_FUNCTION (this << &ch); @@ -421,19 +563,19 @@ CsmaNetDevice::Attach (Ptr ch) m_deviceId = m_channel->Attach (this); -// -// The channel provides us with the transmitter data rate. -// + // + // The channel provides us with the transmitter data rate. + // m_bps = m_channel->GetDataRate (); -// -// We use the Ethernet interframe gap of 96 bit times. -// + // + // We use the Ethernet interframe gap of 96 bit times. + // m_tInterframeGap = Seconds (m_bps.CalculateTxTime (96/8)); -// -// This device is up whenever a channel is attached to it. -// + // + // This device is up whenever a channel is attached to it. + // NotifyLinkUp (); return true; } @@ -441,7 +583,7 @@ CsmaNetDevice::Attach (Ptr ch) void CsmaNetDevice::SetQueue (Ptr q) { - NS_LOG_FUNCTION (this << q); + NS_LOG_FUNCTION (q); m_queue = q; } @@ -453,27 +595,35 @@ CsmaNetDevice::SetReceiveErrorModel (Ptr em) } void -CsmaNetDevice::Receive (Ptr packet) +CsmaNetDevice::Receive (Ptr packet, Ptr senderDevice) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (packet << senderDevice); NS_LOG_LOGIC ("UID is " << packet->GetUid ()); -// -// Only receive if the send side of net device is enabled -// + // + // We never forward up packets that we sent. Real devices don't do this since + // their receivers are disabled during send, so we don't. Drop the packet + // silently (no tracing) since it would really never get here in a real device. + // + if (senderDevice == this) + { + return; + } + + // + // Only receive if the send side of net device is enabled + // if (IsReceiveEnabled () == false) { m_dropTrace (packet); return; } - m_rxTrace (packet); - - if (m_encapMode == RAW) - { - m_rxCallback (this, packet, 0, GetBroadcast ()); - return; - } + // + // Trace sinks will expect complete packets, not packets without some of the + // headers. + // + Ptr originalPacket = packet->Copy (); EthernetTrailer trailer; packet->RemoveTrailer (trailer); @@ -485,47 +635,6 @@ CsmaNetDevice::Receive (Ptr packet) NS_LOG_LOGIC ("Pkt source is " << header.GetSource ()); NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ()); -// -// We never forward up packets that we sent. Real devices don't do this since -// their receivers are disabled during send, so we don't. Drop the packet -// silently (no tracing) since it would really never get here in a real device. -// - if (header.GetSource () == GetAddress ()) - { - NS_LOG_LOGIC ("Dropping packet sourced by this device"); - return; - } - -// -// An IP host group address is mapped to an Ethernet multicast address -// by placing the low-order 23-bits of the IP address into the low-order -// 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex). -// -// We are going to receive all packets destined to any multicast address, -// which means clearing the low-order 23 bits the header destination -// - Mac48Address mcDest; - uint8_t mcBuf[6]; - - header.GetDestination ().CopyTo (mcBuf); - mcBuf[3] &= 0x80; - mcBuf[4] = 0; - mcBuf[5] = 0; - mcDest.CopyFrom (mcBuf); - - Mac48Address multicast = Mac48Address::ConvertFrom (GetMulticast ()); - Mac48Address broadcast = Mac48Address::ConvertFrom (GetBroadcast ()); - Mac48Address destination = Mac48Address::ConvertFrom (GetAddress ()); - - if ((header.GetDestination () != broadcast) && - (mcDest != multicast) && - (header.GetDestination () != destination)) - { - NS_LOG_LOGIC ("Dropping pkt "); - m_dropTrace (packet); - return; - } - if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) ) { NS_LOG_LOGIC ("Dropping pkt due to error model "); @@ -533,16 +642,14 @@ CsmaNetDevice::Receive (Ptr packet) } else { -// -// variable must be initialized to avoid a compiler warning in the -// RAW case that breaks the optimized build. -// + // + // variable 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: + case DIX: protocol = header.GetLengthType (); break; case LLC: @@ -552,11 +659,43 @@ CsmaNetDevice::Receive (Ptr packet) protocol = llc.GetType (); } break; - case RAW: - NS_ASSERT (false); + case ILLEGAL: + default: + NS_FATAL_ERROR ("CsmaNetDevice::Receive(): Unknown packet encapsulation mode"); break; } - m_rxCallback (this, packet, protocol, header.GetSource ()); + + PacketType packetType; + + if (header.GetDestination ().IsBroadcast ()) + { + packetType = PACKET_BROADCAST; + m_rxTrace (originalPacket); + } + else if (header.GetDestination ().IsMulticast ()) + { + packetType = PACKET_MULTICAST; + m_rxTrace (originalPacket); + } + else if (header.GetDestination () == m_address) + { + packetType = PACKET_HOST; + m_rxTrace (originalPacket); + } + else + { + packetType = PACKET_OTHERHOST; + } + + if (!m_promiscRxCallback.IsNull ()) + { + m_promiscRxCallback (this, packet, protocol, header.GetSource (), header.GetDestination (), packetType); + } + + if (packetType != PACKET_OTHERHOST) + { + m_rxCallback (this, packet, protocol, header.GetSource ()); + } } } @@ -570,6 +709,8 @@ CsmaNetDevice::GetQueue (void) const void CsmaNetDevice::NotifyLinkUp (void) { + NS_LOG_FUNCTION_NOARGS (); + m_linkUp = true; if (m_linkChangeCallback.IsNull () == false) { @@ -580,186 +721,157 @@ CsmaNetDevice::NotifyLinkUp (void) void CsmaNetDevice::SetName (const std::string name) { + NS_LOG_FUNCTION (name); m_name = name; } std::string CsmaNetDevice::GetName (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_name; } void CsmaNetDevice::SetIfIndex (const uint32_t index) { + NS_LOG_FUNCTION (index); m_ifIndex = index; } uint32_t CsmaNetDevice::GetIfIndex (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_ifIndex; } Ptr CsmaNetDevice::GetChannel (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_channel; } Address CsmaNetDevice::GetAddress (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_address; } - bool -CsmaNetDevice::SetMtu (const uint16_t mtu) -{ - m_mtu = mtu; - return true; -} - - uint16_t -CsmaNetDevice::GetMtu (void) const -{ - return m_mtu; -} - bool CsmaNetDevice::IsLinkUp (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_linkUp; } void CsmaNetDevice::SetLinkChangeCallback (Callback callback) { + NS_LOG_FUNCTION (&callback); m_linkChangeCallback = callback; } bool CsmaNetDevice::IsBroadcast (void) const { + NS_LOG_FUNCTION_NOARGS (); return true; } Address CsmaNetDevice::GetBroadcast (void) const { + NS_LOG_FUNCTION_NOARGS (); return Mac48Address ("ff:ff:ff:ff:ff:ff"); } bool CsmaNetDevice::IsMulticast (void) const { + NS_LOG_FUNCTION_NOARGS (); return true; } Address CsmaNetDevice::GetMulticast (void) const { - return Mac48Address ("01:00:5e:00:00:00"); + NS_LOG_FUNCTION_NOARGS (); + return Mac48Address::GetMulticastPrefix (); } Address CsmaNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const { - NS_LOG_FUNCTION (this << multicastGroup); -// -// First, get the generic multicast address. -// - Address hardwareDestination = GetMulticast (); + NS_LOG_FUNCTION (multicastGroup); - NS_LOG_LOGIC ("Device multicast address: " << hardwareDestination); -// -// It's our address, and we know we're playing with an EUI-48 address here -// primarily since we know that by construction, but also since the parameter -// is an Ipv4Address. -// - Mac48Address etherAddr = Mac48Address::ConvertFrom (hardwareDestination); -// -// We now have the multicast address in an abstract 48-bit container. We -// need to pull it out so we can play with it. When we're done, we have the -// high order bits in etherBuffer[0], etc. -// - uint8_t etherBuffer[6]; - etherAddr.CopyTo (etherBuffer); -// -// Now we need to pull the raw bits out of the Ipv4 destination address. -// - uint8_t ipBuffer[4]; - multicastGroup.Serialize (ipBuffer); -// -// RFC 1112 says that an Ipv4 host group address is mapped to an EUI-48 -// multicast address by placing the low-order 23-bits of the IP address into -// the low-order 23 bits of the Ethernet multicast address -// 01-00-5E-00-00-00 (hex). -// - etherBuffer[3] |= ipBuffer[1] & 0x7f; - etherBuffer[4] = ipBuffer[2]; - etherBuffer[5] = ipBuffer[3]; -// -// Now, etherBuffer has the desired ethernet multicast address. We have to -// suck these bits back into the Mac48Address, -// - etherAddr.CopyFrom (etherBuffer); -// -// Implicit conversion (operator Address ()) is defined for Mac48Address, so -// use it by just returning the EUI-48 address which is automagically converted -// to an Address. -// - NS_LOG_LOGIC ("multicast address is " << etherAddr); + Mac48Address ad = Mac48Address::GetMulticast (multicastGroup); - return etherAddr; + // + // Implicit conversion (operator Address ()) is defined for Mac48Address, so + // use it by just returning the EUI-48 address which is automagically converted + // to an Address. + // + NS_LOG_LOGIC ("multicast address is " << ad); + + return ad; } bool CsmaNetDevice::IsPointToPoint (void) const { + NS_LOG_FUNCTION_NOARGS (); return false; } - bool -CsmaNetDevice::Send( - Ptr packet, - const Address& dest, - uint16_t protocolNumber) + bool +CsmaNetDevice::Send (Ptr packet,const Address& dest, uint16_t protocolNumber) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (packet << dest << protocolNumber); + return SendFrom (packet, m_address, dest, protocolNumber); +} + + bool +CsmaNetDevice::SendFrom (Ptr packet, const Address& src, const Address& dest, uint16_t protocolNumber) +{ + NS_LOG_FUNCTION (packet << src << dest << protocolNumber); NS_LOG_LOGIC ("p=" << packet); NS_LOG_LOGIC ("UID is " << packet->GetUid () << ")"); NS_ASSERT (IsLinkUp ()); -// -// Only transmit if send side of net device is enabled -// + // + // Only transmit if send side of net device is enabled + // if (IsSendEnabled () == false) { return false; } Mac48Address destination = Mac48Address::ConvertFrom (dest); - AddHeader (packet, destination, protocolNumber); + Mac48Address source = Mac48Address::ConvertFrom (src); + AddHeader (packet, source, destination, protocolNumber); -// -// Place the packet to be sent on the send queue -// + // + // Place the packet to be sent on the send queue + // if (m_queue->Enqueue(packet) == 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 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) { -// -// The next packet to be transmitted goes in m_currentPkt -// + // + // The next packet to be transmitted goes in m_currentPkt + // m_currentPkt = m_queue->Dequeue (); if (m_currentPkt != 0) { @@ -772,32 +884,63 @@ CsmaNetDevice::Send( Ptr CsmaNetDevice::GetNode (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_node; } void CsmaNetDevice::SetNode (Ptr node) { + NS_LOG_FUNCTION (node); + m_node = node; + int count = -1; + if (m_name.size () == 0) + { + for (uint32_t i = 0; i < node->GetNDevices (); i++) + { + Ptr dev = node->GetDevice (i); + if (dynamic_cast (PeekPointer (dev))) + { + count++; + if (dev == this) + { + break; + } + } + } + std::ostringstream s; + s << "eth" << count; + m_name = s.str (); + } } bool CsmaNetDevice::NeedsArp (void) const { - if ((m_encapMode == IP_ARP) || (m_encapMode == LLC)) - { - return true; - } - else - { - return false; - } + NS_LOG_FUNCTION_NOARGS (); + return true; } void CsmaNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) { + NS_LOG_FUNCTION (&cb); m_rxCallback = cb; } + void +CsmaNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb) +{ + NS_LOG_FUNCTION (&cb); + m_promiscRxCallback = cb; +} + + bool +CsmaNetDevice::SupportsSendFrom () const +{ + NS_LOG_FUNCTION_NOARGS (); + return true; +} + } // namespace ns3 diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index 440206d23..f239c4a32 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -49,13 +49,6 @@ class ErrorModel; * TCP stack. The NetDevice takes a raw packet of bytes and creates a * protocol specific packet from them. * - * The Csma net device class takes a packet and adds (or removes) 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 @@ -65,15 +58,15 @@ class CsmaNetDevice : public NetDevice { public: static TypeId GetTypeId (void); + /** * 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 */ + enum EncapsulationMode { + ILLEGAL, /**< Encapsulation mode not set */ + DIX, /**< DIX II / Ethernet II packet */ + LLC, /**< 802.2 LLC/SNAP Packet*/ }; /** @@ -103,7 +96,7 @@ public: * Set the backoff parameters used to determine the wait to retry * transmitting a packet when the channel is busy. * - * @see Attach () + * \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 @@ -118,8 +111,8 @@ public: * * The function Attach is used to add a CsmaNetDevice to a CsmaChannel. * - * @see SetDataRate () - * @see SetInterframeGap () + * \see SetDataRate () + * \see SetInterframeGap () * \param ch a pointer to the channel to which this object is being attached. */ bool Attach (Ptr ch); @@ -131,8 +124,8 @@ public: * level topology objects to implement a particular queueing method such as * DropTail or RED. * - * @see Queue - * @see DropTailQueue + * \see Queue + * \see DropTailQueue * \param queue a Ptr to the queue for being assigned to the device. */ void SetQueue (Ptr queue); @@ -143,8 +136,8 @@ public: * The CsmaNetDevice may optionally include an ErrorModel in * the packet receive chain to simulate data errors in during transmission. * - * @see ErrorModel - * @param em a pointer to the ErrorModel + * \see ErrorModel + * \param em a pointer to the ErrorModel */ void SetReceiveErrorModel (Ptr em); @@ -156,10 +149,11 @@ public: * used by the channel to indicate that the last bit of a packet has * arrived at the device. * - * @see CsmaChannel + * \see CsmaChannel * \param p a reference to the received packet + * \param sender the CsmaNetDevice that transmitted the packet in the first place */ - void Receive (Ptr p); + void Receive (Ptr p, Ptr sender); /** * Is the send side of the network device enabled? @@ -196,17 +190,130 @@ public: */ void SetAddress (Mac48Address addr); -// -// The following methods are inherited from NetDevice base class. -// + /** + * Set The max frame size of packets sent over this device. + * + * Okay, that was easy to say, but the details are a bit thorny. We have a MAC-level MTU that is the payload that higher + * level protocols see. We have a PHY-level MTU which is the maximum number of bytes we can send over the link + * (cf. 1500 bytes for Ethernet). We also have a frame size which is some total number of bytes in a packet which could + * or could not include any framing and overhead. There can be a lot of inconsistency in definitions of these terms. For + * example, RFC 1042 asserts that the terms maximum transmission unit and maximum packet size are equivalent. RFC 791, + * however, defines MTU as the maximum sized IP datagram that can be sent. Packet size and frame size are sometimes + * used interchangeably. + * + * So, some careful definitions are in order to avoid confusion: + * + * In real Ethernet, a packet on the wire starts with a preamble of seven bytes of alternating ones and zeroes followed by + * a Start-of-Frame-Delimeter (10101011). This is followed by what is usually called the packet: a MAC destination and + * source, a type field, payload, a possible padding field and a CRC. To be strictly and pedantically correct the frame + * size is necessarily larger than the packet size on a real Ethernet. But, this isn't a real Ethernet, it's a simulation + * of a device similar to Ethernet, and we have no good reason to add framing bits. So, in the case of the CSMA device, + * the frame size is equal to the packet size. Since these two values are equal, there is no danger in assuming they are + * identical. We do not implement any padding out to a minimum frame size, so padding is a non-issue. We define packet + * size to be equal to frame size and this excludes the preamble and SFD bytes of a real Ethernet frame. We define a + * single (MAC-level) MTU that coresponds to the payload size of the packet, which is the IP-centric view of the term as + * seen in RFC 791. + * + * To make this concrete, consider DIX II (Digital Equipment, Intel, Xerox type II) framing, which is used in most TCP/IP + * stacks. NetWare and Wireshark call this framing Ethernet II, by the way. In this framing scheme, a real packet on the + * wire starts with the preamble and Start-of-Frame-Delimeter (10101011). We ignore these bits on this device since it they + * are not needed. In DIX II, the SFD is followed by the MAC (48) destination address (6 bytes), source address (6 bytes), + * the EtherType field (2 bytes), payload (0-1500 bytes) and a CRC (4 bytes) -- this corresponds to our entire frame. The + * payload of the packet/frame in DIX can be from 0 to 1500 bytes. It is the maxmimum value of this payload that we call + * the MTU. Typically, one sees the MTU set to 1500 bytes and the maximum frame size set to 1518 bytes in Ethernet-based + * networks. + * + * Different framing schemes can make for different MTU and frame size relationships. For example, we support LLC/SNAP + * encapsulation which adds eight bytes of header overhead to the usual DIX framing. In this case, if the maximum frame + * size is left at 1518 bytes, we need to export an MTU that reflects the loss of eight bytes for a total of 1492. + * + * Another complication is that IEEE 802.1Q adds four bytes to the maximum frame size for VLAN tagging. In order to + * provide an MTU of 1500 bytes, the frame size would need to increased to 1522 bytes to absorb the additional overhead. + * + * So, there are really three variables that are not entirely free at work here. There is the maximum frame size, the + * MTU and the framing scheme which we call the encapsulation mode. + * + * So, what do we do since there are be three values which must always be consistent in the driver? Which values to we + * allow to be changed and how do we ensure the other two are consistent? We want to actually allow a user to change + * these three variables in flexible ways, but we want the results (even at intermediate stages of her ultimate change) to + * be consistent. We certainly don't want to require that users must understand the various requirements of an enapsulation + * mode in order to set these variables. + * + * Consider the following situation: A user wants to set the maximum frame size to 1418 bytes instead of 1518. This + * user shouldn't have to concern herself that the current encapuslation mode is LLC/SNAP and this will consume eight bytes. + * She should not have to also figure out that the MTU needs to be set to 1392 bytes, and she should certainly not have to + * do this in some special order to keep intermediate steps consistent. + * + * Similarly, a user who is interested in setting the MTU to 1400 bytes should not be forced to understand that + * (based on encapsulation mode) the frame size may need to be set to eighteen + eight bytes more than what he wants + * in certain cases (802,3 + LLC/SNAP), twenty-two + zero bytes in others (802.1Q) and other inscrutable combinations + * + * Now, consider a user who is only interested in changing the encapsulation mode from LLC/SNAP to DIX. This + * is going to change the relationship between the MTU and the frame size. We've may have to come up with a new value + * for at least one of the these? Which one? There are too many free variables. + * + * We could play games trying to figure out what the user wants to do, but that is typically a bad plan and programmers + * have a long and distinguished history of guessing wrong. We'll avoid all of that and just define a flexible behavior + * that can be worked to get what you want. Here it is: + * + * - If the user is changing the encapsulation mode, the PHY MTU will remain fixed and the MAC MTU will change, if required, + * to make the three values consistent; + * + * - If the user is changing the MTU, she is interested in getting that part of the system set, so the frame size + * will be changed to make the three values consistent; + * + * - If the user is changing the frame size, he is interested in getting that part of the system set, so the MTU + * will be changed to make the three values consistent; + * + * - You cannot define the MTU and frame size separately -- they are always tied together by the emulation mode. This + * is not a restriction. Consider what this means. Perhaps you want to set the frame size to some large number and the + * MTU to some small number. The largest packet you can send is going to be limited by the MTU, so it is not possible to + * send a frame larger than the MTU plus overhead. The larger frame size is not useful. + * + * So, if a user calls SetFrameSize, we assume that the maximum frame size is the interesting thing for that user and + * we just adjust the MTU to a new "correct value" based on the current encapsulation mode. If a user calls SetMtu, we + * assume that the MTU is the interesting property for that user, and we adjust the frame size to a new "correct value" + * for the current encapsulation mode. If a user calls SetEncapsulationMode, then we take the MTU as the free variable + * and set its value to match the current frame size. + * + * \param frameSize The max frame size of packets sent over this device. + */ + void SetFrameSize (uint16_t frameSize); + + /** + * Get The max frame size of packets sent over this device. + * + * \returns The max frame size of packets sent over this device. + */ + uint16_t GetFrameSize (void) const; + + /** + * Set the encapsulation mode of this device. + * + * \param mode The encapsulation mode of this device. + * + * \see SetFrameSize + */ + void SetEncapsulationMode (CsmaNetDevice::EncapsulationMode mode); + + /** + * Get the encapsulation mode of this device. + * + * \returns The encapsulation mode of this device. + */ + CsmaNetDevice::EncapsulationMode GetEncapsulationMode (void); + + // + // The following methods are inherited from NetDevice base class. + // virtual void SetName (const std::string name); virtual std::string GetName (void) const; virtual void SetIfIndex (const uint32_t index); virtual uint32_t GetIfIndex (void) const; virtual Ptr GetChannel (void) const; - virtual Address GetAddress (void) const; virtual bool SetMtu (const uint16_t mtu); virtual uint16_t GetMtu (void) const; + virtual Address GetAddress (void) const; virtual bool IsLinkUp (void) const; virtual void SetLinkChangeCallback (Callback callback); virtual bool IsBroadcast (void) const; @@ -215,7 +322,7 @@ public: virtual Address GetMulticast (void) const; /** - * @brief Make and return a MAC multicast address using the provided + * \brief Make and return a MAC multicast address using the provided * multicast group * * RFC 1112 says that an Ipv4 host group address is mapped to an Ethernet @@ -227,14 +334,14 @@ public: * to an EUI-48-based CSMA device. This MAC address is encapsulated in an * abstract Address to avoid dependencies on the exact address format. * - * @param multicastGroup The IP address for the multicast group destination + * \param multicastGroup The IP address for the multicast group destination * of the packet. - * @return The MAC multicast Address used to send packets to the provided + * \return The MAC multicast Address used to send packets to the provided * multicast group. * - * @see Ipv4Address - * @see Mac48Address - * @see Address + * \see Ipv4Address + * \see Mac48Address + * \see Address */ virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const; @@ -250,6 +357,12 @@ public: virtual bool Send (Ptr packet, const Address& dest, uint16_t protocolNumber); + /** + * Start sending a packet down the channel, with MAC spoofing + */ + virtual bool SendFrom (Ptr packet, const Address& source, const Address& dest, + uint16_t protocolNumber); + /** * Get the node to which this device is attached. * @@ -280,6 +393,10 @@ public: */ virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); + + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb); + virtual bool SupportsSendFrom (void) const; + protected: /** * Perform any object release functionality required to break reference @@ -302,11 +419,12 @@ protected: * respect the packet type * * \param p Packet to which header should be added + * \param source MAC source address from which packet should be sent * \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 (Ptr p, Mac48Address dest, uint16_t protocolNumber); + void AddHeader (Ptr p, Mac48Address source, Mac48Address dest, uint16_t protocolNumber); /** * Removes, from a packet of data, all headers and trailers that @@ -321,6 +439,7 @@ protected: bool ProcessHeader (Ptr p, uint16_t & param); private: + /** * Operator = is declared but not implemented. This disables the assigment * operator for CsmaNetDevice objects. @@ -339,6 +458,18 @@ private: */ void Init (bool sendEnable, bool receiveEnable); + /** + * Calculate the value for the MTU that would result from + * setting the frame size to the given value. + */ + uint32_t MtuFromFrameSize (uint32_t frameSize); + + /** + * Calculate the value for the frame size that would be required + * to be able to set the MTU to the given value. + */ + uint32_t FrameSizeFromMtu (uint32_t mtu); + /** * Start Sending a Packet Down the Wire. * @@ -353,8 +484,8 @@ private: * If the channel is found to be BUSY, this method reschedules itself for * execution at a later time (within the backoff period). * - * @see CsmaChannel::TransmitStart () - * @see TransmitCompleteEvent () + * \see CsmaChannel::TransmitStart () + * \see TransmitCompleteEvent () */ void TransmitStart (); @@ -371,8 +502,8 @@ private: * 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 () + * \see CsmaChannel::TransmitEnd () + * \see TransmitReadyEvent () */ void TransmitCompleteEvent (void); @@ -388,7 +519,7 @@ private: * 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 () + * \see TransmitStart () */ void TransmitReadyEvent (void); @@ -436,7 +567,7 @@ private: /** * The state of the Net Device transmit state machine. - * @see TxMachineState + * \see TxMachineState */ TxMachineState m_txMachineState; @@ -445,19 +576,19 @@ private: * function and that should be processed by the ProcessHeader * function. */ - CsmaEncapsulationMode m_encapMode; + EncapsulationMode m_encapMode; /** * The data rate that the Net Device uses to simulate packet transmission * timing. - * @see class DataRate + * \see class DataRate */ DataRate m_bps; /** * The interframe gap that the Net Device uses insert time between packet * transmission - * @see class Time + * \see class Time */ Time m_tInterframeGap; @@ -478,7 +609,7 @@ private: /** * The CsmaChannel to which this CsmaNetDevice has been * attached. - * @see class CsmaChannel + * \see class CsmaChannel */ Ptr m_channel; @@ -486,8 +617,8 @@ private: * 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 + * \see class Queue + * \see class DropTailQueue */ Ptr m_queue; @@ -500,7 +631,7 @@ private: * The trace source for the packet reception events that the device can * fire. * - * @see class CallBackTraceSource + * \see class CallBackTraceSource */ TracedCallback > m_rxTrace; @@ -508,7 +639,7 @@ private: * The trace source for the packet drop events that the device can * fire. * - * @see class CallBackTraceSource + * \see class CallBackTraceSource */ TracedCallback > m_dropTrace; @@ -526,6 +657,10 @@ private: * The callback used to notify higher layers that a packet has been received. */ NetDevice::ReceiveCallback m_rxCallback; + /** + * The callback used to notify higher layers that a packet has been received in promiscuous mode. + */ + NetDevice::PromiscReceiveCallback m_promiscRxCallback; /** * The interface index (really net evice index) that has been assigned to @@ -549,11 +684,23 @@ private: */ Callback m_linkChangeCallback; + static const uint16_t DEFAULT_FRAME_SIZE = 1518; + static const uint16_t ETHERNET_OVERHEAD = 18; + /** - * The maximum transmission unit (biggest packet) allowed to be sent or - * received by this network device. + * The frame size/packet size. This corresponds to the maximum + * number of bytes that can be transmitted as a packet without framing. + * This corresponds to the 1518 byte packet size often seen on Ethernet. */ - uint16_t m_mtu; + uint32_t m_frameSize; + + /** + * The Maxmimum Transmission Unit. This corresponds to the maximum + * number of bytes that can be transmitted as seen from higher layers. + * This corresponds to the 1500 byte MTU size often seen on IP over + * Ethernet. + */ + uint32_t m_mtu; }; }; // namespace ns3 diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index 25abe19af..159d8a004 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -23,6 +23,7 @@ #include "ns3/llc-snap-header.h" #include "ns3/error-model.h" #include "ns3/trace-source-accessor.h" +#include "ns3/uinteger.h" #include "ns3/pointer.h" #include "point-to-point-net-device.h" #include "point-to-point-channel.h" @@ -40,29 +41,43 @@ PointToPointNetDevice::GetTypeId (void) static TypeId tid = TypeId ("ns3::PointToPointNetDevice") .SetParent () .AddConstructor () - .AddAttribute ("Address", "The address of this device.", + .AddAttribute ("Address", + "The MAC address of this device.", Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")), MakeMac48AddressAccessor (&PointToPointNetDevice::m_address), MakeMac48AddressChecker ()) - .AddAttribute ("DataRate", "The default data rate for point to point links", + .AddAttribute ("FrameSize", + "The maximum size of a packet sent over this device.", + UintegerValue (DEFAULT_FRAME_SIZE), + MakeUintegerAccessor (&PointToPointNetDevice::SetFrameSize, + &PointToPointNetDevice::GetFrameSize), + MakeUintegerChecker ()) + .AddAttribute ("DataRate", + "The default data rate for point to point links", DataRateValue (DataRate ("32768b/s")), MakeDataRateAccessor (&PointToPointNetDevice::m_bps), MakeDataRateChecker ()) - .AddAttribute ("ReceiveErrorModel", "XXX", + .AddAttribute ("ReceiveErrorModel", + "The receiver error model used to simulate packet loss", PointerValue (), MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel), MakePointerChecker ()) - .AddAttribute ("TxQueue", "XXX", + .AddAttribute ("TxQueue", + "A queue to use as the transmit queue in the device.", PointerValue (), MakePointerAccessor (&PointToPointNetDevice::m_queue), MakePointerChecker ()) - .AddAttribute ("InterframeGap", "XXX", + .AddAttribute ("InterframeGap", + "The time to wait between packet (frame) transmissions", TimeValue (Seconds (0.0)), MakeTimeAccessor (&PointToPointNetDevice::m_tInterframeGap), MakeTimeChecker ()) - .AddTraceSource ("Rx", "Receive MAC packet.", + .AddTraceSource ("Rx", + "Trace source to fire on reception of a MAC packet.", MakeTraceSourceAccessor (&PointToPointNetDevice::m_rxTrace)) - .AddTraceSource ("Drop", "Drop MAC packet.", + .AddTraceSource ("Drop", + "Trace source to fire on when a MAC packet is dropped.", + MakeTraceSourceAccessor (&PointToPointNetDevice::m_dropTrace)) ; @@ -75,10 +90,19 @@ PointToPointNetDevice::PointToPointNetDevice () m_txMachineState (READY), m_channel (0), m_name (""), - m_linkUp (false), - m_mtu (0xffff) + m_linkUp (false) { NS_LOG_FUNCTION (this); + + // + // A quick sanity check to ensure consistent constants. + // + PppHeader ppp; + NS_ASSERT_MSG (PPP_OVERHEAD == ppp.GetSerializedSize (), + "PointToPointNetDevice::PointToPointNetDevice(): PPP_OVERHEAD inconsistent"); + + m_frameSize = DEFAULT_FRAME_SIZE; + m_mtu = MtuFromFrameSize (m_frameSize); } PointToPointNetDevice::~PointToPointNetDevice () @@ -207,7 +231,7 @@ PointToPointNetDevice::SetQueue (Ptr q) void PointToPointNetDevice::SetReceiveErrorModel (Ptr em) { - NS_LOG_FUNCTION ("(" << em << ")"); + NS_LOG_FUNCTION (this << em); m_receiveErrorModel = em; } @@ -233,7 +257,11 @@ PointToPointNetDevice::Receive (Ptr packet) // m_rxTrace (packet); ProcessHeader(packet, protocol); - m_rxCallback (this, packet, protocol, GetBroadcast ()); + m_rxCallback (this, packet, protocol, GetRemote ()); + if (!m_promiscCallback.IsNull ()) + { + m_promiscCallback (this, packet, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST); + } } } @@ -301,19 +329,6 @@ PointToPointNetDevice::GetAddress (void) const return m_address; } - bool -PointToPointNetDevice::SetMtu (const uint16_t mtu) -{ - m_mtu = mtu; - return true; -} - - uint16_t -PointToPointNetDevice::GetMtu (void) const -{ - return m_mtu; -} - bool PointToPointNetDevice::IsLinkUp (void) const { @@ -350,6 +365,7 @@ PointToPointNetDevice::GetBroadcast (void) const // // We don't deal with multicast here. It doesn't make sense to include some // of the one destinations on the network but exclude some of the others. +// bool PointToPointNetDevice::IsMulticast (void) const { @@ -425,6 +441,15 @@ PointToPointNetDevice::Send( } } +bool +PointToPointNetDevice::SendFrom (Ptr packet, + const Address &source, + const Address &dest, + uint16_t protocolNumber) +{ + return false; +} + Ptr PointToPointNetDevice::GetNode (void) const { @@ -449,4 +474,104 @@ PointToPointNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) m_rxCallback = cb; } +void +PointToPointNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb) +{ + NS_FATAL_ERROR ("not implemented"); + m_promiscCallback = cb; +} + + bool +PointToPointNetDevice::SupportsSendFrom (void) const +{ + return false; +} + +Address +PointToPointNetDevice::GetRemote (void) const +{ + NS_ASSERT (m_channel->GetNDevices () == 2); + for (uint32_t i = 0; i < m_channel->GetNDevices (); ++i) + { + Ptr tmp = m_channel->GetDevice (i); + if (tmp != this) + { + return tmp->GetAddress (); + } + } + NS_ASSERT (false); + // quiet compiler. + return Address (); +} + + uint32_t +PointToPointNetDevice::MtuFromFrameSize (uint32_t frameSize) +{ + NS_LOG_FUNCTION (frameSize); + NS_ASSERT_MSG (frameSize <= std::numeric_limits::max (), + "PointToPointNetDevice::MtuFromFrameSize(): Frame size should be derived from 16-bit quantity: " << + frameSize); + PppHeader ppp; + NS_ASSERT_MSG ((uint32_t)frameSize >= ppp.GetSerializedSize (), + "PointToPointNetDevice::MtuFromFrameSize(): Given frame size too small to support PPP"); + return frameSize - ppp.GetSerializedSize (); +} + + uint32_t +PointToPointNetDevice::FrameSizeFromMtu (uint32_t mtu) +{ + NS_LOG_FUNCTION (mtu); + + PppHeader ppp; + return mtu + ppp.GetSerializedSize (); +} + + void +PointToPointNetDevice::SetFrameSize (uint16_t frameSize) +{ + NS_LOG_FUNCTION (frameSize); + + m_frameSize = frameSize; + m_mtu = MtuFromFrameSize (frameSize); + + NS_LOG_LOGIC ("m_frameSize = " << m_frameSize); + NS_LOG_LOGIC ("m_mtu = " << m_mtu); +} + + uint16_t +PointToPointNetDevice::GetFrameSize (void) const +{ + return m_frameSize; +} + + bool +PointToPointNetDevice::SetMtu (uint16_t mtu) +{ + NS_LOG_FUNCTION (mtu); + + uint32_t newFrameSize = FrameSizeFromMtu (mtu); + + if (newFrameSize > std::numeric_limits::max ()) + { + NS_LOG_WARN ("PointToPointNetDevice::SetMtu(): Frame size overflow, MTU not set."); + return false; + } + + m_frameSize = newFrameSize; + m_mtu = mtu; + + NS_LOG_LOGIC ("m_frameSize = " << m_frameSize); + NS_LOG_LOGIC ("m_mtu = " << m_mtu); + + return true; +} + + uint16_t +PointToPointNetDevice::GetMtu (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_mtu; +} + + } // namespace ns3 diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index 6b63ecb37..67636fa71 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -139,6 +139,93 @@ public: */ void SetAddress (Mac48Address addr); + /** + * Set The max frame size of packets sent over this device. + * + * Okay, that was easy to say, but the details are a bit thorny. We have a MAC-level MTU that is the payload that higher + * level protocols see. We have a PHY-level MTU which is the maximum number of bytes we can send over the link + * (cf. 1500 bytes for Ethernet). We also have a frame size which is some total number of bytes in a packet which could + * or could not include any framing and overhead. There can be a lot of inconsistency in definitions of these terms. For + * example, RFC 1042 asserts that the terms maximum transmission unit and maximum packet size are equivalent. RFC 791, + * however, defines MTU as the maximum sized IP datagram that can be sent. Packet size and frame size are sometimes + * used interchangeably. + * + * So, some careful definitions are in order to avoid confusion: + * + * In real serial channel (HDLC, for example), the wire idles (sends all ones) until the channel begins sending a packet. + * A frame on the wire starts with a flag character (01111110). This is followed by what is usually called the packet: + * address, control, payload, and a Frame Check Sequence (FCS). This is followed by another flag character. If the flag + * characters are used, then bit stuffing must be used to prevent flag characters from appearing in the packet and confusing + * the link. Som to be strictly and pedantically correct the frame size is then necessarily larger than the packet size on + * a real link. But, this isn't a real link, it's a simulation of a device similar to a point-to-point device, and we have + * no good reason to add framing bits and therefore to do bit-stuffing. So, in the case of the point-to-point device, the + * frame size is equal to the packet size. Since these two values are defined to be equal, there is no danger in assuming + * they are identical. We define packet size to be equal to frame size and this excludes the flag characters. We define a + * single (MAC-level) MTU that coresponds to the payload size of the packet, which is the IP-centric view of the term as + * seen in RFC 791. + * + * To make this concrete, consider PPP framing on a synchronous link. In this framing scheme, a real serial frame on the + * wire starts with a flag character, address and control characters, then a 16-bit PPP protocol ID (0x21 = IP). Then we + * would see the actual payload we are supposed to send, presumably an IP datagram. At then we see the FCS and finally + * another flag character to end the frame. We ignore the flag bits on this device since it they are not needed. We + * aren't really using HDLC to send frames across the link, so we don't need the address and control bits either. In fact, + * to encapsulate using unframed PPP all we need to do is prepend the two-byte protocol ID. + * + * Typically the limiting factor in frame size is due to hardware limitations in the underlying HDLC controller receive + * FIFO buffer size. This number can vary widely. For example, the Motorola MC92460 has a 64 KByte maximum frame size; + * the Intel IXP4XX series has a 16 KByte size. Older USARTs have a maximum frame size around 2KBytes, and typical PPP + * links on the Internet have their MTU set to 1500 bytes since this is what will typically be used on Ethernet segments + * and will avoid path MTU issues. We choose to make the default MTU 1500 bytes which then fixes the maximum frame size + * as described below. + * + * So, there are really two related variables at work here. There is the maximum frame size that can be sent over the + * link and there is the MTU. + * + * So, what do we do since these values must always be consistent in the driver? We want to actually allow a user to change + * these variables, but we want the results (even at intermediate stages of her ultimate change) to be consistent. We + * certainly don't want to require that users must understand the details of PPP encapsulation in order to set these + * variables. + * + * Consider the following situation: A user wants to set the maximum frame size to 16 KBytes. This user shouldn't have to + * concern herself that the PPP encapsulation will consume six bytes. She should not have to figure out that the MTU needs + * to be set to 16K - 2 bytes to make things consistent. + * + * Similarly, a user who is interested in setting the MTU to 1500 bytes should not be forced to understand that the frame + * size will need to be set to 1502 bytes. + * + * We could play games trying to figure out what the user wants to do, but that is typically a bad plan and programmers + * have a long and distinguished history of guessing wrong. We'll avoid all of that and just define a flexible behavior + * that can be worked to get what you want. Here it is: + * + * - If the user is changing the MTU, she is interested in getting that part of the system set, so the frame size + * will be changed to make it consistent; + * + * - If the user is changing the frame size, he is interested in getting that part of the system set, so the MTU + * will be changed to make it consistent; + * + * - You cannot define the MTU and frame size separately -- they are always tied together by the overhead of the PPP + * encapsulation. This is not a restriction. Consider what this means. Perhaps you want to set the frame size to some + * large number and the MTU to some small number. The largest packet you can send is going to be limited by the MTU, so it + * is not possible to send a frame larger than the MTU plus overhead. Having the ability to set a larger frame size is not + * useful. + * + * So, if a user calls SetFrameSize, we assume that the maximum frame size is the interesting thing for that user and + * we just adjust the MTU to a new "correct value" based on the current encapsulation mode. If a user calls SetMtu, we + * assume that the MTU is the interesting property for that user, and we adjust the frame size to a new "correct value" + * for the current encapsulation mode. If a user calls SetEncapsulationMode, then we take the MTU as the free variable + * and set its value to match the current frame size. + * + * \param frameSize The max frame size of packets sent over this device. + */ + void SetFrameSize (uint16_t frameSize); + + /** + * Get The max frame size of packets sent over this device. + * + * \returns The max frame size of packets sent over this device. + */ + uint16_t GetFrameSize (void) const; + // // Pure virtual methods inherited from NetDevice we must implement. // @@ -167,8 +254,8 @@ public: virtual bool IsPointToPoint (void) const; - virtual bool Send(Ptr packet, const Address &dest, - uint16_t protocolNumber); + virtual bool Send(Ptr packet, const Address &dest, uint16_t protocolNumber); + virtual bool SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); virtual Ptr GetNode (void) const; virtual void SetNode (Ptr node); @@ -177,6 +264,9 @@ public: virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb); + virtual bool SupportsSendFrom (void) const; + private: virtual void DoDispose (void); @@ -192,6 +282,24 @@ private: Ptr GetQueue(void) const; private: + /** + * Calculate the value for the MTU that would result from + * setting the frame size to the given value. + */ + uint32_t MtuFromFrameSize (uint32_t frameSize); + + /** + * Calculate the value for the frame size that would be required + * to be able to set the MTU to the given value. + */ + uint32_t FrameSizeFromMtu (uint32_t mtu); + + /** + * \returns the address of the remote device connected to this device + * through the point to point channel. + */ + Address GetRemote (void) const; + /** * Adds the necessary headers and trailers to a packet of data in order to * respect the protocol implemented by the agent. @@ -301,11 +409,30 @@ private: Ptr m_node; Mac48Address m_address; NetDevice::ReceiveCallback m_rxCallback; + NetDevice::PromiscReceiveCallback m_promiscCallback; uint32_t m_ifIndex; std::string m_name; bool m_linkUp; Callback m_linkChangeCallback; - uint16_t m_mtu; + + static const uint16_t DEFAULT_MTU = 1500; + static const uint16_t PPP_OVERHEAD = 2; + static const uint16_t DEFAULT_FRAME_SIZE = DEFAULT_MTU + PPP_OVERHEAD; + + /** + * The frame size/packet size. This corresponds to the maximum + * number of bytes that can be transmitted as a packet without framing. + * This corresponds to the 1518 byte packet size often seen on Ethernet. + */ + uint32_t m_frameSize; + + /** + * The Maxmimum Transmission Unit. This corresponds to the maximum + * number of bytes that can be transmitted as seen from higher layers. + * This corresponds to the 1500 byte MTU size often seen on IP over + * Ethernet. + */ + uint32_t m_mtu; }; } // namespace ns3 diff --git a/src/devices/wifi/adhoc-wifi-mac.cc b/src/devices/wifi/adhoc-wifi-mac.cc index a67f10ecd..84513c666 100644 --- a/src/devices/wifi/adhoc-wifi-mac.cc +++ b/src/devices/wifi/adhoc-wifi-mac.cc @@ -50,7 +50,7 @@ AdhocWifiMac::AdhocWifiMac () m_low = CreateObject (); m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle)); - m_low->SetMac (this); + m_low->SetBssid (GetBssid ()); m_dcfManager = new DcfManager (); m_dcfManager->SetupLowListener (m_low); @@ -80,13 +80,13 @@ void AdhocWifiMac::SetSlot (Time slotTime) { m_dcfManager->SetSlot (slotTime); - m_slot = slotTime; + m_low->SetSlotTime (slotTime); } void AdhocWifiMac::SetSifs (Time sifs) { m_dcfManager->SetSifs (sifs); - m_sifs = sifs; + m_low->SetSifs (sifs); } void AdhocWifiMac::SetEifsNoDifs (Time eifsNoDifs) @@ -94,22 +94,51 @@ AdhocWifiMac::SetEifsNoDifs (Time eifsNoDifs) m_dcfManager->SetEifsNoDifs (eifsNoDifs); m_eifsNoDifs = eifsNoDifs; } +void +AdhocWifiMac::SetAckTimeout (Time ackTimeout) +{ + m_low->SetAckTimeout (ackTimeout); +} +void +AdhocWifiMac::SetCtsTimeout (Time ctsTimeout) +{ + m_low->SetCtsTimeout (ctsTimeout); +} +void +AdhocWifiMac::SetPifs (Time pifs) +{ + m_low->SetPifs (pifs); +} Time AdhocWifiMac::GetSlot (void) const { - return m_slot; + return m_low->GetSlotTime (); } Time AdhocWifiMac::GetSifs (void) const { - return m_sifs; + return m_low->GetSifs (); } Time AdhocWifiMac::GetEifsNoDifs (void) const { return m_eifsNoDifs; } - +Time +AdhocWifiMac::GetAckTimeout (void) const +{ + return m_low->GetAckTimeout (); +} +Time +AdhocWifiMac::GetCtsTimeout (void) const +{ + return m_low->GetCtsTimeout (); +} +Time +AdhocWifiMac::GetPifs (void) const +{ + return m_low->GetPifs (); +} void AdhocWifiMac::SetWifiPhy (Ptr phy) { @@ -125,7 +154,7 @@ AdhocWifiMac::SetWifiRemoteStationManager (Ptr station m_low->SetWifiRemoteStationManager (stationManager); } void -AdhocWifiMac::SetForwardUpCallback (Callback, const Mac48Address &> upCallback) +AdhocWifiMac::SetForwardUpCallback (Callback, Mac48Address, Mac48Address> upCallback) { m_upCallback = upCallback; } @@ -141,7 +170,7 @@ AdhocWifiMac::SetLinkDownCallback (Callback linkDown) Mac48Address AdhocWifiMac::GetAddress (void) const { - return m_address; + return m_low->GetAddress (); } Ssid AdhocWifiMac::GetSsid (void) const @@ -151,14 +180,15 @@ AdhocWifiMac::GetSsid (void) const Mac48Address AdhocWifiMac::GetBssid (void) const { - // XXX the bssid should be generated by the procedure - // described in ieee802.11 section 11.1.3 - return Mac48Address::GetBroadcast (); + return m_low->GetBssid (); } void AdhocWifiMac::SetAddress (Mac48Address address) { - m_address = address; + m_low->SetAddress (address); + m_low->SetBssid (address); + // XXX the bssid should be generated by the procedure + // described in ieee802.11 section 11.1.3 } void AdhocWifiMac::SetSsid (Ssid ssid) @@ -167,14 +197,19 @@ AdhocWifiMac::SetSsid (Ssid ssid) m_ssid = ssid; } +void +AdhocWifiMac::Enqueue (Ptr packet, Mac48Address to, Mac48Address from) +{ + NS_FATAL_ERROR ("Adhoc does not support a from != m_low->GetAddress ()"); +} void AdhocWifiMac::Enqueue (Ptr packet, Mac48Address to) { - NS_LOG_DEBUG ("enqueue size="<GetSize ()<<", to="<GetSize () << to); WifiMacHeader hdr; hdr.SetType (WIFI_MAC_DATA); hdr.SetAddr1 (to); - hdr.SetAddr2 (GetAddress ()); + hdr.SetAddr2 (m_low->GetAddress ()); hdr.SetAddr3 (GetBssid ()); hdr.SetDsNotFrom (); hdr.SetDsNotTo (); @@ -193,15 +228,17 @@ AdhocWifiMac::Enqueue (Ptr packet, Mac48Address to) m_dca->Queue (packet, hdr); } +bool +AdhocWifiMac::SupportsSendFrom (void) const +{ + return false; +} void AdhocWifiMac::ForwardUp (Ptr packet, WifiMacHeader const *hdr) { NS_LOG_DEBUG ("received size="<GetSize ()<<", from="<GetAddr2 ()); - if (hdr->GetAddr1 ().IsBroadcast () || hdr->GetAddr1 () == GetAddress ()) - { - m_upCallback (packet, hdr->GetAddr2 ()); - } + m_upCallback (packet, hdr->GetAddr2 (), hdr->GetAddr1 ()); } } // namespace ns3 diff --git a/src/devices/wifi/adhoc-wifi-mac.h b/src/devices/wifi/adhoc-wifi-mac.h index b8072b6ce..d5d5f4b44 100644 --- a/src/devices/wifi/adhoc-wifi-mac.h +++ b/src/devices/wifi/adhoc-wifi-mac.h @@ -56,39 +56,45 @@ public: virtual void SetSlot (Time slotTime); virtual void SetSifs (Time sifs); virtual void SetEifsNoDifs (Time eifsNoDifs); + virtual void SetAckTimeout (Time ackTimeout); + virtual void SetCtsTimeout (Time ctsTimeout); + virtual void SetPifs (Time pifs); virtual Time GetSlot (void) const; virtual Time GetSifs (void) const; virtual Time GetEifsNoDifs (void) const; + virtual Time GetAckTimeout (void) const; + virtual Time GetCtsTimeout (void) const; + virtual Time GetPifs (void) const; virtual void SetWifiPhy (Ptr phy); virtual void SetWifiRemoteStationManager (Ptr stationManager); + virtual void Enqueue (Ptr packet, Mac48Address to, Mac48Address from); virtual void Enqueue (Ptr packet, Mac48Address to); - virtual void SetForwardUpCallback (Callback, const Mac48Address &> upCallback); + virtual bool SupportsSendFrom (void) const; + virtual void SetForwardUpCallback (Callback, Mac48Address, Mac48Address> upCallback); virtual void SetLinkUpCallback (Callback linkUp); virtual void SetLinkDownCallback (Callback linkDown); virtual Mac48Address GetAddress (void) const; virtual Ssid GetSsid (void) const; - virtual Mac48Address GetBssid (void) const; virtual void SetAddress (Mac48Address address); virtual void SetSsid (Ssid ssid); - + virtual Mac48Address GetBssid (void) const; private: // inherited from Object base class. virtual void DoDispose (void); /* invoked by the MacLows. */ void ForwardUp (Ptr packet, WifiMacHeader const*hdr); + AdhocWifiMac (const AdhocWifiMac & ctor_arg); + AdhocWifiMac &operator = (const AdhocWifiMac &o); Ptr m_dca; - Callback,const Mac48Address &> m_upCallback; + Callback, Mac48Address, Mac48Address> m_upCallback; Ptr m_stationManager; Ptr m_phy; DcfManager *m_dcfManager; MacRxMiddle *m_rxMiddle; Ptr m_low; - Mac48Address m_address; Ssid m_ssid; - Time m_slot; - Time m_sifs; Time m_eifsNoDifs; }; diff --git a/src/devices/wifi/dca-txop.cc b/src/devices/wifi/dca-txop.cc index 1ab34bee6..a9d3f6790 100644 --- a/src/devices/wifi/dca-txop.cc +++ b/src/devices/wifi/dca-txop.cc @@ -37,7 +37,7 @@ NS_LOG_COMPONENT_DEFINE ("DcaTxop"); #define MY_DEBUG(x) \ - NS_LOG_DEBUG (m_low->GetMac ()->GetAddress () << " " << x) + NS_LOG_DEBUG (m_low->GetAddress () << " " << x) namespace ns3 { @@ -305,12 +305,6 @@ DcaTxop::NeedFragmentation (void) return station->NeedFragmentation (m_currentPacket); } -uint32_t -DcaTxop::GetNFragments (void) -{ - WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ()); - return station->GetNFragments (m_currentPacket); -} void DcaTxop::NextFragment (void) { @@ -337,12 +331,19 @@ DcaTxop::GetNextFragmentSize (void) return station->GetFragmentSize (m_currentPacket, m_fragmentNumber + 1); } +uint32_t +DcaTxop::GetFragmentOffset (void) +{ + WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ()); + return station->GetFragmentOffset (m_currentPacket, m_fragmentNumber); +} + Ptr DcaTxop::GetFragmentPacket (WifiMacHeader *hdr) { *hdr = m_currentHdr; hdr->SetFragmentNumber (m_fragmentNumber); - uint32_t startOffset = m_fragmentNumber * GetFragmentSize (); + uint32_t startOffset = GetFragmentOffset (); Ptr fragment; if (IsLastFragment ()) { diff --git a/src/devices/wifi/dca-txop.h b/src/devices/wifi/dca-txop.h index 22d01ad09..7765520b2 100644 --- a/src/devices/wifi/dca-txop.h +++ b/src/devices/wifi/dca-txop.h @@ -137,9 +137,9 @@ private: bool NeedRtsRetransmission (void); bool NeedDataRetransmission (void); bool NeedFragmentation (void); - uint32_t GetNFragments (void); uint32_t GetNextFragmentSize (void); uint32_t GetFragmentSize (void); + uint32_t GetFragmentOffset (void); WifiRemoteStation *GetStation (Mac48Address to) const; bool IsLastFragment (void); void NextFragment (void); diff --git a/src/devices/wifi/ideal-wifi-manager.h b/src/devices/wifi/ideal-wifi-manager.h index 613bda65a..80d3b7503 100644 --- a/src/devices/wifi/ideal-wifi-manager.h +++ b/src/devices/wifi/ideal-wifi-manager.h @@ -50,7 +50,6 @@ public: virtual void SetupPhy (Ptr phy); - WifiMode GetMode (double snr) const; // return the min snr needed to successfully transmit // data with this mode at the specified ber. double GetSnrThreshold (WifiMode mode) const; diff --git a/src/devices/wifi/interference-helper.cc b/src/devices/wifi/interference-helper.cc index 5212f8c4b..3f6ddb42b 100644 --- a/src/devices/wifi/interference-helper.cc +++ b/src/devices/wifi/interference-helper.cc @@ -3,6 +3,7 @@ #include "error-rate-model.h" #include "ns3/simulator.h" #include "ns3/log.h" +#include NS_LOG_COMPONENT_DEFINE ("InterferenceHelper"); @@ -107,6 +108,10 @@ InterferenceHelper::InterferenceHelper () { m_errorRateModel = Create (); } +InterferenceHelper::~InterferenceHelper () +{ + m_errorRateModel = 0; +} Ptr InterferenceHelper::Add (uint32_t size, WifiMode payloadMode, diff --git a/src/devices/wifi/interference-helper.h b/src/devices/wifi/interference-helper.h index 73198d2bd..29d284501 100644 --- a/src/devices/wifi/interference-helper.h +++ b/src/devices/wifi/interference-helper.h @@ -47,6 +47,7 @@ public: }; InterferenceHelper (); + ~InterferenceHelper (); void Configure80211aParameters (void); void SetNoiseFloorW (double noiseFloor); @@ -83,6 +84,8 @@ private: typedef std::vector NiChanges; typedef std::list > Events; + InterferenceHelper (const InterferenceHelper &o); + InterferenceHelper &operator = (const InterferenceHelper &o); void AppendEvent (Ptr event); double CalculateNoiseInterferenceW (Ptr event, NiChanges *ni) const; double CalculateSnr (double signal, double noiseInterference, WifiMode mode) const; diff --git a/src/devices/wifi/jakes-propagation-loss-model.h b/src/devices/wifi/jakes-propagation-loss-model.h index 17ae36e63..bf7c76b50 100644 --- a/src/devices/wifi/jakes-propagation-loss-model.h +++ b/src/devices/wifi/jakes-propagation-loss-model.h @@ -97,7 +97,8 @@ public: * Set the number of oscillators to use to compute the ray coefficient */ void SetNOscillators (uint8_t nOscillators); -protected: + +private: class PathCoefficients; struct ComplexNumber { double real; @@ -109,7 +110,7 @@ protected: ComplexNumber* m_amp; RandomVariable m_variable; double m_fd; -private: + typedef std::vector DestinationList; struct PathsSet { Ptr sender; diff --git a/src/devices/wifi/mac-low.cc b/src/devices/wifi/mac-low.cc index 32825901b..89f31a94b 100644 --- a/src/devices/wifi/mac-low.cc +++ b/src/devices/wifi/mac-low.cc @@ -28,12 +28,11 @@ #include "mac-low.h" #include "wifi-phy.h" #include "wifi-mac-trailer.h" -#include "wifi-mac.h" NS_LOG_COMPONENT_DEFINE ("MacLow"); #define MY_DEBUG(x) \ - NS_LOG_DEBUG (m_mac->GetAddress () << " " << x) + NS_LOG_DEBUG (m_self << " " << x) namespace ns3 { @@ -273,7 +272,6 @@ MacLow::DoDispose (void) NS_LOG_FUNCTION (this); CancelAllEvents (); m_phy = 0; - m_mac = 0; m_stationManager = 0; } @@ -341,21 +339,83 @@ MacLow::SetPhy (Ptr phy) m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::ReceiveOk, this)); m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this)); } -void -MacLow::SetMac (Ptr mac) -{ - m_mac = mac; -} void MacLow::SetWifiRemoteStationManager (Ptr manager) { m_stationManager = manager; } -Ptr -MacLow::GetMac (void) + +void +MacLow::SetAddress (Mac48Address ad) { - return m_mac; + m_self = ad; } +void +MacLow::SetAckTimeout (Time ackTimeout) +{ + m_ackTimeout = ackTimeout; +} +void +MacLow::SetCtsTimeout (Time ctsTimeout) +{ + m_ctsTimeout = ctsTimeout; +} +void +MacLow::SetSifs (Time sifs) +{ + m_sifs = sifs; +} +void +MacLow::SetSlotTime (Time slotTime) +{ + m_slotTime = slotTime; +} +void +MacLow::SetPifs (Time pifs) +{ + m_pifs = pifs; +} +void +MacLow::SetBssid (Mac48Address bssid) +{ + m_bssid = bssid; +} +Mac48Address +MacLow::GetAddress (void) const +{ + return m_self; +} +Time +MacLow::GetAckTimeout (void) const +{ + return m_ackTimeout; +} +Time +MacLow::GetCtsTimeout (void) const +{ + return m_ctsTimeout; +} +Time +MacLow::GetSifs (void) const +{ + return m_sifs; +} +Time +MacLow::GetSlotTime (void) const +{ + return m_slotTime; +} +Time +MacLow::GetPifs (void) const +{ + return m_pifs; +} +Mac48Address +MacLow::GetBssid (void) const +{ + return m_bssid; +} + void MacLow::SetRxCallback (Callback,const WifiMacHeader *> callback) { @@ -451,7 +511,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb * that STA shall not respond to the RTS frame. */ if (isPrevNavZero && - hdr.GetAddr1 () == m_mac->GetAddress ()) + hdr.GetAddr1 () == m_self) { MY_DEBUG ("rx RTS from=" << hdr.GetAddr2 () << ", schedule CTS"); NS_ASSERT (m_sendCtsEvent.IsExpired ()); @@ -470,7 +530,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb } } else if (hdr.IsCts () && - hdr.GetAddr1 () == m_mac->GetAddress () && + hdr.GetAddr1 () == m_self && m_ctsTimeoutEvent.IsRunning () && m_currentPacket != 0) { @@ -491,7 +551,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb txMode); } else if (hdr.IsAck () && - hdr.GetAddr1 () == m_mac->GetAddress () && + hdr.GetAddr1 () == m_self && (m_normalAckTimeoutEvent.IsRunning () || m_fastAckTimeoutEvent.IsRunning () || m_superFastAckTimeoutEvent.IsRunning ()) && @@ -530,7 +590,7 @@ MacLow::ReceiveOk (Ptr packet, double rxSnr, WifiMode txMode, WifiPreamb { MY_DEBUG ("rx drop " << hdr.GetTypeString ()); } - else if (hdr.GetAddr1 () == m_mac->GetAddress ()) + else if (hdr.GetAddr1 () == m_self) { WifiRemoteStation *station = GetStation (hdr.GetAddr2 ()); station->ReportRxOk (rxSnr, txMode); @@ -609,31 +669,6 @@ MacLow::GetCtsSize (void) const cts.SetType (WIFI_MAC_CTL_CTS); return cts.GetSize () + 4; } -Time -MacLow::GetSifs (void) const -{ - return m_mac->GetSifs (); -} -Time -MacLow::GetSlotTime (void) const -{ - return m_mac->GetSlot (); -} -Time -MacLow::GetPifs (void) const -{ - return m_mac->GetPifs (); -} -Time -MacLow::GetAckTimeout (void) const -{ - return m_mac->GetAckTimeout (); -} -Time -MacLow::GetCtsTimeout (void) const -{ - return m_mac->GetCtsTimeout (); -} uint32_t MacLow::GetSize (Ptr packet, const WifiMacHeader *hdr) const { @@ -714,7 +749,7 @@ MacLow::NotifyNav (const WifiMacHeader &hdr, WifiMode txMode, WifiPreamble pream Time duration = hdr.GetDuration (); if (hdr.IsCfpoll () && - hdr.GetAddr2 () == m_mac->GetBssid ()) + hdr.GetAddr2 () == m_bssid) { // see section 9.3.2.2 802.11-1999 DoNavResetNow (duration); @@ -722,7 +757,7 @@ MacLow::NotifyNav (const WifiMacHeader &hdr, WifiMode txMode, WifiPreamble pream } // XXX Note that we should also handle CF_END specially here // but we don't for now because we do not generate them. - else if (hdr.GetAddr1 () != m_mac->GetAddress ()) + else if (hdr.GetAddr1 () != m_self) { // see section 9.2.5.4 802.11-1999 bool navUpdated = DoNavStartNow (duration); @@ -882,9 +917,10 @@ MacLow::SendRtsForPacket (void) rts.SetType (WIFI_MAC_CTL_RTS); rts.SetDsNotFrom (); rts.SetDsNotTo (); + rts.SetNoRetry (); rts.SetNoMoreFragments (); rts.SetAddr1 (m_currentHdr.GetAddr1 ()); - rts.SetAddr2 (m_mac->GetAddress ()); + rts.SetAddr2 (m_self); WifiMode rtsTxMode = GetRtsTxMode (m_currentPacket, &m_currentHdr); Time duration = Seconds (0); if (m_txParams.HasDurationId ()) @@ -1019,7 +1055,7 @@ MacLow::GetStation (Mac48Address ad) const void MacLow::SendCtsAfterRts (Mac48Address source, Time duration, WifiMode rtsTxMode, double rtsSnr) { - NS_LOG_FUNCTION (this); + NS_LOG_FUNCTION (this << source << duration << rtsTxMode << rtsSnr); /* send a CTS when you receive a RTS * right after SIFS. */ @@ -1029,6 +1065,7 @@ MacLow::SendCtsAfterRts (Mac48Address source, Time duration, WifiMode rtsTxMode, cts.SetDsNotFrom (); cts.SetDsNotTo (); cts.SetNoMoreFragments (); + cts.SetNoRetry (); cts.SetAddr1 (source); duration -= GetCtsDuration (source, rtsTxMode); duration -= GetSifs (); @@ -1106,6 +1143,7 @@ MacLow::SendAckAfterData (Mac48Address source, Time duration, WifiMode dataTxMod ack.SetType (WIFI_MAC_CTL_ACK); ack.SetDsNotFrom (); ack.SetDsNotTo (); + ack.SetNoRetry (); ack.SetNoMoreFragments (); ack.SetAddr1 (source); duration -= GetAckDuration (source, dataTxMode); diff --git a/src/devices/wifi/mac-low.h b/src/devices/wifi/mac-low.h index 3933d5790..b3925f57f 100644 --- a/src/devices/wifi/mac-low.h +++ b/src/devices/wifi/mac-low.h @@ -278,10 +278,22 @@ public: virtual ~MacLow (); void SetPhy (Ptr phy); - void SetMac (Ptr mac); void SetWifiRemoteStationManager (Ptr manager); - Ptr GetMac (void); + void SetAddress (Mac48Address ad); + void SetAckTimeout (Time ackTimeout); + void SetCtsTimeout (Time ctsTimeout); + void SetSifs (Time sifs); + void SetSlotTime (Time slotTime); + void SetPifs (Time pifs); + void SetBssid (Mac48Address ad); + Mac48Address GetAddress (void) const; + Time GetAckTimeout (void) const; + Time GetCtsTimeout (void) const; + Time GetSifs (void) const; + Time GetSlotTime (void) const; + Time GetPifs (void) const; + Mac48Address GetBssid (void) const; /** * \param callback the callback which receives every incoming packet. @@ -345,11 +357,6 @@ private: uint32_t GetAckSize (void) const; uint32_t GetRtsSize (void) const; uint32_t GetCtsSize (void) const; - Time GetSifs (void) const; - Time GetPifs (void) const; - Time GetSlotTime (void) const; - Time GetAckTimeout (void) const; - Time GetCtsTimeout (void) const; uint32_t GetSize (Ptr packet, const WifiMacHeader *hdr) const; Time NowUs (void) const; WifiRemoteStation *GetStation (Mac48Address to) const; @@ -388,7 +395,6 @@ private: virtual void DoDispose (void); Ptr m_phy; - Ptr m_mac; Ptr m_stationManager; MacLowRxCallback m_rxCallback; typedef std::vector::const_iterator NavListenersCI; @@ -410,6 +416,13 @@ private: WifiMacHeader m_currentHdr; MacLowTransmissionParameters m_txParams; MacLowTransmissionListener *m_listener; + Mac48Address m_self; + Mac48Address m_bssid; + Time m_ackTimeout; + Time m_ctsTimeout; + Time m_sifs; + Time m_slotTime; + Time m_pifs; Time m_lastNavStart; Time m_lastNavDuration; diff --git a/src/devices/wifi/mgt-headers.cc b/src/devices/wifi/mgt-headers.cc index d18baaecd..eccb71aa6 100644 --- a/src/devices/wifi/mgt-headers.cc +++ b/src/devices/wifi/mgt-headers.cc @@ -163,7 +163,7 @@ MgtProbeResponseHeader::GetSerializedSize (void) const size += m_capability.GetSerializedSize (); size += m_ssid.GetSerializedSize (); size += m_rates.GetSerializedSize (); - size += 3; // ds parameter set + //size += 3; // ds parameter set // xxx return size; } @@ -192,7 +192,7 @@ MgtProbeResponseHeader::Serialize (Buffer::Iterator start) const i = m_capability.Serialize (i); i = m_ssid.Serialize (i); i = m_rates.Serialize (i); - i.Next (3); // ds parameter set. + //i.WriteU8 (0, 3); // ds parameter set. } uint32_t MgtProbeResponseHeader::Deserialize (Buffer::Iterator start) @@ -204,7 +204,7 @@ MgtProbeResponseHeader::Deserialize (Buffer::Iterator start) i = m_capability.Deserialize (i); i = m_ssid.Deserialize (i); i = m_rates.Deserialize (i); - i.Next (3); // ds parameter set + //i.Next (3); // ds parameter set return i.GetDistanceFrom (start); } @@ -215,6 +215,7 @@ MgtProbeResponseHeader::Deserialize (Buffer::Iterator start) NS_OBJECT_ENSURE_REGISTERED (MgtAssocRequestHeader); MgtAssocRequestHeader::MgtAssocRequestHeader () + : m_listenInterval (0) {} MgtAssocRequestHeader::~MgtAssocRequestHeader () {} @@ -307,6 +308,7 @@ MgtAssocRequestHeader::Deserialize (Buffer::Iterator start) NS_OBJECT_ENSURE_REGISTERED (MgtAssocResponseHeader); MgtAssocResponseHeader::MgtAssocResponseHeader () + : m_aid (0) {} MgtAssocResponseHeader::~MgtAssocResponseHeader () {} diff --git a/src/devices/wifi/nqap-wifi-mac.cc b/src/devices/wifi/nqap-wifi-mac.cc index db8add000..f5f6c5016 100644 --- a/src/devices/wifi/nqap-wifi-mac.cc +++ b/src/devices/wifi/nqap-wifi-mac.cc @@ -45,10 +45,11 @@ NqapWifiMac::GetTypeId (void) .AddConstructor () .AddAttribute ("BeaconInterval", "Delay between two beacons", TimeValue (Seconds (0.1)), - MakeTimeAccessor (&NqapWifiMac::m_beaconInterval), + MakeTimeAccessor (&NqapWifiMac::GetBeaconInterval, + &NqapWifiMac::SetBeaconInterval), MakeTimeChecker ()) .AddAttribute ("BeaconGeneration", "Whether or not beacons are generated.", - BooleanValue (false), + BooleanValue (true), MakeBooleanAccessor (&NqapWifiMac::SetBeaconGeneration, &NqapWifiMac::GetBeaconGeneration), MakeBooleanChecker ()) @@ -64,7 +65,6 @@ NqapWifiMac::NqapWifiMac () m_low = CreateObject (); m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle)); - m_low->SetMac (this); m_dcfManager = new DcfManager (); m_dcfManager->SetupLowListener (m_low); @@ -76,6 +76,9 @@ NqapWifiMac::NqapWifiMac () m_dca->SetTxFailedCallback (MakeCallback (&NqapWifiMac::TxFailed, this)); m_beaconDca = CreateObject (); + m_beaconDca->SetAifsn(1); + m_beaconDca->SetMinCw(0); + m_beaconDca->SetMaxCw(0); m_beaconDca->SetLow (m_low); m_beaconDca->SetManager (m_dcfManager); } @@ -119,20 +122,25 @@ NqapWifiMac::GetBeaconGeneration (void) const { return m_beaconEvent.IsRunning (); } +Time +NqapWifiMac::GetBeaconInterval (void) const +{ + return m_beaconInterval; +} void NqapWifiMac::SetSlot (Time slotTime) { NS_LOG_FUNCTION (this << slotTime); m_dcfManager->SetSlot (slotTime); - m_slot = slotTime; + m_low->SetSlotTime (slotTime); } void NqapWifiMac::SetSifs (Time sifs) { NS_LOG_FUNCTION (this << sifs); m_dcfManager->SetSifs (sifs); - m_sifs = sifs; + m_low->SetSifs (sifs); } void NqapWifiMac::SetEifsNoDifs (Time eifsNoDifs) @@ -141,23 +149,51 @@ NqapWifiMac::SetEifsNoDifs (Time eifsNoDifs) m_dcfManager->SetEifsNoDifs (eifsNoDifs); m_eifsNoDifs = eifsNoDifs; } +void +NqapWifiMac::SetAckTimeout (Time ackTimeout) +{ + m_low->SetAckTimeout (ackTimeout); +} +void +NqapWifiMac::SetCtsTimeout (Time ctsTimeout) +{ + m_low->SetCtsTimeout (ctsTimeout); +} +void +NqapWifiMac::SetPifs (Time pifs) +{ + m_low->SetPifs (pifs); +} Time NqapWifiMac::GetSlot (void) const { - return m_slot; + return m_low->GetSlotTime (); } Time NqapWifiMac::GetSifs (void) const { - return m_sifs; + return m_low->GetSifs (); } Time NqapWifiMac::GetEifsNoDifs (void) const { return m_eifsNoDifs; } - - +Time +NqapWifiMac::GetAckTimeout (void) const +{ + return m_low->GetAckTimeout (); +} +Time +NqapWifiMac::GetCtsTimeout (void) const +{ + return m_low->GetCtsTimeout (); +} +Time +NqapWifiMac::GetPifs (void) const +{ + return m_low->GetPifs (); +} void NqapWifiMac::SetWifiPhy (Ptr phy) { @@ -176,7 +212,7 @@ NqapWifiMac::SetWifiRemoteStationManager (Ptr stationM m_low->SetWifiRemoteStationManager (stationManager); } void -NqapWifiMac::SetForwardUpCallback (Callback, const Mac48Address &> upCallback) +NqapWifiMac::SetForwardUpCallback (Callback, Mac48Address, Mac48Address> upCallback) { NS_LOG_FUNCTION (this); m_upCallback = upCallback; @@ -198,23 +234,19 @@ NqapWifiMac::SetLinkDownCallback (Callback linkDown) Mac48Address NqapWifiMac::GetAddress (void) const { - return m_address; + return m_low->GetAddress (); } Ssid NqapWifiMac::GetSsid (void) const { return m_ssid; } -Mac48Address -NqapWifiMac::GetBssid (void) const -{ - return m_address; -} void NqapWifiMac::SetAddress (Mac48Address address) { NS_LOG_FUNCTION (address); - m_address = address; + m_low->SetAddress (address); + m_low->SetBssid (address); } void NqapWifiMac::SetSsid (Ssid ssid) @@ -222,6 +254,11 @@ NqapWifiMac::SetSsid (Ssid ssid) NS_LOG_FUNCTION (ssid); m_ssid = ssid; } +Mac48Address +NqapWifiMac::GetBssid (void) const +{ + return m_low->GetBssid (); +} void @@ -237,10 +274,10 @@ NqapWifiMac::StartBeaconing (void) SendOneBeacon (); } void -NqapWifiMac::ForwardUp (Ptr packet, Mac48Address from) +NqapWifiMac::ForwardUp (Ptr packet, Mac48Address from, Mac48Address to) { NS_LOG_FUNCTION (this << packet << from); - m_upCallback (packet, from); + m_upCallback (packet, from, to); } void NqapWifiMac::ForwardDown (Ptr packet, Mac48Address from, Mac48Address to) @@ -256,10 +293,21 @@ NqapWifiMac::ForwardDown (Ptr packet, Mac48Address from, Mac48Addr m_dca->Queue (packet, hdr); } void +NqapWifiMac::Enqueue (Ptr packet, Mac48Address to, Mac48Address from) +{ + NS_LOG_FUNCTION (this << packet << to << from); + ForwardDown (packet, from, to); +} +void NqapWifiMac::Enqueue (Ptr packet, Mac48Address to) { NS_LOG_FUNCTION (this << packet << to); - ForwardDown (packet, GetAddress (), to); + ForwardDown (packet, m_low->GetAddress (), to); +} +bool +NqapWifiMac::SupportsSendFrom (void) const +{ + return true; } SupportedRates NqapWifiMac::GetSupportedRates (void) const @@ -378,28 +426,38 @@ NqapWifiMac::Receive (Ptr packet, WifiMacHeader const *hdr) { NS_LOG_FUNCTION (this << packet << hdr); - WifiRemoteStation *station = m_stationManager->Lookup (hdr->GetAddr2 ()); + Mac48Address from = hdr->GetAddr2 (); + WifiRemoteStation *fromStation = m_stationManager->Lookup (from); if (hdr->IsData ()) { + Mac48Address bssid = hdr->GetAddr1 (); if (!hdr->IsFromDs () && hdr->IsToDs () && - hdr->GetAddr1 () == GetAddress () && - station->IsAssociated ()) + bssid == GetAddress () && + fromStation->IsAssociated ()) { - if (hdr->GetAddr3 () == GetAddress ()) + Mac48Address to = hdr->GetAddr3 (); + WifiRemoteStation *toStation = m_stationManager->Lookup (to); + if (to == GetAddress ()) { - NS_LOG_DEBUG ("frame for me from="<GetAddr2 ()); - ForwardUp (packet, hdr->GetAddr2 ()); + NS_LOG_DEBUG ("frame for me from="<IsAssociated ()) { - NS_LOG_DEBUG ("forwarding frame from="<GetAddr2 ()<<", to="<GetAddr3 ()); + NS_LOG_DEBUG ("forwarding frame from="< packet, Mac48Address to) { @@ -421,12 +454,18 @@ NqstaWifiMac::Enqueue (Ptr packet, Mac48Address to) WifiMacHeader hdr; hdr.SetTypeData (); hdr.SetAddr1 (GetBssid ()); - hdr.SetAddr2 (GetAddress ()); + hdr.SetAddr2 (m_low->GetAddress ()); hdr.SetAddr3 (to); hdr.SetDsNotFrom (); hdr.SetDsTo (); m_dca->Queue (packet, hdr); } +bool +NqstaWifiMac::SupportsSendFrom (void) const +{ + return true; +} + void NqstaWifiMac::Receive (Ptr packet, WifiMacHeader const *hdr) @@ -440,7 +479,10 @@ NqstaWifiMac::Receive (Ptr packet, WifiMacHeader const *hdr) } else if (hdr->IsData ()) { - ForwardUp (packet, hdr->GetAddr2 ()); + if (hdr->GetAddr3 () != GetAddress ()) + { + ForwardUp (packet, hdr->GetAddr3 (), hdr->GetAddr1 ()); + } } else if (hdr->IsProbeReq () || hdr->IsAssocReq ()) diff --git a/src/devices/wifi/nqsta-wifi-mac.h b/src/devices/wifi/nqsta-wifi-mac.h index a0aaf0fe7..5408d0429 100644 --- a/src/devices/wifi/nqsta-wifi-mac.h +++ b/src/devices/wifi/nqsta-wifi-mac.h @@ -62,21 +62,28 @@ public: virtual void SetSlot (Time slotTime); virtual void SetSifs (Time sifs); virtual void SetEifsNoDifs (Time eifsNoDifs); + virtual void SetAckTimeout (Time ackTimeout); + virtual void SetCtsTimeout (Time ctsTimeout); + virtual void SetPifs (Time pifs); virtual Time GetSlot (void) const; virtual Time GetSifs (void) const; virtual Time GetEifsNoDifs (void) const; + virtual Time GetAckTimeout (void) const; + virtual Time GetCtsTimeout (void) const; + virtual Time GetPifs (void) const; virtual void SetWifiPhy (Ptr phy); virtual void SetWifiRemoteStationManager (Ptr stationManager); + virtual void Enqueue (Ptr packet, Mac48Address to, Mac48Address from); virtual void Enqueue (Ptr packet, Mac48Address to); - virtual void SetForwardUpCallback (Callback, const Mac48Address &> upCallback); + virtual bool SupportsSendFrom (void) const; + virtual void SetForwardUpCallback (Callback, Mac48Address, Mac48Address> upCallback); virtual void SetLinkUpCallback (Callback linkUp); virtual void SetLinkDownCallback (Callback linkDown); virtual Mac48Address GetAddress (void) const; virtual Ssid GetSsid (void) const; - virtual Mac48Address GetBssid (void) const; virtual void SetAddress (Mac48Address address); virtual void SetSsid (Ssid ssid); - + virtual Mac48Address GetBssid (void) const; /** * \param missed the number of beacons which must be missed @@ -107,7 +114,7 @@ private: void SetBssid (Mac48Address bssid); void SetActiveProbing (bool enable); bool GetActiveProbing (void) const; - void ForwardUp (Ptr packet, const Mac48Address &address); + void ForwardUp (Ptr packet, Mac48Address from, Mac48Address to); void Receive (Ptr packet, WifiMacHeader const *hdr); Mac48Address GetBroadcastBssid (void); void SendProbeRequest (void); @@ -120,6 +127,8 @@ private: void RestartBeaconWatchdog (Time delay); SupportedRates GetSupportedRates (void) const; virtual void DoDispose (void); + NqstaWifiMac (const NqstaWifiMac & ctor_arg); + NqstaWifiMac &operator = (const NqstaWifiMac & ctor_arg); enum { ASSOCIATED, @@ -132,13 +141,12 @@ private: Time m_assocRequestTimeout; EventId m_probeRequestEvent; EventId m_assocRequestEvent; - Callback,const Mac48Address &> m_forwardUp; + Callback, Mac48Address, Mac48Address> m_forwardUp; Callback m_linkUp; Callback m_linkDown; Ptr m_dca; EventId m_beaconWatchdog; Time m_beaconWatchdogEnd; - Mac48Address m_bssid; uint32_t m_maxMissedBeacons; Ptr m_phy; @@ -146,10 +154,7 @@ private: DcfManager *m_dcfManager; MacRxMiddle *m_rxMiddle; Ptr m_low; - Mac48Address m_address; Ssid m_ssid; - Time m_slot; - Time m_sifs; Time m_eifsNoDifs; }; diff --git a/src/devices/wifi/propagation-loss-model.cc b/src/devices/wifi/propagation-loss-model.cc index 022f783b7..b54e90a0b 100644 --- a/src/devices/wifi/propagation-loss-model.cc +++ b/src/devices/wifi/propagation-loss-model.cc @@ -97,7 +97,8 @@ FriisPropagationLossModel::GetTypeId (void) .AddAttribute ("MinDistance", "The distance under which the propagation model refuses to give results (m)", DoubleValue (0.5), - MakeDoubleAccessor (&FriisPropagationLossModel::m_minDistance), + MakeDoubleAccessor (&FriisPropagationLossModel::SetMinDistance, + &FriisPropagationLossModel::GetMinDistance), MakeDoubleChecker ()) ; return tid; @@ -116,6 +117,16 @@ FriisPropagationLossModel::GetSystemLoss (void) const return m_systemLoss; } void +FriisPropagationLossModel::SetMinDistance (double minDistance) +{ + m_minDistance = minDistance; +} +double +FriisPropagationLossModel::GetMinDistance (void) const +{ + return m_minDistance; +} +void FriisPropagationLossModel::SetLambda (double frequency, double speed) { m_lambda = speed / frequency; @@ -266,12 +277,10 @@ LogDistancePropagationLossModel::GetLoss (Ptr a, * * rx = rx0(tx) - 10 * n * log (d/d0) */ - static Ptr zero = - CreateObject ("Position", - VectorValue (Vector (0.0, 0.0, 0.0))); - static Ptr reference = - CreateObject ("Position", - VectorValue (Vector (m_referenceDistance, 0.0, 0.0))); + static Ptr zero = CreateObject (); + static Ptr reference = CreateObject (); + zero->SetPosition (Vector (0.0, 0.0, 0.0)); + reference->SetPosition (Vector (m_referenceDistance, 0.0, 0.0)); double ref = m_reference->GetLoss (zero, reference); double pathLossDb = 10 * m_exponent * log10 (distance / m_referenceDistance); double rxc = ref - pathLossDb; diff --git a/src/devices/wifi/propagation-loss-model.h b/src/devices/wifi/propagation-loss-model.h index 4ff7eac25..4ae46aa22 100644 --- a/src/devices/wifi/propagation-loss-model.h +++ b/src/devices/wifi/propagation-loss-model.h @@ -133,6 +133,11 @@ public: */ void SetMinDistance (double minDistance); + /** + * \returns the minimum distance. + */ + double GetMinDistance (void) const; + /** * \returns the current wavelength (m) */ diff --git a/src/devices/wifi/ssid.cc b/src/devices/wifi/ssid.cc index 015cbc078..f7bd1bc78 100644 --- a/src/devices/wifi/ssid.cc +++ b/src/devices/wifi/ssid.cc @@ -32,8 +32,10 @@ Ssid::Ssid () m_ssid[i] = 0; } } -Ssid::Ssid (char const *ssid) +Ssid::Ssid (std::string s) { + NS_ASSERT (s.size () < 32); + const char *ssid = s.c_str (); uint8_t len = 0; while (*ssid != 0 && len < 32) { diff --git a/src/devices/wifi/ssid.h b/src/devices/wifi/ssid.h index dc47e0787..a45fac472 100644 --- a/src/devices/wifi/ssid.h +++ b/src/devices/wifi/ssid.h @@ -35,8 +35,7 @@ class Ssid public: // broadcast ssid Ssid (); - /* 0-terminated string */ - Ssid (char const *ssid); + Ssid (std::string s); Ssid (char const ssid[32], uint8_t length); bool IsEqual (Ssid const &o) const; diff --git a/src/devices/wifi/status-code.h b/src/devices/wifi/status-code.h index e7daf9e26..cbeffc570 100644 --- a/src/devices/wifi/status-code.h +++ b/src/devices/wifi/status-code.h @@ -21,6 +21,7 @@ #define STATUS_CODE_H #include +#include #include "ns3/buffer.h" namespace ns3 { diff --git a/src/devices/wifi/supported-rates.h b/src/devices/wifi/supported-rates.h index 417390f1a..0e52cbe50 100644 --- a/src/devices/wifi/supported-rates.h +++ b/src/devices/wifi/supported-rates.h @@ -21,6 +21,7 @@ #define SUPPORTED_RATES_H #include +#include #include "ns3/buffer.h" namespace ns3 { diff --git a/src/devices/wifi/waf b/src/devices/wifi/waf new file mode 100755 index 000000000..4283ec141 --- /dev/null +++ b/src/devices/wifi/waf @@ -0,0 +1 @@ +exec "`dirname "$0"`"/../../../waf "$@" diff --git a/src/devices/wifi/wifi-mac-header.cc b/src/devices/wifi/wifi-mac-header.cc index 5c93e20a1..057e3a875 100644 --- a/src/devices/wifi/wifi-mac-header.cc +++ b/src/devices/wifi/wifi-mac-header.cc @@ -40,7 +40,8 @@ enum { }; WifiMacHeader::WifiMacHeader () - : m_ctrlMoreData (0), + : m_ctrlPwrMgt (0), + m_ctrlMoreData (0), m_ctrlWep (0), m_ctrlOrder (1) {} diff --git a/src/devices/wifi/wifi-mac-header.h b/src/devices/wifi/wifi-mac-header.h index 33eedd8dd..01498364a 100644 --- a/src/devices/wifi/wifi-mac-header.h +++ b/src/devices/wifi/wifi-mac-header.h @@ -154,27 +154,27 @@ private: void SetQosControl (uint16_t qos); void PrintFrameControl (std::ostream &os) const; - uint16_t m_ctrlType : 2; - uint16_t m_ctrlSubtype : 4; - uint16_t m_ctrlToDs : 1; - uint16_t m_ctrlFromDs : 1; - uint16_t m_ctrlMoreFrag : 1; - uint16_t m_ctrlRetry : 1; - uint16_t m_ctrlPwrMgt : 1; - uint16_t m_ctrlMoreData : 1; - uint16_t m_ctrlWep : 1; - uint16_t m_ctrlOrder : 1; + uint8_t m_ctrlType; + uint8_t m_ctrlSubtype; + uint8_t m_ctrlToDs; + uint8_t m_ctrlFromDs; + uint8_t m_ctrlMoreFrag; + uint8_t m_ctrlRetry; + uint8_t m_ctrlPwrMgt; + uint8_t m_ctrlMoreData; + uint8_t m_ctrlWep; + uint8_t m_ctrlOrder; uint16_t m_duration; Mac48Address m_addr1; Mac48Address m_addr2; Mac48Address m_addr3; - uint16_t m_seqFrag : 4; - uint16_t m_seqSeq : 12; + uint8_t m_seqFrag; + uint16_t m_seqSeq; Mac48Address m_addr4; - uint16_t m_qosTid : 4; - uint16_t m_qosEosp : 1; - uint16_t m_qosAckPolicy : 2; - uint16_t m_qosStuff: 8; + uint8_t m_qosTid; + uint8_t m_qosEosp; + uint8_t m_qosAckPolicy; + uint16_t m_qosStuff; }; } // namespace ns3 diff --git a/src/devices/wifi/wifi-mac.cc b/src/devices/wifi/wifi-mac.cc index 49116b256..844eb6ef1 100644 --- a/src/devices/wifi/wifi-mac.cc +++ b/src/devices/wifi/wifi-mac.cc @@ -75,11 +75,13 @@ WifiMac::GetTypeId (void) .SetParent () .AddAttribute ("CtsTimeout", "When this timeout expires, the RTS/CTS handshake has failed.", TimeValue (GetDefaultCtsAckTimeout ()), - MakeTimeAccessor (&WifiMac::m_ctsTimeout), + MakeTimeAccessor (&WifiMac::SetCtsTimeout, + &WifiMac::GetCtsTimeout), MakeTimeChecker ()) .AddAttribute ("AckTimeout", "When this timeout expires, the DATA/ACK handshake has failed.", TimeValue (GetDefaultCtsAckTimeout ()), - MakeTimeAccessor (&WifiMac::m_ackTimeout), + MakeTimeAccessor (&WifiMac::GetAckTimeout, + &WifiMac::SetAckTimeout), MakeTimeChecker ()) .AddAttribute ("Sifs", "The value of the SIFS constant.", TimeValue (GetDefaultSifs ()), @@ -98,7 +100,8 @@ WifiMac::GetTypeId (void) MakeTimeChecker ()) .AddAttribute ("Pifs", "The value of the PIFS constant.", TimeValue (GetDefaultSifs () + GetDefaultSlot ()), - MakeTimeAccessor (&WifiMac::m_pifs), + MakeTimeAccessor (&WifiMac::SetPifs, + &WifiMac::GetPifs), MakeTimeChecker ()) .AddAttribute ("MaxPropagationDelay", "The maximum propagation delay. Unused for now.", TimeValue (GetDefaultMaxPropagationDelay ()), @@ -118,41 +121,11 @@ WifiMac::GetTypeId (void) return tid; } -void -WifiMac::SetPifs (Time pifs) -{ - m_pifs = pifs; -} -void -WifiMac::SetCtsTimeout (Time ctsTimeout) -{ - m_ctsTimeout = ctsTimeout; -} -void -WifiMac::SetAckTimeout (Time ackTimeout) -{ - m_ackTimeout = ackTimeout; -} void WifiMac::SetMaxPropagationDelay (Time delay) { m_maxPropagationDelay = delay; } -Time -WifiMac::GetPifs (void) const -{ - return m_pifs; -} -Time -WifiMac::GetCtsTimeout (void) const -{ - return m_ctsTimeout; -} -Time -WifiMac::GetAckTimeout (void) const -{ - return m_ackTimeout; -} Time WifiMac::GetMsduLifetime (void) const diff --git a/src/devices/wifi/wifi-mac.h b/src/devices/wifi/wifi-mac.h index 2d76fe91d..5e5ef7094 100644 --- a/src/devices/wifi/wifi-mac.h +++ b/src/devices/wifi/wifi-mac.h @@ -60,15 +60,15 @@ public: /** * \param pifs the pifs duration. */ - void SetPifs (Time pifs); + virtual void SetPifs (Time pifs) = 0; /** * \param ctsTimeout the duration of a CTS timeout. */ - void SetCtsTimeout (Time ctsTimeout); + virtual void SetCtsTimeout (Time ctsTimeout) = 0; /** * \param ackTimeout the duration of an ACK timeout. */ - void SetAckTimeout (Time ackTimeout); + virtual void SetAckTimeout (Time ackTimeout) = 0; /** * \param delay the max propagation delay. * @@ -79,7 +79,7 @@ public: /** * \returns the current PIFS duration. */ - Time GetPifs (void) const; + virtual Time GetPifs (void) const = 0; /** * \returns the current SIFS duration. */ @@ -95,11 +95,11 @@ public: /** * \returns the current CTS timeout duration. */ - Time GetCtsTimeout (void) const; + virtual Time GetCtsTimeout (void) const = 0; /** * \returns the current ACK timeout duration. */ - Time GetAckTimeout (void) const; + virtual Time GetAckTimeout (void) const = 0; /** * Unused for now. */ @@ -121,14 +121,6 @@ public: * \returns the ssid which this MAC layer is going to try to stay in. */ virtual Ssid GetSsid (void) const = 0; - /** - * \returns the BSSID associated to the current SSID. - * - * If we are an AP, this is the address of the AP itself. - * If are a STA, this is the address of the AP with which - * the STA is associated. - */ - virtual Mac48Address GetBssid (void) const = 0; /** * \param address the current address of this MAC layer. */ @@ -137,7 +129,23 @@ public: * \param ssid the current ssid of this MAC layer. */ virtual void SetSsid (Ssid ssid) = 0; + /** + * \returns the bssid of the network this device belongs to. + */ + virtual Mac48Address GetBssid (void) const = 0; + /** + * \param packet the packet to send. + * \param to the address to which the packet should be sent. + * \param from the address from which the packet should be sent. + * + * The packet should be enqueued in a tx queue, and should be + * dequeued as soon as the DCF function determines that + * access it granted to this MAC. The extra parameter "from" allows + * this device to operate in a bridged mode, forwarding received + * frames without altering the source addresss. + */ + virtual void Enqueue (Ptr packet, Mac48Address to, Mac48Address from) = 0; /** * \param packet the packet to send. * \param to the address to which the packet should be sent. @@ -147,6 +155,7 @@ public: * access it granted to this MAC. */ virtual void Enqueue (Ptr packet, Mac48Address to) = 0; + virtual bool SupportsSendFrom (void) const = 0; /** * \param phy the physical layer attached to this MAC. */ @@ -158,7 +167,7 @@ public: /** * \param upCallback the callback to invoke when a packet must be forwarded up the stack. */ - virtual void SetForwardUpCallback (Callback, const Mac48Address &> upCallback) = 0; + virtual void SetForwardUpCallback (Callback, Mac48Address, Mac48Address> upCallback) = 0; /** * \param linkUp the callback to invoke when the link becomes up. */ @@ -178,9 +187,6 @@ private: static Time GetDefaultCtsAckDelay (void); static Time GetDefaultCtsAckTimeout (void); - Time m_pifs; - Time m_ctsTimeout; - Time m_ackTimeout; Time m_maxPropagationDelay; uint32_t m_maxMsduSize; }; diff --git a/src/devices/wifi/wifi-net-device.cc b/src/devices/wifi/wifi-net-device.cc index 48e751262..a02cd4549 100644 --- a/src/devices/wifi/wifi-net-device.cc +++ b/src/devices/wifi/wifi-net-device.cc @@ -245,12 +245,12 @@ WifiNetDevice::IsMulticast (void) const Address WifiNetDevice::GetMulticast (void) const { - return Mac48Address ("01:00:5e:00:00:00"); + return Mac48Address::GetMulticastPrefix (); } Address WifiNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const { - return GetMulticast (); + return Mac48Address::GetMulticast (multicastGroup); } bool WifiNetDevice::IsPointToPoint (void) const @@ -295,12 +295,36 @@ WifiNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) } void -WifiNetDevice::ForwardUp (Ptr packet, const Mac48Address &from) +WifiNetDevice::ForwardUp (Ptr packet, Mac48Address from, Mac48Address to) { m_rxLogger (packet, from); LlcSnapHeader llc; packet->RemoveHeader (llc); - m_forwardUp (this, packet, llc.GetType (), from); + enum NetDevice::PacketType type; + if (to.IsBroadcast ()) + { + type = NetDevice::PACKET_BROADCAST; + } + else if (to.IsMulticast ()) + { + type = NetDevice::PACKET_MULTICAST; + } + else if (to == m_mac->GetAddress ()) + { + type = NetDevice::PACKET_HOST; + } + else + { + type = NetDevice::PACKET_OTHERHOST; + } + if (type != NetDevice::PACKET_OTHERHOST) + { + m_forwardUp (this, packet, llc.GetType (), from); + } + if (!m_promiscRx.IsNull ()) + { + m_promiscRx (this, packet, llc.GetType (), from, to, type); + } } void @@ -322,5 +346,37 @@ WifiNetDevice::LinkDown (void) } } +bool +WifiNetDevice::SendFrom (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) +{ + NS_ASSERT (Mac48Address::IsMatchingType (dest)); + NS_ASSERT (Mac48Address::IsMatchingType (source)); + + Mac48Address realTo = Mac48Address::ConvertFrom (dest); + Mac48Address realFrom = Mac48Address::ConvertFrom (source); + + LlcSnapHeader llc; + llc.SetType (protocolNumber); + packet->AddHeader (llc); + + m_txLogger (packet, realTo); + + m_mac->Enqueue (packet, realTo, realFrom); + + return true; +} + +void +WifiNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb) +{ + m_promiscRx = cb; +} + +bool +WifiNetDevice::SupportsSendFrom (void) const +{ + return m_mac->SupportsSendFrom (); +} + } // namespace ns3 diff --git a/src/devices/wifi/wifi-net-device.h b/src/devices/wifi/wifi-net-device.h index 6740b9e20..556ddde15 100644 --- a/src/devices/wifi/wifi-net-device.h +++ b/src/devices/wifi/wifi-net-device.h @@ -101,9 +101,13 @@ public: virtual bool NeedsArp (void) const; virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); + virtual bool SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb); + virtual bool SupportsSendFrom (void) const; + private: virtual void DoDispose (void); - void ForwardUp (Ptr packet, const Mac48Address &from); + void ForwardUp (Ptr packet, Mac48Address from, Mac48Address to); void LinkUp (void); void LinkDown (void); void Setup (void); @@ -113,7 +117,8 @@ private: Ptr m_channel; Ptr m_mac; Ptr m_stationManager; - Callback ,Ptr,uint16_t,const Address &> m_forwardUp; + NetDevice::ReceiveCallback m_forwardUp; + NetDevice::PromiscReceiveCallback m_promiscRx; TracedCallback, Mac48Address> m_rxLogger; TracedCallback, Mac48Address> m_txLogger; uint32_t m_ifIndex; diff --git a/src/devices/wifi/wifi-phy.h b/src/devices/wifi/wifi-phy.h index 01b8bc225..89dd95fc2 100644 --- a/src/devices/wifi/wifi-phy.h +++ b/src/devices/wifi/wifi-phy.h @@ -240,7 +240,6 @@ public: */ virtual double CalculateSnr (WifiMode txMode, double ber) const = 0; - virtual Ptr GetChannel (void) const = 0; static WifiMode g_6mba; diff --git a/src/devices/wifi/wifi-remote-station-manager.cc b/src/devices/wifi/wifi-remote-station-manager.cc index cab82289d..9744587d5 100644 --- a/src/devices/wifi/wifi-remote-station-manager.cc +++ b/src/devices/wifi/wifi-remote-station-manager.cc @@ -656,6 +656,13 @@ WifiRemoteStation::GetFragmentSize (Ptr packet, uint32_t fragmentN return GetManager ()->GetFragmentationThreshold (); } } +uint32_t +WifiRemoteStation::GetFragmentOffset (Ptr packet, uint32_t fragmentNumber) +{ + NS_ASSERT (fragmentNumber < GetNFragments (packet)); + uint32_t fragmentOffset = fragmentNumber * GetManager ()->GetFragmentationThreshold (); + return fragmentOffset; +} bool WifiRemoteStation::IsLastFragment (Ptr packet, uint32_t fragmentNumber) diff --git a/src/devices/wifi/wifi-remote-station-manager.h b/src/devices/wifi/wifi-remote-station-manager.h index 2c89e04dc..00e23f485 100644 --- a/src/devices/wifi/wifi-remote-station-manager.h +++ b/src/devices/wifi/wifi-remote-station-manager.h @@ -226,17 +226,18 @@ public: * \returns true if this packet should be fragmented, false otherwise. */ virtual bool NeedFragmentation (Ptr packet); - /** - * \param packet the packet to send - * \returns the number of fragments which should be used for this packet. - */ - virtual uint32_t GetNFragments (Ptr packet); /** * \param packet the packet to send * \param fragmentNumber the fragment index of the next fragment to send (starts at zero). * \returns the size of the corresponding fragment. */ virtual uint32_t GetFragmentSize (Ptr packet, uint32_t fragmentNumber); + /** + * \param packet the packet to send + * \param fragmentNumber the fragment index of the next fragment to send (starts at zero). + * \returns the offset within the original packet where this fragment starts. + */ + virtual uint32_t GetFragmentOffset (Ptr packet, uint32_t fragmentNumber); /** * \param packet the packet to send * \param fragmentNumber the fragment index of the next fragment to send (starts at zero). @@ -262,6 +263,7 @@ private: virtual Ptr GetManager (void) const = 0; virtual WifiMode DoGetDataMode (uint32_t size) = 0; virtual WifiMode DoGetRtsMode (void) = 0; + uint32_t GetNFragments (Ptr packet); protected: virtual void DoReportRtsFailed (void) = 0; virtual void DoReportDataFailed (void) = 0; diff --git a/src/devices/wifi/yans-wifi-phy.h b/src/devices/wifi/yans-wifi-phy.h index 03462aecc..bfeb4d74e 100644 --- a/src/devices/wifi/yans-wifi-phy.h +++ b/src/devices/wifi/yans-wifi-phy.h @@ -117,6 +117,7 @@ private: typedef std::vector Modes; private: + YansWifiPhy (const YansWifiPhy &o); virtual void DoDispose (void); void Configure80211a (void); void ConfigureHolland (void); diff --git a/src/helper/bridge-helper.cc b/src/helper/bridge-helper.cc new file mode 100644 index 000000000..720dfb86d --- /dev/null +++ b/src/helper/bridge-helper.cc @@ -0,0 +1,34 @@ +#include "bridge-helper.h" + +#include "ns3/bridge-net-device.h" +#include "ns3/node.h" + +namespace ns3 { + +BridgeHelper::BridgeHelper () +{ + m_deviceFactory.SetTypeId ("ns3::BridgeNetDevice"); +} + +void +BridgeHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1) +{ + m_deviceFactory.Set (n1, v1); +} + +NetDeviceContainer +BridgeHelper::Install (Ptr node, NetDeviceContainer c) +{ + NetDeviceContainer devs; + Ptr dev = m_deviceFactory.Create (); + devs.Add (dev); + node->AddDevice (dev); + + for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + dev->AddBridgePort (*i); + } + return devs; +} + +} // namespace ns3 diff --git a/src/helper/bridge-helper.h b/src/helper/bridge-helper.h new file mode 100644 index 000000000..62f8a49b2 --- /dev/null +++ b/src/helper/bridge-helper.h @@ -0,0 +1,26 @@ +#ifndef BRIDGE_HELPER_H +#define BRIDGE_HELPER_H + +#include "net-device-container.h" +#include "ns3/object-factory.h" +#include + +namespace ns3 { + +class Node; +class AttributeValue; + +class BridgeHelper +{ +public: + BridgeHelper (); + void SetDeviceAttribute (std::string n1, const AttributeValue &v1); + NetDeviceContainer Install (Ptr node, NetDeviceContainer c); +private: + ObjectFactory m_deviceFactory; +}; + +} // namespace ns3 + + +#endif /* BRIDGE_HELPER_H */ diff --git a/src/helper/csma-helper.cc b/src/helper/csma-helper.cc index 391e529c7..b3ee71a60 100644 --- a/src/helper/csma-helper.cc +++ b/src/helper/csma-helper.cc @@ -39,10 +39,10 @@ CsmaHelper::CsmaHelper () void CsmaHelper::SetQueue (std::string type, - std::string n1, const AttributeValue &v1, - std::string n2, const AttributeValue &v2, - std::string n3, const AttributeValue &v3, - std::string n4, const AttributeValue &v4) + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4) { m_queueFactory.SetTypeId (type); m_queueFactory.Set (n1, v1); @@ -52,21 +52,39 @@ CsmaHelper::SetQueue (std::string type, } void -CsmaHelper::SetDeviceParameter (std::string n1, const AttributeValue &v1) +CsmaHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1) { m_deviceFactory.Set (n1, v1); } void -CsmaHelper::SetChannelParameter (std::string n1, const AttributeValue &v1) +CsmaHelper::SetChannelAttribute (std::string n1, const AttributeValue &v1) { m_channelFactory.Set (n1, v1); } +void +CsmaHelper::SetDeviceParameter (std::string n1, const AttributeValue &v1) +{ + SetDeviceAttribute (n1, v1); +} +void +CsmaHelper::SetChannelParameter (std::string n1, const AttributeValue &v1) +{ + SetChannelAttribute (n1, v1); +} + void CsmaHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid) { std::ostringstream oss; + oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/"; + Config::MatchContainer matches = Config::LookupMatches (oss.str ()); + if (matches.GetN () == 0) + { + return; + } + oss.str (""); oss << filename << "-" << nodeid << "-" << deviceid << ".pcap"; Ptr pcap = Create (); pcap->Open (oss.str ()); @@ -95,9 +113,9 @@ CsmaHelper::EnablePcap (std::string filename, NodeContainer n) { Ptr node = *i; for (uint32_t j = 0; j < node->GetNDevices (); ++j) - { - devs.Add (node->GetDevice (j)); - } + { + devs.Add (node->GetDevice (j)); + } } EnablePcap (filename, devs); } @@ -111,7 +129,7 @@ CsmaHelper::EnablePcapAll (std::string filename) void CsmaHelper::EnableAscii (std::ostream &os, uint32_t nodeid, uint32_t deviceid) { - Packet::EnableMetadata (); + Packet::EnablePrinting (); std::ostringstream oss; oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::CsmaNetDevice/Rx"; Config::Connect (oss.str (), MakeBoundCallback (&CsmaHelper::AsciiRxEvent, &os)); @@ -142,9 +160,9 @@ CsmaHelper::EnableAscii (std::ostream &os, NodeContainer n) { Ptr node = *i; for (uint32_t j = 0; j < node->GetNDevices (); ++j) - { - devs.Add (node->GetDevice (j)); - } + { + devs.Add (node->GetDevice (j)); + } } EnableAscii (os, devs); } @@ -181,6 +199,19 @@ CsmaHelper::Install (const NodeContainer &c, Ptr channel) return container; } +void +CsmaHelper::InstallStar (Ptr hub, NodeContainer spokes, + NetDeviceContainer& hubDevices, NetDeviceContainer& spokeDevices) +{ + for (uint32_t i = 0; i < spokes.GetN (); ++i) + { + NodeContainer nodes (hub, spokes.Get (i)); + NetDeviceContainer nd = Install (nodes); + hubDevices.Add (nd.Get (0)); + spokeDevices.Add (nd.Get (1)); + } +} + void CsmaHelper::EnqueueEvent (Ptr writer, Ptr packet) { diff --git a/src/helper/csma-helper.h b/src/helper/csma-helper.h index 2a2822f3b..9ffa4a51b 100644 --- a/src/helper/csma-helper.h +++ b/src/helper/csma-helper.h @@ -27,6 +27,7 @@ #include "ns3/net-device-container.h" #include "ns3/node-container.h" #include "ns3/csma-channel.h" +#include "ns3/deprecated.h" namespace ns3 { @@ -56,28 +57,31 @@ public: * CsmaNetDevice created through CsmaHelper::Install. */ void SetQueue (std::string type, - std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), - std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), - std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue ()); + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue ()); /** * \param n1 the name of the attribute to set * \param v1 the value of the attribute to set * - * Set these parameters on each ns3::CsmaNetDevice created + * Set these attributes on each ns3::CsmaNetDevice created * by CsmaHelper::Install */ - void SetDeviceParameter (std::string n1, const AttributeValue &v1); + void SetDeviceAttribute (std::string n1, const AttributeValue &v1); /** * \param n1 the name of the attribute to set * \param v1 the value of the attribute to set * - * Set these parameters on each ns3::CsmaChannel created + * Set these attributes on each ns3::CsmaChannel created * by CsmaHelper::Install */ - void SetChannelParameter (std::string n1, const AttributeValue &v1); + void SetChannelAttribute (std::string n1, const AttributeValue &v1); + + void SetDeviceParameter (std::string n1, const AttributeValue &v1) NS_DEPRECATED; + void SetChannelParameter (std::string n1, const AttributeValue &v1) NS_DEPRECATED; /** * \param filename filename prefix to use for pcap files. @@ -160,7 +164,7 @@ public: * \param c a set of nodes * * This method creates a simple ns3::CsmaChannel with the - * attributes configured by CsmaHelper::SetChannelParameter and + * attributes configured by CsmaHelper::SetChannelAttribute and * then calls CsmaHelper::Install. */ NetDeviceContainer Install (const NodeContainer &c); @@ -170,11 +174,44 @@ public: * \param channel the channel to use as a backbone. * * For each node in the input container, we create a ns3::CsmaNetDevice with - * the requested parameters, a queue for this NetDevice, and associate + * the requested attributes, a queue for this NetDevice, and associate * the resulting ns3::NetDevice with the ns3::Node and ns3::CsmaChannel. */ NetDeviceContainer Install (const NodeContainer &c, Ptr channel); + /** + * \brief Make a star network topology. + * + * Given a pointer to a node that will become the hub of the star, and a + * NodeContainer containing pointers to the nodes that will become the + * spokes; we construct CSMA net devices on the hub (corresponding to the + * spokes) and store them in the hubDevices NetDeviceContainer. We add a + * net device to each spoke node and store them in the spokeDevices + * NetDeviceContainer. A CSMA is created for each spoke. + * + * Usually when one thinks of a star network, one thinks of point-to-point + * links. We're just using a single pair of devices on a multi-point-to-point + * network "drops" as the link. You are free to add any number of other + * devices on the link if you want. + * + * The ordering of the devices in the hubDevices container is according to + * the order of the spokes container -- that is, hubDevices[0] will be the + * net device used on the hub that talks to spokes[0]. the container entry + * spokeDevices[0] will have the device that hubDevices[0] talks to -- those + * two devices are the ones that connect hub to spokes[0]. + * + * \param hub The central node of the star network + * \param spokes A NodeContainer of the nodes that will be the spoke (leaf) + * nodes + * \param hubDevices A NetDeviceContainer that will be filled with pointers + * to the point-to-point net devices created on the hub. + * \param spokeDevices A NetDeviceContainer that will be filled with pointers + * to the point-to-point net devices created on each of + * the spokes. + */ + void InstallStar (Ptr hub, NodeContainer spokes, + NetDeviceContainer& hubDevices, NetDeviceContainer& spokeDevices); + private: static void RxEvent (Ptr writer, Ptr packet); static void EnqueueEvent (Ptr writer, Ptr packet); diff --git a/src/helper/internet-stack-helper.cc b/src/helper/internet-stack-helper.cc index 8b6661bfb..ac4523848 100644 --- a/src/helper/internet-stack-helper.cc +++ b/src/helper/internet-stack-helper.cc @@ -26,12 +26,17 @@ #include "ns3/packet-socket-factory.h" #include "ns3/config.h" #include "ns3/simulator.h" +#include namespace ns3 { std::vector InternetStackHelper::m_traces; std::string InternetStackHelper::m_pcapBaseFilename; +InternetStackHelper::InternetStackHelper() : m_nscLibrary("") +{ +} + void InternetStackHelper::Cleanup (void) { @@ -47,6 +52,12 @@ InternetStackHelper::Cleanup (void) m_traces.clear (); } +void +InternetStackHelper::SetNscStack(const std::string soname) +{ + m_nscLibrary = soname; +} + void InternetStackHelper::Install (NodeContainer c) { @@ -58,8 +69,12 @@ InternetStackHelper::Install (NodeContainer c) NS_FATAL_ERROR ("InternetStackHelper::Install(): Aggregating " "an InternetStack to a node with an existing Ipv4 object"); return; - } - AddInternetStack (node); + } + if (m_nscLibrary != "") + AddNscInternetStack (node, m_nscLibrary); + else + AddInternetStack (node); + Ptr factory = CreateObject (); node->AggregateObject (factory); } diff --git a/src/helper/internet-stack-helper.h b/src/helper/internet-stack-helper.h index 74f1054e0..59b397a34 100644 --- a/src/helper/internet-stack-helper.h +++ b/src/helper/internet-stack-helper.h @@ -33,6 +33,8 @@ namespace ns3 { class InternetStackHelper { public: + InternetStackHelper(void); + /** * \param c the set of nodes * @@ -44,6 +46,13 @@ public: */ void Install (NodeContainer c); + /** + * \param soname name of the shared library with the nsc tcp stack + * to use, e.g. 'liblinux2.6.26.so'. The empty string resets + * the InternetStackHelper to use the ns-3 models again. + */ + void SetNscStack(std::string soname); + /** * \param filename filename prefix to use for pcap files. * @@ -60,6 +69,7 @@ public: static void EnablePcapAll (std::string filename); private: + std::string m_nscLibrary; static void Cleanup (void); static void LogRxIp (std::string context, Ptr packet, uint32_t deviceId); static void LogTxIp (std::string context, Ptr packet, uint32_t deviceId); diff --git a/src/helper/ipv4-interface-container.cc b/src/helper/ipv4-interface-container.cc index 9b57609f3..d31174e30 100644 --- a/src/helper/ipv4-interface-container.cc +++ b/src/helper/ipv4-interface-container.cc @@ -6,11 +6,21 @@ namespace ns3 { Ipv4InterfaceContainer::Ipv4InterfaceContainer () {} +void +Ipv4InterfaceContainer::Add (Ipv4InterfaceContainer other) +{ + for (InterfaceVector::const_iterator i = other.m_interfaces.begin (); i != other.m_interfaces.end (); i++) + { + m_interfaces.push_back (*i); + } +} + uint32_t Ipv4InterfaceContainer::GetN (void) const { return m_interfaces.size (); } + Ipv4Address Ipv4InterfaceContainer::GetAddress (uint32_t i) const { diff --git a/src/helper/ipv4-interface-container.h b/src/helper/ipv4-interface-container.h index 7c38fac15..ed544bef8 100644 --- a/src/helper/ipv4-interface-container.h +++ b/src/helper/ipv4-interface-container.h @@ -20,6 +20,11 @@ public: */ Ipv4InterfaceContainer (); + /** + * Concatenate the entries in the other container with ours. + */ + void Add (Ipv4InterfaceContainer other); + /** * \returns the number of interfaces stored in this Ipv4InterfaceContainer. */ @@ -31,7 +36,9 @@ public: void Add (Ptr ipv4, uint32_t interface); private: - std::vector,uint32_t> > m_interfaces; + + typedef std::vector,uint32_t> > InterfaceVector; + InterfaceVector m_interfaces; }; } // namespace ns3 diff --git a/src/helper/mobility-helper.cc b/src/helper/mobility-helper.cc index 1976f0c63..ad595f4d2 100644 --- a/src/helper/mobility-helper.cc +++ b/src/helper/mobility-helper.cc @@ -23,6 +23,9 @@ #include "ns3/hierarchical-mobility-model.h" #include "ns3/log.h" #include "ns3/pointer.h" +#include "ns3/config.h" +#include "ns3/simulator.h" +#include namespace ns3 { @@ -44,15 +47,15 @@ MobilityHelper::SetPositionAllocator (Ptr allocator) } void MobilityHelper::SetPositionAllocator (std::string type, - std::string n1, const AttributeValue &v1, - std::string n2, const AttributeValue &v2, - std::string n3, const AttributeValue &v3, - std::string n4, const AttributeValue &v4, - std::string n5, const AttributeValue &v5, - std::string n6, const AttributeValue &v6, - std::string n7, const AttributeValue &v7, - std::string n8, const AttributeValue &v8, - std::string n9, const AttributeValue &v9) + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4, + std::string n5, const AttributeValue &v5, + std::string n6, const AttributeValue &v6, + std::string n7, const AttributeValue &v7, + std::string n8, const AttributeValue &v8, + std::string n9, const AttributeValue &v9) { ObjectFactory pos; pos.SetTypeId (type); @@ -70,15 +73,15 @@ MobilityHelper::SetPositionAllocator (std::string type, void MobilityHelper::SetMobilityModel (std::string type, - std::string n1, const AttributeValue &v1, - std::string n2, const AttributeValue &v2, - std::string n3, const AttributeValue &v3, - std::string n4, const AttributeValue &v4, - std::string n5, const AttributeValue &v5, - std::string n6, const AttributeValue &v6, - std::string n7, const AttributeValue &v7, - std::string n8, const AttributeValue &v8, - std::string n9, const AttributeValue &v9) + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4, + std::string n5, const AttributeValue &v5, + std::string n6, const AttributeValue &v6, + std::string n7, const AttributeValue &v7, + std::string n8, const AttributeValue &v8, + std::string n9, const AttributeValue &v9) { m_mobility.SetTypeId (type); m_mobility.Set (n1, v1); @@ -119,29 +122,29 @@ MobilityHelper::Install (NodeContainer c) Ptr object = *i; Ptr model = object->GetObject (); if (model == 0) - { - model = m_mobility.Create ()->GetObject (); - if (model == 0) - { - NS_FATAL_ERROR ("The requested mobility model is not a mobility model: \""<< - m_mobility.GetTypeId ().GetName ()<<"\""); - } - if (m_mobilityStack.empty ()) - { - NS_LOG_DEBUG ("node="<AggregateObject (hierarchical); - NS_LOG_DEBUG ("node="<AggregateObject (hierarchical); + NS_LOG_DEBUG ("node="<flags (saved_flags); + os->precision (saved_precision); +} + +void +MobilityHelper::EnableAscii (std::ostream &os, uint32_t nodeid) +{ + std::ostringstream oss; + oss << "/NodeList/" << nodeid << "/$ns3::MobilityModel/CourseChange"; + Config::ConnectWithoutContext (oss.str (), + MakeBoundCallback (&MobilityHelper::CourseChanged, &os)); +} +void +MobilityHelper::EnableAscii (std::ostream &os, NodeContainer n) +{ + for (NodeContainer::Iterator i = n.Begin (); i != n.End (); ++i) + { + EnableAscii (os, (*i)->GetId ()); + } +} +void +MobilityHelper::EnableAsciiAll (std::ostream &os) +{ + EnableAscii (os, NodeContainer::GetGlobal ()); +} + } // namespace ns3 diff --git a/src/helper/mobility-helper.h b/src/helper/mobility-helper.h index d37eb36c6..942c2bb8b 100644 --- a/src/helper/mobility-helper.h +++ b/src/helper/mobility-helper.h @@ -72,15 +72,15 @@ public: * \param v9 the value of the attribute to set in the mobility model. */ void SetPositionAllocator (std::string type, - std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), - std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), - std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), - std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), - std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), - std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue (), - std::string n8 = "", const AttributeValue &v8 = EmptyAttributeValue (), - std::string n9 = "", const AttributeValue &v9 = EmptyAttributeValue ()); + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), + std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), + std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), + std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue (), + std::string n8 = "", const AttributeValue &v8 = EmptyAttributeValue (), + std::string n9 = "", const AttributeValue &v9 = EmptyAttributeValue ()); /** * \param type the type of mobility model to use. @@ -107,15 +107,15 @@ public: * mobility model for each node. */ void SetMobilityModel (std::string type, - std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), - std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), - std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), - std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), - std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), - std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue (), - std::string n8 = "", const AttributeValue &v8 = EmptyAttributeValue (), - std::string n9 = "", const AttributeValue &v9 = EmptyAttributeValue ()); + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), + std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), + std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), + std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue (), + std::string n8 = "", const AttributeValue &v8 = EmptyAttributeValue (), + std::string n9 = "", const AttributeValue &v9 = EmptyAttributeValue ()); /** * \param reference item to push. @@ -163,8 +163,36 @@ public: * exist in the simulation. */ void InstallAll (void); -private: + /** + * \param os output stream + * \param nodeid the id of the node to generate ascii output for. + * + * Enable ascii output on the mobility model associated to the + * specified nodeid and dump that to the specified stdc++ output + * stream. + */ + static void EnableAscii (std::ostream &os, uint32_t nodeid); + /** + * \param os output stream + * \param n node container + * + * Enable ascii output on the mobility model associated each of + * the nodes in the input container and dump that to the + * specified stdc++ output stream. + */ + static void EnableAscii (std::ostream &os, NodeContainer n); + /** + * \param os output stream + * + * Enable ascii output on the mobility model associated + * every node in the system and dump that to the specified + * stdc++ output stream. + */ + static void EnableAsciiAll (std::ostream &os); + +private: + static void CourseChanged (std::ostream *os, Ptr mobility); std::vector > m_mobilityStack; ObjectFactory m_mobility; Ptr m_position; diff --git a/src/helper/net-device-container.cc b/src/helper/net-device-container.cc index e2a963e84..bcdae3b97 100644 --- a/src/helper/net-device-container.cc +++ b/src/helper/net-device-container.cc @@ -21,6 +21,19 @@ namespace ns3 { +NetDeviceContainer::NetDeviceContainer () +{} +NetDeviceContainer::NetDeviceContainer (Ptr dev) +{ + m_devices.push_back (dev); +} +NetDeviceContainer::NetDeviceContainer (const NetDeviceContainer &a, const NetDeviceContainer &b) +{ + *this = a; + Add (b); +} + + NetDeviceContainer::Iterator NetDeviceContainer::Begin (void) const { diff --git a/src/helper/net-device-container.h b/src/helper/net-device-container.h index 477da54a6..e3357ee9d 100644 --- a/src/helper/net-device-container.h +++ b/src/helper/net-device-container.h @@ -35,6 +35,33 @@ class NetDeviceContainer public: typedef std::vector >::const_iterator Iterator; + /** + * Create an empty NetDeviceContainer. + */ + NetDeviceContainer (); + /** + * \param dev a device to add to the container + * + * Create a NetDeviceContainer with exactly one device + */ + NetDeviceContainer (Ptr dev); + /** + * \param a a device container + * \param b another device container + * + * Create a device container which is a concatenation of the two input + * NetDeviceContainers. + * + * \note A frequently seen idiom that uses these constructors involves the + * implicit conversion by constructor of Ptr. When used, two + * Ptr will be passed to this constructor instead of NetDeviceContainer&. + * C++ will notice the implicit conversion path that goes through the + * NetDeviceContainer (Ptr dev) constructor above. Using this conversion + * one may provide optionally provide arguments of Ptr to these + * constructors. + */ + NetDeviceContainer (const NetDeviceContainer &a, const NetDeviceContainer &b); + /** * \returns an iterator which points to the start of the array of pointers. */ diff --git a/src/helper/node-container.cc b/src/helper/node-container.cc index f26c9cba6..333737e9c 100644 --- a/src/helper/node-container.cc +++ b/src/helper/node-container.cc @@ -35,14 +35,14 @@ NodeContainer::NodeContainer (const NodeContainer &a, const NodeContainer &b) Add (b); } NodeContainer::NodeContainer (const NodeContainer &a, const NodeContainer &b, - const NodeContainer &c) + const NodeContainer &c) { Add (a); Add (b); Add (c); } NodeContainer::NodeContainer (const NodeContainer &a, const NodeContainer &b, - const NodeContainer &c, const NodeContainer &d) + const NodeContainer &c, const NodeContainer &d) { Add (a); Add (b); diff --git a/src/helper/ns2-mobility-helper.cc b/src/helper/ns2-mobility-helper.cc index 563287b05..8e20f1d79 100644 --- a/src/helper/ns2-mobility-helper.cc +++ b/src/helper/ns2-mobility-helper.cc @@ -75,62 +75,65 @@ Ns2MobilityHelper::LayoutObjectStore (const ObjectStore &store) const if (file.is_open()) { while (!file.eof() ) - { - std::string line; - getline (file, line); - std::string::size_type startNodeId = line.find_first_of ("("); - std::string::size_type endNodeId = line.find_first_of (")"); - if (startNodeId == std::string::npos || - endNodeId == std::string::npos) - { - continue; - } - Ptr model = GetMobilityModel (line.substr (startNodeId + 1, - endNodeId - startNodeId), - store); - if (model == 0) - { - continue; - } - if (startNodeId == 6) - { - double value = ReadDouble (line.substr (endNodeId + 9, std::string::npos)); - std::string coordinate = line.substr (endNodeId + 6, 1); + { + std::string line; + getline (file, line); + std::string::size_type startNodeId = line.find_first_of ("("); + std::string::size_type endNodeId = line.find_first_of (")"); + if (startNodeId == std::string::npos || + endNodeId == std::string::npos) + { + continue; + } + Ptr model = GetMobilityModel (line.substr (startNodeId + 1, + endNodeId - startNodeId), + store); + if (model == 0) + { + continue; + } + if (startNodeId == 6) + { + double value = ReadDouble (line.substr (endNodeId + 9, std::string::npos)); + std::string coordinate = line.substr (endNodeId + 6, 1); Vector position = model->GetPosition (); - if (coordinate == "X") - { + if (coordinate == "X") + { position.x = value; - NS_LOG_DEBUG ("X=" << value); - } - else if (coordinate == "Y") - { + NS_LOG_DEBUG ("X=" << value); + } + else if (coordinate == "Y") + { position.y = value; - NS_LOG_DEBUG ("Y=" << value); - } - else if (coordinate == "Z") - { + NS_LOG_DEBUG ("Y=" << value); + } + else if (coordinate == "Z") + { position.z = value; - NS_LOG_DEBUG ("Z=" << value); - } + NS_LOG_DEBUG ("Z=" << value); + } else { continue; } model->SetPosition (position); - } - else - { - double at = ReadDouble (line.substr (8, startNodeId - 17)); - std::string::size_type xSpeedEnd = line.find_first_of (" ", endNodeId + 10); - std::string::size_type ySpeedEnd = line.find_first_of (" ", xSpeedEnd + 1); - double xSpeed = ReadDouble (line.substr (endNodeId + 10, xSpeedEnd - endNodeId - 10)); - double ySpeed = ReadDouble (line.substr (xSpeedEnd + 1, ySpeedEnd - xSpeedEnd - 1)); - double zSpeed = ReadDouble (line.substr (ySpeedEnd + 1, std::string::npos)); - NS_LOG_DEBUG ("at=" << at << "xSpeed=" << xSpeed << ", ySpeed=" << ySpeed << ", zSpeed=" << zSpeed); - Simulator::Schedule (Seconds (at), &StaticSpeedMobilityModel::SetSpeed, model, - Vector (xSpeed, ySpeed, zSpeed)); - } - } + } + else + { + std::string::size_type atEnd = line.find_first_of (" ", 8); + std::string atStr = line.substr (8, atEnd-8); + NS_LOG_DEBUG (atStr); + double at = ReadDouble (atStr); + std::string::size_type xSpeedEnd = line.find_first_of (" ", endNodeId + 10); + std::string::size_type ySpeedEnd = line.find_first_of (" ", xSpeedEnd + 1); + double xSpeed = ReadDouble (line.substr (endNodeId + 10, xSpeedEnd - endNodeId - 10)); + double ySpeed = ReadDouble (line.substr (xSpeedEnd + 1, ySpeedEnd - xSpeedEnd - 1)); + double zSpeed = ReadDouble (line.substr (ySpeedEnd + 1, std::string::npos)); + NS_LOG_DEBUG ("at=" << at << "xSpeed=" << xSpeed << ", ySpeed=" << ySpeed << ", zSpeed=" << zSpeed); + Simulator::Schedule (Seconds (at), &StaticSpeedMobilityModel::SetVelocity, model, + Vector (xSpeed, ySpeed, zSpeed)); + } + } file.close(); } } diff --git a/src/helper/ns2-mobility-helper.h b/src/helper/ns2-mobility-helper.h index 809a51125..795f16392 100644 --- a/src/helper/ns2-mobility-helper.h +++ b/src/helper/ns2-mobility-helper.h @@ -90,14 +90,14 @@ Ns2MobilityHelper::Install (T begin, T end) const MyObjectStore (T begin, T end) : m_begin (begin), m_end (end) - {} + {} virtual Ptr Get (uint32_t i) const { T iterator = m_begin; iterator += i; if (iterator >= m_end) - { - return 0; - } + { + return 0; + } return *iterator; } private: diff --git a/src/helper/olsr-helper.cc b/src/helper/olsr-helper.cc index 656e276ca..86f85ffd3 100644 --- a/src/helper/olsr-helper.cc +++ b/src/helper/olsr-helper.cc @@ -30,14 +30,14 @@ OlsrHelper::OlsrHelper () void OlsrHelper::SetAgent (std::string tid, - std::string n0, const AttributeValue &v0, - std::string n1, const AttributeValue &v1, - std::string n2, const AttributeValue &v2, - std::string n3, const AttributeValue &v3, - std::string n4, const AttributeValue &v4, - std::string n5, const AttributeValue &v5, - std::string n6, const AttributeValue &v6, - std::string n7, const AttributeValue &v7) + std::string n0, const AttributeValue &v0, + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4, + std::string n5, const AttributeValue &v5, + std::string n6, const AttributeValue &v6, + std::string n7, const AttributeValue &v7) { m_agentFactory.SetTypeId (tid); m_agentFactory.Set (n0, v0); diff --git a/src/helper/olsr-helper.h b/src/helper/olsr-helper.h index b901ab9d8..3a37167e5 100644 --- a/src/helper/olsr-helper.h +++ b/src/helper/olsr-helper.h @@ -26,23 +26,38 @@ namespace ns3 { +/** + * \brief Helper class that adds OLSR routing to nodes. + */ class OlsrHelper { public: OlsrHelper (); + /** + * \brief Set default OLSR routing agent attributes + */ void SetAgent (std::string tid, - std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (), - std::string n1 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), - std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), - std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), - std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), - std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); + std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (), + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), + std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), + std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), + std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); + /** + * \brief Enable OLSR routing for a set of nodes + */ void Install (NodeContainer container); + /** + * \brief Enable OLSR routing for a single node + */ void Install (Ptr node); + /** + * \brief Enable OLSR routing for all nodes + */ void InstallAll (void); private: ObjectFactory m_agentFactory; diff --git a/src/helper/on-off-helper.h b/src/helper/on-off-helper.h index a36ab49a5..3b4ac6cc1 100644 --- a/src/helper/on-off-helper.h +++ b/src/helper/on-off-helper.h @@ -31,13 +31,34 @@ namespace ns3 { +/** + * \brief instanciate an ns3::OnOffApplication on a set of nodes. + */ class OnOffHelper { public: + /** + * \param protocol the name of the protocol to use to send traffic + * by the applications. This string identifies the socket + * factory type used to create sockets for the applications. + * A typical value would be ns3::UdpSocketFactory. + * \param address the address of the remote node to send traffic + * to. + */ OnOffHelper (std::string protocol, Address address); + /** + * \param name the name of the application attribute to set + * \param value the value of the application attribute to set + */ void SetAttribute (std::string name, const AttributeValue &value); + /** + * \param c the set of nodes on which an OnOffApplication will be installed. + * + * Install an ns3::OnOffApplication on each node of the input container + * configured with all the attributes set with SetAttribute. + */ ApplicationContainer Install (NodeContainer c); private: diff --git a/src/helper/point-to-point-helper.cc b/src/helper/point-to-point-helper.cc index 7f1fbcd03..ae45b7ca6 100644 --- a/src/helper/point-to-point-helper.cc +++ b/src/helper/point-to-point-helper.cc @@ -39,10 +39,10 @@ PointToPointHelper::PointToPointHelper () void PointToPointHelper::SetQueue (std::string type, - std::string n1, const AttributeValue &v1, - std::string n2, const AttributeValue &v2, - std::string n3, const AttributeValue &v3, - std::string n4, const AttributeValue &v4) + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4) { m_queueFactory.SetTypeId (type); m_queueFactory.Set (n1, v1); @@ -52,21 +52,39 @@ PointToPointHelper::SetQueue (std::string type, } void -PointToPointHelper::SetDeviceParameter (std::string n1, const AttributeValue &v1) +PointToPointHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1) { m_deviceFactory.Set (n1, v1); } void -PointToPointHelper::SetChannelParameter (std::string n1, const AttributeValue &v1) +PointToPointHelper::SetChannelAttribute (std::string n1, const AttributeValue &v1) { m_channelFactory.Set (n1, v1); } +void +PointToPointHelper::SetDeviceParameter (std::string name, const AttributeValue &value) +{ + SetDeviceAttribute (name, value); +} +void +PointToPointHelper::SetChannelParameter (std::string name, const AttributeValue &value) +{ + SetChannelAttribute (name, value); +} + void PointToPointHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid) { std::ostringstream oss; + oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/"; + Config::MatchContainer matches = Config::LookupMatches (oss.str ()); + if (matches.GetN () == 0) + { + return; + } + oss.str (""); oss << filename << "-" << nodeid << "-" << deviceid << ".pcap"; Ptr pcap = Create (); pcap->Open (oss.str ()); @@ -95,9 +113,9 @@ PointToPointHelper::EnablePcap (std::string filename, NodeContainer n) { Ptr node = *i; for (uint32_t j = 0; j < node->GetNDevices (); ++j) - { - devs.Add (node->GetDevice (j)); - } + { + devs.Add (node->GetDevice (j)); + } } EnablePcap (filename, devs); } @@ -111,7 +129,7 @@ PointToPointHelper::EnablePcapAll (std::string filename) void PointToPointHelper::EnableAscii (std::ostream &os, uint32_t nodeid, uint32_t deviceid) { - Packet::EnableMetadata (); + Packet::EnablePrinting (); std::ostringstream oss; oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/Rx"; Config::Connect (oss.str (), MakeBoundCallback (&PointToPointHelper::AsciiRxEvent, &os)); @@ -142,9 +160,9 @@ PointToPointHelper::EnableAscii (std::ostream &os, NodeContainer n) { Ptr node = *i; for (uint32_t j = 0; j < node->GetNDevices (); ++j) - { - devs.Add (node->GetDevice (j)); - } + { + devs.Add (node->GetDevice (j)); + } } EnableAscii (os, devs); } @@ -161,6 +179,7 @@ PointToPointHelper::Install (NodeContainer c) NS_ASSERT (c.GetN () == 2); return Install (c.Get (0), c.Get (1)); } + NetDeviceContainer PointToPointHelper::Install (Ptr a, Ptr b) { @@ -185,6 +204,18 @@ PointToPointHelper::Install (Ptr a, Ptr b) return container; } +void +PointToPointHelper::InstallStar (Ptr hub, NodeContainer spokes, + NetDeviceContainer& hubDevices, NetDeviceContainer& spokeDevices) +{ + for (uint32_t i = 0; i < spokes.GetN (); ++i) + { + NetDeviceContainer nd = Install (hub, spokes.Get (i)); + hubDevices.Add (nd.Get (0)); + spokeDevices.Add (nd.Get (1)); + } +} + void PointToPointHelper::EnqueueEvent (Ptr writer, Ptr packet) { diff --git a/src/helper/point-to-point-helper.h b/src/helper/point-to-point-helper.h index f945a144f..4b53cf4c1 100644 --- a/src/helper/point-to-point-helper.h +++ b/src/helper/point-to-point-helper.h @@ -23,6 +23,7 @@ #include "ns3/object-factory.h" #include "ns3/net-device-container.h" #include "ns3/node-container.h" +#include "ns3/deprecated.h" #include namespace ns3 { @@ -56,27 +57,30 @@ public: * PointToPointNetDevice created through PointToPointHelper::Install. */ void SetQueue (std::string type, - std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), - std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), - std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue ()); + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue ()); /** * \param name the name of the attribute to set * \param value the value of the attribute to set * - * Set these parameters on each ns3::PointToPointNetDevice created + * Set these attributes on each ns3::PointToPointNetDevice created * by PointToPointHelper::Install */ - void SetDeviceParameter (std::string name, const AttributeValue &value); + void SetDeviceAttribute (std::string name, const AttributeValue &value); /** * \param name the name of the attribute to set * \param value the value of the attribute to set * - * Set these parameters on each ns3::PointToPointChannel created + * Set these attribute on each ns3::PointToPointChannel created * by PointToPointHelper::Install */ - void SetChannelParameter (std::string name, const AttributeValue &value); + void SetChannelAttribute (std::string name, const AttributeValue &value); + + void SetDeviceParameter (std::string name, const AttributeValue &value) NS_DEPRECATED; + void SetChannelParameter (std::string name, const AttributeValue &value) NS_DEPRECATED; /** * \param filename filename prefix to use for pcap files. @@ -159,13 +163,14 @@ public: * \param c a set of nodes * * This method creates a ns3::PointToPointChannel with the - * attributes configured by PointToPointHelper::SetChannelParameter, + * attributes configured by PointToPointHelper::SetChannelAttribute, * then, for each node in the input container, we create a - * ns3::PointToPointNetDevice with the requested parameters, + * ns3::PointToPointNetDevice with the requested attributes, * a queue for this ns3::NetDevice, and associate the resulting * ns3::NetDevice with the ns3::Node and ns3::PointToPointChannel. */ NetDeviceContainer Install (NodeContainer c); + /** * \param a first node * \param b second node @@ -174,6 +179,34 @@ public: */ NetDeviceContainer Install (Ptr a, Ptr b); + /** + * \brief Make a star network topology. + * + * Given a pointer to a node that will become the hub of the star, and a + * NodeContainer containing pointers to the nodes that will become the + * spokes; we construct point to point net devices on the hub (corresponding + * to the spokes) and store them in the hubDevices NetDeviceContainer. We + * add a net device to each spoke node and store them in the spokeDevices + * NetDeviceContainer. A point-to-point channel is created for each spoke. + * + * The ordering of the devices in the hubDevices container is according to + * the order of the spokes container -- that is, hubDevices[0] will be the + * net device used on the hub that talks to spokes[0]. the container entry + * spokeDevices[0] will have the device that hubDevices[0] talks to -- those + * two devices are the ones that connect hub to spokes[0]. + * + * \param hub The central node of the star network + * \param spokes A NodeContainer of the nodes that will be the spoke (leaf) + * nodes + * \param hubDevices A NetDeviceContainer that will be filled with pointers + * to the point-to-point net devices created on the hub. + * \param spokeDevices A NetDeviceContainer that will be filled with pointers + * to the point-to-point net devices created on each of + * the spokes. + */ + void InstallStar (Ptr hub, NodeContainer spokes, + NetDeviceContainer& hubDevices, NetDeviceContainer& spokeDevices); + private: void EnablePcap (Ptr node, Ptr device, Ptr queue); void EnableAscii (Ptr node, Ptr device); diff --git a/src/helper/udp-echo-helper.cc b/src/helper/udp-echo-helper.cc index ef5f59777..c346cb6b2 100644 --- a/src/helper/udp-echo-helper.cc +++ b/src/helper/udp-echo-helper.cc @@ -24,15 +24,21 @@ namespace ns3 { -UdpEchoServerHelper::UdpEchoServerHelper () - : m_port (9) -{} +UdpEchoServerHelper::UdpEchoServerHelper (uint16_t port) +{ + m_factory.SetTypeId (UdpEchoServer::GetTypeId ()); + SetAttribute ("Port", UintegerValue(port)); +} void -UdpEchoServerHelper::SetPort (uint16_t port) +UdpEchoServerHelper::SetAttribute ( + std::string name, + const AttributeValue &value) { - m_port = port; + m_factory.Set (name, value); } + + ApplicationContainer UdpEchoServerHelper::Install (NodeContainer c) { @@ -40,25 +46,24 @@ UdpEchoServerHelper::Install (NodeContainer c) for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) { Ptr node = *i; - Ptr server = CreateObject ("Port", UintegerValue (m_port)); + Ptr server = m_factory.Create (); node->AddApplication (server); apps.Add (server); } return apps; } -UdpEchoClientHelper::UdpEchoClientHelper () +UdpEchoClientHelper::UdpEchoClientHelper (Ipv4Address address, uint16_t port) { m_factory.SetTypeId (UdpEchoClient::GetTypeId ()); + SetAttribute ("RemoteAddress", Ipv4AddressValue (address)); + SetAttribute ("RemotePort", UintegerValue (port)); } + void -UdpEchoClientHelper::SetRemote (Ipv4Address ip, uint16_t port) -{ - m_remoteIp = ip; - m_remotePort = port; -} -void -UdpEchoClientHelper::SetAppAttribute (std::string name, const AttributeValue &value) +UdpEchoClientHelper::SetAttribute ( + std::string name, + const AttributeValue &value) { m_factory.Set (name, value); } @@ -71,13 +76,10 @@ UdpEchoClientHelper::Install (NodeContainer c) { Ptr node = *i; Ptr client = m_factory.Create (); - client->SetRemote (m_remoteIp, m_remotePort); node->AddApplication (client); apps.Add (client); } return apps; } - - } // namespace ns3 diff --git a/src/helper/udp-echo-helper.h b/src/helper/udp-echo-helper.h index ef13c959a..4e06519a1 100644 --- a/src/helper/udp-echo-helper.h +++ b/src/helper/udp-echo-helper.h @@ -31,25 +31,25 @@ namespace ns3 { class UdpEchoServerHelper { public: - UdpEchoServerHelper (); - void SetPort (uint16_t port); + UdpEchoServerHelper (uint16_t port); + + void SetAttribute (std::string name, const AttributeValue &value); ApplicationContainer Install (NodeContainer c); -private: - uint16_t m_port; + + private: + ObjectFactory m_factory; }; class UdpEchoClientHelper { public: - UdpEchoClientHelper (); + UdpEchoClientHelper (Ipv4Address ip, uint16_t port); - void SetRemote (Ipv4Address ip, uint16_t port); - void SetAppAttribute (std::string name, const AttributeValue &value); + void SetAttribute (std::string name, const AttributeValue &value); ApplicationContainer Install (NodeContainer c); + private: ObjectFactory m_factory; - Ipv4Address m_remoteIp; - uint16_t m_remotePort; }; diff --git a/src/helper/wifi-helper.cc b/src/helper/wifi-helper.cc index 24522647f..2864870b6 100644 --- a/src/helper/wifi-helper.cc +++ b/src/helper/wifi-helper.cc @@ -41,30 +41,30 @@ NS_LOG_COMPONENT_DEFINE ("WifiHelper"); namespace ns3 { static void PcapPhyTxEvent (Ptr writer, Ptr packet, - WifiMode mode, WifiPreamble preamble, - uint8_t txLevel) + WifiMode mode, WifiPreamble preamble, + uint8_t txLevel) { writer->WritePacket (packet); } static void PcapPhyRxEvent (Ptr writer, - Ptr packet, double snr, WifiMode mode, - enum WifiPreamble preamble) + Ptr packet, double snr, WifiMode mode, + enum WifiPreamble preamble) { writer->WritePacket (packet); } static void AsciiPhyTxEvent (std::ostream *os, std::string context, - Ptr packet, - WifiMode mode, WifiPreamble preamble, - uint8_t txLevel) + Ptr packet, + WifiMode mode, WifiPreamble preamble, + uint8_t txLevel) { *os << "+ " << Simulator::Now () << " " << context << " " << *packet << std::endl; } static void AsciiPhyRxOkEvent (std::ostream *os, std::string context, - Ptr packet, double snr, WifiMode mode, - enum WifiPreamble preamble) + Ptr packet, double snr, WifiMode mode, + enum WifiPreamble preamble) { *os << "r " << Simulator::Now () << " " << context << " " << *packet << std::endl; } @@ -78,14 +78,14 @@ WifiHelper::WifiHelper () void WifiHelper::SetRemoteStationManager (std::string type, - std::string n0, const AttributeValue &v0, - std::string n1, const AttributeValue &v1, - std::string n2, const AttributeValue &v2, - std::string n3, const AttributeValue &v3, - std::string n4, const AttributeValue &v4, - std::string n5, const AttributeValue &v5, - std::string n6, const AttributeValue &v6, - std::string n7, const AttributeValue &v7) + std::string n0, const AttributeValue &v0, + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4, + std::string n5, const AttributeValue &v5, + std::string n6, const AttributeValue &v6, + std::string n7, const AttributeValue &v7) { m_stationManager = ObjectFactory (); m_stationManager.SetTypeId (type); @@ -101,14 +101,14 @@ WifiHelper::SetRemoteStationManager (std::string type, void WifiHelper::SetMac (std::string type, - std::string n0, const AttributeValue &v0, - std::string n1, const AttributeValue &v1, - std::string n2, const AttributeValue &v2, - std::string n3, const AttributeValue &v3, - std::string n4, const AttributeValue &v4, - std::string n5, const AttributeValue &v5, - std::string n6, const AttributeValue &v6, - std::string n7, const AttributeValue &v7) + std::string n0, const AttributeValue &v0, + std::string n1, const AttributeValue &v1, + std::string n2, const AttributeValue &v2, + std::string n3, const AttributeValue &v3, + std::string n4, const AttributeValue &v4, + std::string n5, const AttributeValue &v5, + std::string n6, const AttributeValue &v6, + std::string n7, const AttributeValue &v7) { m_mac = ObjectFactory (); m_mac.SetTypeId (type); @@ -132,6 +132,13 @@ void WifiHelper::EnablePcap (std::string filename, uint32_t nodeid, uint32_t deviceid) { std::ostringstream oss; + oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/"; + Config::MatchContainer matches = Config::LookupMatches (oss.str ()); + if (matches.GetN () == 0) + { + return; + } + oss.str (""); oss << filename << "-" << nodeid << "-" << deviceid << ".pcap"; Ptr pcap = Create (); pcap->Open (oss.str ()); @@ -160,9 +167,9 @@ WifiHelper::EnablePcap (std::string filename, NodeContainer n) { Ptr node = *i; for (uint32_t j = 0; j < node->GetNDevices (); ++j) - { - devs.Add (node->GetDevice (j)); - } + { + devs.Add (node->GetDevice (j)); + } } EnablePcap (filename, devs); } @@ -176,7 +183,7 @@ WifiHelper::EnablePcapAll (std::string filename) void WifiHelper::EnableAscii (std::ostream &os, uint32_t nodeid, uint32_t deviceid) { - Packet::EnableMetadata (); + Packet::EnablePrinting (); std::ostringstream oss; oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::WifiNetDevice/Phy/State/RxOk"; Config::Connect (oss.str (), MakeBoundCallback (&AsciiPhyRxOkEvent, &os)); @@ -201,9 +208,9 @@ WifiHelper::EnableAscii (std::ostream &os, NodeContainer n) { Ptr node = *i; for (uint32_t j = 0; j < node->GetNDevices (); ++j) - { - devs.Add (node->GetDevice (j)); - } + { + devs.Add (node->GetDevice (j)); + } } EnableAscii (os, devs); } diff --git a/src/helper/wifi-helper.h b/src/helper/wifi-helper.h index 9b8cae398..aae9fd698 100644 --- a/src/helper/wifi-helper.h +++ b/src/helper/wifi-helper.h @@ -35,7 +35,7 @@ class WifiChannel; * * This class can help to create a large set of similar * WifiNetDevice objects and to configure a large set of - * their parameters during creation. + * their attributes during creation. */ class WifiHelper { @@ -65,14 +65,14 @@ public: * in the requested station manager. */ void SetRemoteStationManager (std::string type, - std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (), - std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), - std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), - std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), - std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), - std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), - std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); + std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (), + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), + std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), + std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), + std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); /** * \param type the type of ns3::WifiMac to create. @@ -97,14 +97,14 @@ public: * in the requested mac. */ void SetMac (std::string type, - std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (), - std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), - std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), - std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), - std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), - std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), - std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), - std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); + std::string n0 = "", const AttributeValue &v0 = EmptyAttributeValue (), + std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (), + std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (), + std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (), + std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue (), + std::string n5 = "", const AttributeValue &v5 = EmptyAttributeValue (), + std::string n6 = "", const AttributeValue &v6 = EmptyAttributeValue (), + std::string n7 = "", const AttributeValue &v7 = EmptyAttributeValue ()); /** * \param name the name of the attribute to set diff --git a/src/helper/wscript b/src/helper/wscript index 2ebd99099..c638e84f0 100644 --- a/src/helper/wscript +++ b/src/helper/wscript @@ -20,6 +20,7 @@ def build(bld): 'packet-socket-helper.cc', 'ipv4-interface-container.cc', 'udp-echo-helper.cc', + 'bridge-helper.cc', ] headers = bld.create_obj('ns3header') @@ -42,4 +43,5 @@ def build(bld): 'packet-socket-helper.h', 'ipv4-interface-container.h', 'udp-echo-helper.h', + 'bridge-helper.h', ] diff --git a/src/internet-stack/arp-cache.cc b/src/internet-stack/arp-cache.cc index bfceaea2f..4da9c4091 100644 --- a/src/internet-stack/arp-cache.cc +++ b/src/internet-stack/arp-cache.cc @@ -22,6 +22,8 @@ #include "ns3/simulator.h" #include "ns3/uinteger.h" #include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/trace-source-accessor.h" #include "arp-cache.h" #include "arp-header.h" @@ -47,15 +49,23 @@ ArpCache::GetTypeId (void) MakeTimeAccessor (&ArpCache::m_deadTimeout), MakeTimeChecker ()) .AddAttribute ("WaitReplyTimeout", - "When this timeout expires, the matching cache entry is marked dead", + "When this timeout expires, the cache entries will be scanned and entries in WaitReply state will resend ArpRequest unless MaxRetries has been exceeded, in which case the entry is marked dead", TimeValue (Seconds (1)), MakeTimeAccessor (&ArpCache::m_waitReplyTimeout), MakeTimeChecker ()) + .AddAttribute ("MaxRetries", + "Number of retransmissions of ArpRequest before marking dead", + UintegerValue (3), + MakeUintegerAccessor (&ArpCache::m_maxRetries), + MakeUintegerChecker ()) .AddAttribute ("PendingQueueSize", "The size of the queue for packets pending an arp reply.", UintegerValue (3), MakeUintegerAccessor (&ArpCache::m_pendingQueueSize), MakeUintegerChecker ()) + .AddTraceSource ("Drop", + "Packet dropped due to ArpCache entry in WaitReply expiring.", + MakeTraceSourceAccessor (&ArpCache::m_dropTrace)) ; return tid; } @@ -79,12 +89,17 @@ ArpCache::DoDispose (void) Flush (); m_device = 0; m_interface = 0; + if (!m_waitReplyTimer.IsRunning ()) + { + Simulator::Remove (m_waitReplyTimer); + } Object::DoDispose (); } void ArpCache::SetDevice (Ptr device, Ptr interface) { + NS_LOG_FUNCTION_NOARGS (); m_device = device; m_interface = interface; } @@ -92,50 +107,126 @@ ArpCache::SetDevice (Ptr device, Ptr interface) Ptr ArpCache::GetDevice (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_device; } Ptr ArpCache::GetInterface (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_interface; } void ArpCache::SetAliveTimeout (Time aliveTimeout) { + NS_LOG_FUNCTION_NOARGS (); m_aliveTimeout = aliveTimeout; } void ArpCache::SetDeadTimeout (Time deadTimeout) { + NS_LOG_FUNCTION_NOARGS (); m_deadTimeout = deadTimeout; } void ArpCache::SetWaitReplyTimeout (Time waitReplyTimeout) { + NS_LOG_FUNCTION_NOARGS (); m_waitReplyTimeout = waitReplyTimeout; } Time ArpCache::GetAliveTimeout (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_aliveTimeout; } Time ArpCache::GetDeadTimeout (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_deadTimeout; } Time ArpCache::GetWaitReplyTimeout (void) const { + NS_LOG_FUNCTION_NOARGS (); return m_waitReplyTimeout; } +void +ArpCache::SetArpRequestCallback (Callback, + Ipv4Address> arpRequestCallback) +{ + NS_LOG_FUNCTION_NOARGS (); + m_arpRequestCallback = arpRequestCallback; +} + +void +ArpCache::StartWaitReplyTimer (void) +{ + NS_LOG_FUNCTION_NOARGS (); + if (!m_waitReplyTimer.IsRunning ()) + { + NS_LOG_LOGIC ("Starting WaitReplyTimer at " << Simulator::Now ().GetSeconds ()); + m_waitReplyTimer = Simulator::Schedule (m_waitReplyTimeout, + &ArpCache::HandleWaitReplyTimeout, this); + } +} + +void +ArpCache::HandleWaitReplyTimeout (void) +{ + NS_LOG_FUNCTION_NOARGS (); + ArpCache::Entry* entry; + bool restartWaitReplyTimer = false; + for (CacheI i = m_arpCache.begin (); i != m_arpCache.end (); i++) + { + entry = (*i).second; + if (entry != 0 && entry->IsWaitReply () && entry->IsExpired ()) + { + if (entry->GetRetries () < m_maxRetries) + { + NS_LOG_LOGIC ("node="<< m_device->GetNode ()->GetId () << + ", ArpWaitTimeout for " << entry->GetIpv4Address () << + " expired -- retransmitting arp request since retries = " << + entry->GetRetries ()); + m_arpRequestCallback (this, entry->GetIpv4Address ()); + restartWaitReplyTimer = true; + entry->IncrementRetries (); + } + else + { + NS_LOG_LOGIC ("node="<GetNode ()->GetId () << + ", wait reply for " << entry->GetIpv4Address () << + " expired -- drop since max retries exceeded: " << + entry->GetRetries ()); + entry->MarkDead (); + entry->ClearRetries (); + Ptr pending = entry->DequeuePending(); + while (pending != 0) + { + m_dropTrace (pending); + pending = entry->DequeuePending(); + } + } + } + + } + if (restartWaitReplyTimer) + { + NS_LOG_LOGIC ("Restarting WaitReplyTimer at " << Simulator::Now ().GetSeconds ()); + m_waitReplyTimer = Simulator::Schedule (m_waitReplyTimeout, + &ArpCache::HandleWaitReplyTimeout, this); + } +} + void ArpCache::Flush (void) { + NS_LOG_FUNCTION_NOARGS (); for (CacheI i = m_arpCache.begin (); i != m_arpCache.end (); i++) { delete (*i).second; @@ -146,6 +237,7 @@ ArpCache::Flush (void) ArpCache::Entry * ArpCache::Lookup (Ipv4Address to) { + NS_LOG_FUNCTION_NOARGS (); if (m_arpCache.find (to) != m_arpCache.end ()) { ArpCache::Entry *entry = m_arpCache[to]; @@ -157,32 +249,40 @@ ArpCache::Lookup (Ipv4Address to) ArpCache::Entry * ArpCache::Add (Ipv4Address to) { + NS_LOG_FUNCTION_NOARGS (); NS_ASSERT (m_arpCache.find (to) == m_arpCache.end ()); ArpCache::Entry *entry = new ArpCache::Entry (this); m_arpCache[to] = entry; + entry->SetIpv4Address (to); return entry; } ArpCache::Entry::Entry (ArpCache *arp) : m_arp (arp), - m_state (ALIVE) -{} + m_state (ALIVE), + m_retries (0) +{ + NS_LOG_FUNCTION_NOARGS (); +} bool ArpCache::Entry::IsDead (void) { + NS_LOG_FUNCTION_NOARGS (); return (m_state == DEAD)?true:false; } bool ArpCache::Entry::IsAlive (void) { + NS_LOG_FUNCTION_NOARGS (); return (m_state == ALIVE)?true:false; } bool ArpCache::Entry::IsWaitReply (void) { + NS_LOG_FUNCTION_NOARGS (); return (m_state == WAIT_REPLY)?true:false; } @@ -190,21 +290,26 @@ ArpCache::Entry::IsWaitReply (void) void ArpCache::Entry::MarkDead (void) { + NS_LOG_FUNCTION_NOARGS (); m_state = DEAD; + ClearRetries (); UpdateSeen (); } void ArpCache::Entry::MarkAlive (Address macAddress) { + NS_LOG_FUNCTION_NOARGS (); NS_ASSERT (m_state == WAIT_REPLY); m_macAddress = macAddress; m_state = ALIVE; + ClearRetries (); UpdateSeen (); } bool ArpCache::Entry::UpdateWaitReply (Ptr waiting) { + NS_LOG_FUNCTION_NOARGS (); NS_ASSERT (m_state == WAIT_REPLY); /* We are already waiting for an answer so * we dump the previously waiting packet and @@ -220,22 +325,39 @@ ArpCache::Entry::UpdateWaitReply (Ptr waiting) void ArpCache::Entry::MarkWaitReply (Ptr waiting) { + NS_LOG_FUNCTION_NOARGS (); NS_ASSERT (m_state == ALIVE || m_state == DEAD); NS_ASSERT (m_pending.empty ()); m_state = WAIT_REPLY; m_pending.push_back (waiting); UpdateSeen (); + m_arp->StartWaitReplyTimer (); } Address -ArpCache::Entry::GetMacAddress (void) +ArpCache::Entry::GetMacAddress (void) const { + NS_LOG_FUNCTION_NOARGS (); NS_ASSERT (m_state == ALIVE); return m_macAddress; } +Ipv4Address +ArpCache::Entry::GetIpv4Address (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_ipv4Address; +} +void +ArpCache::Entry::SetIpv4Address (Ipv4Address destination) +{ + NS_LOG_FUNCTION (this << destination); + m_ipv4Address = destination; +} + bool ArpCache::Entry::IsExpired (void) { + NS_LOG_FUNCTION_NOARGS (); Time timeout; switch (m_state) { case ArpCache::Entry::WAIT_REPLY: @@ -266,6 +388,7 @@ ArpCache::Entry::IsExpired (void) Ptr ArpCache::Entry::DequeuePending (void) { + NS_LOG_FUNCTION_NOARGS (); if (m_pending.empty ()) { return 0; @@ -280,8 +403,28 @@ ArpCache::Entry::DequeuePending (void) void ArpCache::Entry::UpdateSeen (void) { + NS_LOG_FUNCTION_NOARGS (); m_lastSeen = Simulator::Now (); } +uint32_t +ArpCache::Entry::GetRetries (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_retries; +} +void +ArpCache::Entry::IncrementRetries (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_retries++; + UpdateSeen (); +} +void +ArpCache::Entry::ClearRetries (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_retries = 0; +} } // namespace ns3 diff --git a/src/internet-stack/arp-cache.h b/src/internet-stack/arp-cache.h index 899bd70d9..a161b898e 100644 --- a/src/internet-stack/arp-cache.h +++ b/src/internet-stack/arp-cache.h @@ -22,6 +22,8 @@ #include #include +#include "ns3/simulator.h" +#include "ns3/callback.h" #include "ns3/packet.h" #include "ns3/nstime.h" #include "ns3/net-device.h" @@ -29,6 +31,7 @@ #include "ns3/address.h" #include "ns3/ptr.h" #include "ns3/object.h" +#include "ns3/traced-callback.h" #include "sgi-hashmap.h" namespace ns3 { @@ -37,6 +40,7 @@ class NetDevice; class Ipv4Interface; /** + * \ingroup arp * \brief An ARP cache * * A cached lookup table for translating layer 3 addresses to layer 2. @@ -72,7 +76,22 @@ public: Time GetWaitReplyTimeout (void) const; /** - * \brief Do lookup in the ARP chache against an IP address + * This callback is set when the ArpCache is set up and allows + * the cache to generate an Arp request when the WaitReply + * time expires and a retransmission must be sent + * + * \param arpRequestCallback Callback for transmitting an Arp request. + */ + void SetArpRequestCallback (Callback, + Ipv4Address> arpRequestCallback); + /** + * This method will schedule a timeout at WaitReplyTimeout interval + * in the future, unless a timer is already running for the cache, + * in which case this method does nothing. + */ + void StartWaitReplyTimer (void); + /** + * \brief Do lookup in the ARP cache against an IP address * \param destination The destination IPv4 address to lookup the MAC address * of * \return An ArpCache::Entry with info about layer 2 @@ -131,7 +150,15 @@ public: /** * \return The MacAddress of this entry */ - Address GetMacAddress (void); + Address GetMacAddress (void) const; + /** + * \return The Ipv4Address for this entry + */ + Ipv4Address GetIpv4Address (void) const; + /** + * \param destination The Ipv4Address for this entry + */ + void SetIpv4Address (Ipv4Address destination); /** * \return True if this entry has timedout; false otherwise. */ @@ -142,6 +169,20 @@ public: * packets are pending. */ Ptr DequeuePending (void); + /** + * \returns number of retries that have been sent for an ArpRequest + * in WaitReply state. + */ + uint32_t GetRetries (void) const; + /** + * \brief Increment the counter of number of retries for an entry + */ + void IncrementRetries (void); + /** + * \brief Zero the counter of number of retries for an entry + */ + void ClearRetries (void); + private: enum ArpCacheEntryState_e { ALIVE, @@ -154,7 +195,9 @@ public: ArpCacheEntryState_e m_state; Time m_lastSeen; Address m_macAddress; + Ipv4Address m_ipv4Address; std::list > m_pending; + uint32_t m_retries; }; private: @@ -168,8 +211,18 @@ private: Time m_aliveTimeout; Time m_deadTimeout; Time m_waitReplyTimeout; + EventId m_waitReplyTimer; + Callback, Ipv4Address> m_arpRequestCallback; + uint32_t m_maxRetries; + /** + * This function is an event handler for the event that the + * ArpCache wants to check whether it must retry any Arp requests. + * If there are no Arp requests pending, this event is not scheduled. + */ + void HandleWaitReplyTimeout (void); uint32_t m_pendingQueueSize; Cache m_arpCache; + TracedCallback > m_dropTrace; }; diff --git a/src/internet-stack/arp-header.h b/src/internet-stack/arp-header.h index cb6167d67..27a8eabca 100644 --- a/src/internet-stack/arp-header.h +++ b/src/internet-stack/arp-header.h @@ -28,6 +28,7 @@ namespace ns3 { /** + * \ingroup arp * \brief The packet header for an ARP packet */ class ArpHeader : public Header diff --git a/src/internet-stack/arp-ipv4-interface.h b/src/internet-stack/arp-ipv4-interface.h index 2c5300e36..733e3b8ae 100644 --- a/src/internet-stack/arp-ipv4-interface.h +++ b/src/internet-stack/arp-ipv4-interface.h @@ -30,6 +30,7 @@ class Node; class ArpCache; /** + * \ingroup arp * \brief an Ipv4 Interface which uses ARP * * If you need to use ARP on top of a specific NetDevice, you diff --git a/src/internet-stack/arp-l3-protocol.cc b/src/internet-stack/arp-l3-protocol.cc index bd27ce7c6..e99d233d0 100644 --- a/src/internet-stack/arp-l3-protocol.cc +++ b/src/internet-stack/arp-l3-protocol.cc @@ -68,6 +68,7 @@ ArpL3Protocol::~ArpL3Protocol () void ArpL3Protocol::SetNode (Ptr node) { + NS_LOG_FUNCTION (this); m_node = node; } @@ -88,11 +89,13 @@ ArpL3Protocol::DoDispose (void) Ptr ArpL3Protocol::CreateCache (Ptr device, Ptr interface) { + NS_LOG_FUNCTION (this << device << interface); Ptr ipv4 = m_node->GetObject (); Ptr cache = CreateObject (); cache->SetDevice (device, interface); NS_ASSERT (device->IsBroadcast ()); device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache)); + cache->SetArpRequestCallback (MakeCallback (&ArpL3Protocol::SendArpRequest, this)); m_cacheList.push_back (cache); return cache; } @@ -100,7 +103,7 @@ ArpL3Protocol::CreateCache (Ptr device, Ptr interface) Ptr ArpL3Protocol::FindCache (Ptr device) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (this << device); for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++) { if ((*i)->GetDevice () == device) @@ -114,9 +117,13 @@ ArpL3Protocol::FindCache (Ptr device) } void -ArpL3Protocol::Receive(Ptr device, Ptr packet, uint16_t protocol, const Address &from) +ArpL3Protocol::Receive(Ptr device, Ptr p, uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (this << device << p->GetSize () << protocol << from << to << packetType); + + Ptr packet = p->Copy (); + Ptr cache = FindCache (device); ArpHeader arp; packet->RemoveHeader (arp); @@ -192,7 +199,7 @@ ArpL3Protocol::Lookup (Ptr packet, Ipv4Address destination, Ptr cache, Address *hardwareDestination) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (this << packet << destination << device << cache); ArpCache::Entry *entry = cache->Lookup (destination); if (entry != 0) { @@ -214,16 +221,7 @@ ArpL3Protocol::Lookup (Ptr packet, Ipv4Address destination, } else if (entry->IsWaitReply ()) { - NS_LOG_LOGIC ("node="<GetId ()<< - ", wait reply for " << destination << " expired -- drop"); - entry->MarkDead (); - Ptr pending = entry->DequeuePending(); - while (pending != 0) - { - m_dropTrace (pending); - pending = entry->DequeuePending(); - } - m_dropTrace (packet); + NS_FATAL_ERROR ("Test for possibly unreachable code-- please file a bug report if this is ever hit"); } } else @@ -267,7 +265,7 @@ ArpL3Protocol::Lookup (Ptr packet, Ipv4Address destination, void ArpL3Protocol::SendArpRequest (Ptr cache, Ipv4Address to) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (this << cache << to); ArpHeader arp; NS_LOG_LOGIC ("ARP: sending request from node "<GetId ()<< " || src: " << cache->GetDevice ()->GetAddress () << @@ -286,7 +284,7 @@ ArpL3Protocol::SendArpRequest (Ptr cache, Ipv4Address to) void ArpL3Protocol::SendArpReply (Ptr cache, Ipv4Address toIp, Address toMac) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (this << cache << toIp << toMac); ArpHeader arp; NS_LOG_LOGIC ("ARP: sending reply from node "<GetId ()<< "|| src: " << cache->GetDevice ()->GetAddress () << diff --git a/src/internet-stack/arp-l3-protocol.h b/src/internet-stack/arp-l3-protocol.h index 6815cdea0..9b46d71b6 100644 --- a/src/internet-stack/arp-l3-protocol.h +++ b/src/internet-stack/arp-l3-protocol.h @@ -36,6 +36,13 @@ class Node; class Packet; /** + * \ingroup internetStack + * \defgroup arp Arp + * + * This is an overview of Arp capabilities (write me). + */ +/** + * \ingroup arp * \brief An implementation of the ARP protocol */ class ArpL3Protocol : public Object @@ -52,9 +59,10 @@ public: Ptr CreateCache (Ptr device, Ptr interface); /** - * \brief Recieve a packet + * \brief Receive a packet */ - void Receive(Ptr device, Ptr p, uint16_t protocol, const Address &from); + void Receive(Ptr device, Ptr p, uint16_t protocol, const Address &from, const Address &to, + NetDevice::PacketType packetType); /** * \brief Perform an ARP lookup * \param p diff --git a/src/internet-stack/internet-stack.cc b/src/internet-stack/internet-stack.cc index 6070daab9..83520a3c0 100644 --- a/src/internet-stack/internet-stack.cc +++ b/src/internet-stack/internet-stack.cc @@ -21,8 +21,8 @@ #include "ns3/net-device.h" #include "ns3/callback.h" #include "ns3/node.h" +#include "ns3/core-config.h" -#include "ipv4-l4-demux.h" #include "udp-l4-protocol.h" #include "tcp-l4-protocol.h" #include "ipv4-l3-protocol.h" @@ -30,42 +30,94 @@ #include "udp-socket-factory-impl.h" #include "tcp-socket-factory-impl.h" #include "ipv4-impl.h" +#ifdef NETWORK_SIMULATION_CRADLE +#include "nsc-tcp-socket-factory-impl.h" +#include "nsc-tcp-l4-protocol.h" +#endif namespace ns3 { -void -AddInternetStack (Ptr node) +static void +AddArpStack (Ptr node) { - Ptr ipv4 = CreateObject (); Ptr arp = CreateObject (); - ipv4->SetNode (node); arp->SetNode (node); - - Ptr ipv4L4Demux = CreateObject (); - Ptr udp = CreateObject (); - Ptr tcp = CreateObject (); - - ipv4L4Demux->SetNode (node); - udp->SetNode (node); - tcp->SetNode (node); - - ipv4L4Demux->Insert (udp); - ipv4L4Demux->Insert (tcp); - - Ptr udpFactory = CreateObject (); - Ptr tcpFactory = CreateObject (); - Ptr ipv4Impl = CreateObject (); - - udpFactory->SetUdp (udp); - tcpFactory->SetTcp (tcp); - ipv4Impl->SetIpv4 (ipv4); - - node->AggregateObject (ipv4); node->AggregateObject (arp); - node->AggregateObject (ipv4Impl); - node->AggregateObject (udpFactory); - node->AggregateObject (tcpFactory); - node->AggregateObject (ipv4L4Demux); } +static void +AddUdpStack(Ptr node) +{ + Ptr ipv4 = node->GetObject (); + Ptr udp = CreateObject (); + udp->SetNode (node); + ipv4->Insert (udp); + Ptr udpFactory = CreateObject (); + udpFactory->SetUdp (udp); + node->AggregateObject (udpFactory); +} + +static void +AddTcpStack(Ptr node) +{ + Ptr ipv4 = node->GetObject (); + Ptr tcp = CreateObject (); + tcp->SetNode (node); + ipv4->Insert (tcp); + Ptr tcpFactory = CreateObject (); + tcpFactory->SetTcp (tcp); + node->AggregateObject (tcpFactory); +} + +static void +AddIpv4Stack(Ptr node) +{ + Ptr ipv4 = CreateObject (); + ipv4->SetNode (node); + node->AggregateObject (ipv4); + Ptr ipv4Impl = CreateObject (); + ipv4Impl->SetIpv4 (ipv4); + node->AggregateObject (ipv4Impl); +} + +void +AddInternetStack (Ptr node) +{ + AddArpStack (node); + AddIpv4Stack (node); + AddUdpStack (node); + AddTcpStack (node); +} + +#ifdef NETWORK_SIMULATION_CRADLE +static void +AddNscStack(Ptr node, const std::string &soname) +{ + Ptr ipv4 = node->GetObject (); + Ptr tcp = CreateObject (); + tcp->SetNscLibrary(soname); + tcp->SetNode (node); + ipv4->Insert (tcp); + Ptr tcpFactory = CreateObject (); + tcpFactory->SetTcp (tcp); + node->AggregateObject (tcpFactory); +} + + +void +AddNscInternetStack (Ptr node, const std::string &soname) +{ + AddArpStack (node); + AddIpv4Stack (node); + + AddUdpStack (node); + AddNscStack (node, soname); +} +#else +void +AddNscInternetStack (Ptr node, const std::string &soname) +{ + NS_FATAL_ERROR ("NSC Not enabled on this platform."); +} +#endif }//namespace ns3 diff --git a/src/internet-stack/internet-stack.h b/src/internet-stack/internet-stack.h index 9997d862f..41ff375ad 100644 --- a/src/internet-stack/internet-stack.h +++ b/src/internet-stack/internet-stack.h @@ -27,6 +27,7 @@ namespace ns3 { class Node; void AddInternetStack (Ptr node); +void AddNscInternetStack (Ptr node, const std::string &soname); }//namespace ns3 diff --git a/src/internet-stack/ipv4-end-point-demux.cc b/src/internet-stack/ipv4-end-point-demux.cc index 3d3f779be..54ed3fbbe 100644 --- a/src/internet-stack/ipv4-end-point-demux.cc +++ b/src/internet-stack/ipv4-end-point-demux.cc @@ -168,6 +168,24 @@ Ipv4EndPointDemux::DeAllocate (Ipv4EndPoint *endPoint) } } +/* + * return list of all available Endpoints + */ +Ipv4EndPointDemux::EndPoints +Ipv4EndPointDemux::GetAllEndPoints (void) +{ + NS_LOG_FUNCTION_NOARGS (); + EndPoints ret; + + for (EndPointsI i = m_endPoints.begin (); i != m_endPoints.end (); i++) + { + Ipv4EndPoint* endP = *i; + ret.push_back(endP); + } + return ret; +} + + /* * If we have an exact match, we return it. * Otherwise, if we find a generic match, we return it. diff --git a/src/internet-stack/ipv4-end-point-demux.h b/src/internet-stack/ipv4-end-point-demux.h index 271325164..58a417264 100644 --- a/src/internet-stack/ipv4-end-point-demux.h +++ b/src/internet-stack/ipv4-end-point-demux.h @@ -30,6 +30,16 @@ namespace ns3 { class Ipv4EndPoint; +/** + * \brief Demultiplexes packets to various transport layer endpoints + * + * This class serves as a lookup table to match partial or full information + * about a four-tuple to an ns3::Ipv4EndPoint. It internally contains a list + * of endpoints, and has APIs to add and find endpoints in this demux. This + * code is shared in common to TCP and UDP protocols in ns3. This demux + * sits between ns3's layer four and the socket layer + */ + class Ipv4EndPointDemux { public: typedef std::list EndPoints; @@ -38,6 +48,7 @@ public: Ipv4EndPointDemux (); ~Ipv4EndPointDemux (); + EndPoints GetAllEndPoints (void); bool LookupPortLocal (uint16_t port); bool LookupLocal (Ipv4Address addr, uint16_t port); EndPoints Lookup (Ipv4Address daddr, diff --git a/src/internet-stack/ipv4-end-point.h b/src/internet-stack/ipv4-end-point.h index 35f0f04bc..99666f73f 100644 --- a/src/internet-stack/ipv4-end-point.h +++ b/src/internet-stack/ipv4-end-point.h @@ -30,6 +30,17 @@ namespace ns3 { class Header; class Packet; +/** + * \brief A representation of an internet endpoint/connection + * + * This class provides an internet four-tuple (source and destination ports + * and addresses). These are used in the ns3::Ipv4EndPointDemux as targets + * of lookups. The class also has a callback for notification to higher + * layers that a packet from a lower layer was received. In the ns3 + * internet-stack, these notifications are automatically registered to be + * received by the corresponding socket. + */ + class Ipv4EndPoint { public: Ipv4EndPoint (Ipv4Address address, uint16_t port); diff --git a/src/internet-stack/ipv4-interface.h b/src/internet-stack/ipv4-interface.h index 5a1e94df5..74007b09e 100644 --- a/src/internet-stack/ipv4-interface.h +++ b/src/internet-stack/ipv4-interface.h @@ -58,6 +58,7 @@ class Packet; * * Subclasses must implement the two methods: * - Ipv4Interface::SendTo + * - Ipv4Interface::GetDevice */ class Ipv4Interface : public Object { diff --git a/src/internet-stack/ipv4-l3-protocol.cc b/src/internet-stack/ipv4-l3-protocol.cc index affe814bb..d4defa7b9 100644 --- a/src/internet-stack/ipv4-l3-protocol.cc +++ b/src/internet-stack/ipv4-l3-protocol.cc @@ -38,7 +38,6 @@ #include "ipv4-interface.h" #include "ipv4-loopback-interface.h" #include "arp-ipv4-interface.h" -#include "ipv4-l4-demux.h" NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol"); @@ -91,6 +90,29 @@ Ipv4L3Protocol::~Ipv4L3Protocol () NS_LOG_FUNCTION (this); } +void +Ipv4L3Protocol::Insert(Ptr protocol) +{ + m_protocols.push_back (protocol); +} +Ptr +Ipv4L3Protocol::GetProtocol(int protocolNumber) const +{ + for (L4List_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) + { + if ((*i)->GetProtocolNumber () == protocolNumber) + { + return *i; + } + } + return 0; +} +void +Ipv4L3Protocol::Remove (Ptr protocol) +{ + m_protocols.remove (protocol); +} + void Ipv4L3Protocol::SetNode (Ptr node) { @@ -102,6 +124,13 @@ void Ipv4L3Protocol::DoDispose (void) { NS_LOG_FUNCTION (this); + for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) + { + (*i)->Dispose (); + *i = 0; + } + m_protocols.clear (); + for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); ++i) { Ptr interface = *i; @@ -449,12 +478,15 @@ Ipv4L3Protocol::FindInterfaceForDevice (Ptr device) } void -Ipv4L3Protocol::Receive( Ptr device, Ptr packet, uint16_t protocol, const Address &from) +Ipv4L3Protocol::Receive( Ptr device, Ptr p, uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType) { - NS_LOG_FUNCTION (this << &device << packet << protocol << from); + NS_LOG_FUNCTION (this << &device << p << protocol << from); NS_LOG_LOGIC ("Packet from " << from << " received on node " << m_node->GetId ()); + Ptr packet = p->Copy (); + uint32_t index = 0; Ptr ipv4Interface; for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); @@ -696,8 +728,7 @@ Ipv4L3Protocol::ForwardUp (Ptr p, Ipv4Header const&ip, { NS_LOG_FUNCTION (this << p << &ip); - Ptr demux = m_node->GetObject (); - Ptr protocol = demux->GetProtocol (ip.GetProtocol ()); + Ptr protocol = GetProtocol (ip.GetProtocol ()); protocol->Receive (p, ip.GetSource (), ip.GetDestination (), incomingInterface); } diff --git a/src/internet-stack/ipv4-l3-protocol.h b/src/internet-stack/ipv4-l3-protocol.h index 40f0be5bd..c5d59297d 100644 --- a/src/internet-stack/ipv4-l3-protocol.h +++ b/src/internet-stack/ipv4-l3-protocol.h @@ -25,6 +25,7 @@ #include #include "ns3/ipv4-address.h" #include "ns3/ptr.h" +#include "ns3/net-device.h" #include "ns3/ipv4.h" #include "ns3/traced-callback.h" #include "ns3/ipv4-header.h" @@ -39,10 +40,14 @@ class Ipv4Address; class Ipv4Header; class Ipv4Route; class Node; +class Ipv4L4Protocol; /** * \brief Implement the Ipv4 layer. + * + * This is the actual implementation of IP. It contains APIs to send and + * receive packets at the IP layer, as well as APIs for IP routing. */ class Ipv4L3Protocol : public Object { @@ -55,6 +60,35 @@ public: void SetNode (Ptr node); + /** + * \param protocol a template for the protocol to add to this L4 Demux. + * \returns the L4Protocol effectively added. + * + * Invoke Copy on the input template to get a copy of the input + * protocol which can be used on the Node on which this L4 Demux + * is running. The new L4Protocol is registered internally as + * a working L4 Protocol and returned from this method. + * The caller does not get ownership of the returned pointer. + */ + void Insert(Ptr protocol); + /** + * \param protocolNumber number of protocol to lookup + * in this L4 Demux + * \returns a matching L4 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::GetUdp for example. + */ + Ptr GetProtocol(int protocolNumber) const; + /** + * \param protocol protocol to remove from this demux. + * + * The input value to this method should be the value + * returned from the Ipv4L4Protocol::Insert method. + */ + void Remove (Ptr protocol); + /** * \param ttl default ttl to use * @@ -79,7 +113,8 @@ public: * - implement a per-NetDevice ARP cache * - send back arp replies on the right device */ - void Receive( Ptr device, Ptr p, uint16_t protocol, const Address &from); + void Receive( Ptr device, Ptr p, uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType); /** * \param packet packet to send @@ -182,12 +217,16 @@ private: void ForwardUp (Ptr p, Ipv4Header const&ip, Ptr incomingInterface); uint32_t AddIpv4Interface (Ptr interface); void SetupLoopback (void); + Ipv4L3Protocol(const Ipv4L3Protocol &); + Ipv4L3Protocol &operator = (const Ipv4L3Protocol &); typedef std::list > Ipv4InterfaceList; typedef std::list > Ipv4MulticastGroupList; typedef std::list< std::pair< int, Ptr > > Ipv4RoutingProtocolList; + typedef std::list > L4List_t; + L4List_t m_protocols; Ipv4InterfaceList m_interfaces; uint32_t m_nInterfaces; uint8_t m_defaultTtl; diff --git a/src/internet-stack/ipv4-l4-demux.cc b/src/internet-stack/ipv4-l4-demux.cc deleted file mode 100644 index a40614891..000000000 --- a/src/internet-stack/ipv4-l4-demux.cc +++ /dev/null @@ -1,97 +0,0 @@ -// -*- 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 -// - -// Define the layer 4 demultiplexer object for ns3. -// George F. Riley, Georgia Tech, Fall 2006 - -#include -#include "ns3/node.h" -#include "ns3/object-vector.h" -#include "ipv4-l4-demux.h" -#include "ipv4-l4-protocol.h" - -namespace ns3 { - -NS_OBJECT_ENSURE_REGISTERED (Ipv4L4Demux); - -TypeId -Ipv4L4Demux::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::Ipv4L4Demux") - .SetParent () - .AddAttribute ("Protocols", "The set of protocols registered with this demux.", - ObjectVectorValue (), - MakeObjectVectorAccessor (&Ipv4L4Demux::m_protocols), - MakeObjectVectorChecker ()) - ; - return tid; -} - -Ipv4L4Demux::Ipv4L4Demux () -{} - -Ipv4L4Demux::~Ipv4L4Demux() -{} - -void -Ipv4L4Demux::SetNode (Ptr node) -{ - m_node = node; -} - -void -Ipv4L4Demux::DoDispose (void) -{ - for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) - { - (*i)->Dispose (); - *i = 0; - } - m_protocols.clear (); - m_node = 0; - Object::DoDispose (); -} - -void -Ipv4L4Demux::Insert(Ptr protocol) -{ - m_protocols.push_back (protocol); -} -Ptr -Ipv4L4Demux::GetProtocol(int protocolNumber) -{ - for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) - { - if ((*i)->GetProtocolNumber () == protocolNumber) - { - return *i; - } - } - return 0; -} -void -Ipv4L4Demux::Remove (Ptr protocol) -{ - m_protocols.remove (protocol); -} - - - -}//namespace ns3 diff --git a/src/internet-stack/ipv4-l4-demux.h b/src/internet-stack/ipv4-l4-demux.h deleted file mode 100644 index fa04f8a37..000000000 --- a/src/internet-stack/ipv4-l4-demux.h +++ /dev/null @@ -1,85 +0,0 @@ -// -*- 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 -// - -// Define the layer 4 demultiplexer object for ns3. -// George F. Riley, Georgia Tech, Fall 2006 - -#ifndef IPV4_L4_DEMUX_H -#define IPV4_L4_DEMUX_H - -#include -#include "ns3/object.h" -#include "ns3/ptr.h" - -namespace ns3 { - -class Ipv4L4Protocol; -class Node; - -/** - * \brief L4 Ipv4 Demux - */ -class Ipv4L4Demux : public Object -{ -public: - static TypeId GetTypeId (void); - Ipv4L4Demux (); - virtual ~Ipv4L4Demux(); - - void SetNode (Ptr node); - - /** - * \param protocol a template for the protocol to add to this L4 Demux. - * \returns the L4Protocol effectively added. - * - * Invoke Copy on the input template to get a copy of the input - * protocol which can be used on the Node on which this L4 Demux - * is running. The new L4Protocol is registered internally as - * a working L4 Protocol and returned from this method. - * The caller does not get ownership of the returned pointer. - */ - void Insert(Ptr protocol); - /** - * \param protocolNumber number of protocol to lookup - * in this L4 Demux - * \returns a matching L4 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::GetUdp for example. - */ - Ptr GetProtocol(int protocolNumber); - /** - * \param protocol protocol to remove from this demux. - * - * The input value to this method should be the value - * returned from the Ipv4L4Protocol::Insert method. - */ - void Remove (Ptr protocol); -protected: - virtual void DoDispose (void); -private: - typedef std::list > L4List_t; - L4List_t m_protocols; - Ptr m_node; -}; - -} //namespace ns3 -#endif diff --git a/src/internet-stack/ipv4-l4-protocol.cc b/src/internet-stack/ipv4-l4-protocol.cc index 662dc37b3..83e56b0f9 100644 --- a/src/internet-stack/ipv4-l4-protocol.cc +++ b/src/internet-stack/ipv4-l4-protocol.cc @@ -37,10 +37,6 @@ Ipv4L4Protocol::GetTypeId (void) UintegerValue (0), MakeUintegerAccessor (&Ipv4L4Protocol::GetProtocolNumber), MakeUintegerChecker ()) - .AddAttribute ("Version", "The version of the protocol.", - UintegerValue (0), - MakeUintegerAccessor (&Ipv4L4Protocol::GetVersion), - MakeUintegerChecker ()) ; return tid; } diff --git a/src/internet-stack/ipv4-l4-protocol.h b/src/internet-stack/ipv4-l4-protocol.h index e7f2407ad..bb348bcd9 100644 --- a/src/internet-stack/ipv4-l4-protocol.h +++ b/src/internet-stack/ipv4-l4-protocol.h @@ -33,10 +33,10 @@ class Packet; class Ipv4Address; /** - * \brief L4 Protocol base class + * \brief L4 Protocol abstract base class * - * If you want to implement a new L4 protocol, all you have to do is - * implement a subclass of this base class and add it to an L4Demux. + * This is an abstract base class for layer four protocols which use IPv4 as + * the network layer. */ class Ipv4L4Protocol : public Object { @@ -49,10 +49,6 @@ public: * \returns the protocol number of this protocol. */ virtual int GetProtocolNumber (void) const = 0; - /** - * \returns the version number of this protocol. - */ - virtual int GetVersion (void) const = 0; /** * \param p packet to forward up diff --git a/src/internet-stack/ipv4-loopback-interface.cc b/src/internet-stack/ipv4-loopback-interface.cc index 088634f04..a87495009 100644 --- a/src/internet-stack/ipv4-loopback-interface.cc +++ b/src/internet-stack/ipv4-loopback-interface.cc @@ -73,7 +73,10 @@ Ipv4LoopbackInterface::SendTo (Ptr packet, Ipv4Address dest) m_node->GetObject (); ipv4->Receive (0, packet, Ipv4L3Protocol::PROT_NUMBER, - Mac48Address ("ff:ff:ff:ff:ff:ff")); + Mac48Address ("ff:ff:ff:ff:ff:ff"), + Mac48Address ("ff:ff:ff:ff:ff:ff"), + NetDevice::PACKET_HOST // note: linux uses PACKET_LOOPBACK here + ); } }//namespace ns3 diff --git a/src/internet-stack/nsc-sysctl.cc b/src/internet-stack/nsc-sysctl.cc new file mode 100644 index 000000000..1ce0ea548 --- /dev/null +++ b/src/internet-stack/nsc-sysctl.cc @@ -0,0 +1,154 @@ +/* -*- 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 + * + * Author: Mathieu Lacage + */ + +#include "ns3/string.h" +#include "nsc-sysctl.h" + +#include "sim_interface.h" + +namespace ns3 { + +class NscStackStringAccessor : public AttributeAccessor +{ + public: + NscStackStringAccessor (std::string name) : m_name (name) {} + + virtual bool Set (ObjectBase * object, const AttributeValue &val) const; + virtual bool Get (const ObjectBase * object, AttributeValue &val) const; + virtual bool HasGetter (void) const; + virtual bool HasSetter (void) const; + private: + std::string m_name; +}; + +bool NscStackStringAccessor::HasGetter(void) const +{ + return true; +} + +bool NscStackStringAccessor::HasSetter(void) const +{ + return true; +} + + +bool NscStackStringAccessor::Set (ObjectBase * object, const AttributeValue & val) const +{ + const StringValue *value = dynamic_cast (&val); + if (value == 0) + { + return false; + } + Ns3NscStack *obj = dynamic_cast (object); + if (obj == 0) + { + return false; + } + obj->Set (m_name, value->Get ()); + return true; +} + +bool NscStackStringAccessor::Get (const ObjectBase * object, AttributeValue &val) const +{ + StringValue *value = dynamic_cast (&val); + if (value == 0) + { + return false; + } + const Ns3NscStack *obj = dynamic_cast (object); + if (obj == 0) + { + return false; + } + value->Set (obj->Get (m_name)); + return true; +} + + +TypeId +Ns3NscStack::GetInstanceTypeId (void) const +{ + if (m_stack == 0) + { + // if we have no stack, we are a normal NscStack without any attributes. + return GetTypeId (); + } + std::string name = "ns3::Ns3NscStack<"; + name += m_stack->get_name (); + name += ">"; + TypeId tid; + if (TypeId::LookupByNameFailSafe (name, &tid)) + { + // if the relevant TypeId has already been registered, no need to do it again. + return tid; + } + else + { + // Now, we register a new TypeId for this stack which will look + // like a subclass of the Ns3NscStack. The class Ns3NscStack is effectively + // mutating into a subclass of itself from the point of view of the TypeId + // system _here_ + tid = TypeId (name.c_str ()); + tid.SetParent (); + char buf[256]; + for (int i=0; m_stack->sysctl_getnum(i, buf, sizeof(buf)) > 0 ;i++) + { + char value[256]; + if (m_stack->sysctl_get (buf, value, sizeof(value)) > 0) + { + tid.AddAttribute (buf, "Help text", + StringValue (value), + Create (buf), + MakeStringChecker ()); + } + } + return tid; + } +} + +std::string +Ns3NscStack::Get (std::string name) const +{ + char buf[512]; + if (m_stack->sysctl_get (name.c_str (), buf, sizeof(buf)) <= 0) + { // name.c_str () is not a valid sysctl name, or internal NSC error (eg. error converting value) + return NULL; + } + return std::string(buf); +} + +void +Ns3NscStack::Set (std::string name, std::string value) +{ + int ret = m_stack->sysctl_set (name.c_str (), value.c_str ()); + if (ret < 0) + { + NS_FATAL_ERROR ("setting " << name << " to " << value << "failed (retval " << ret << ")"); + } +} + +TypeId +Ns3NscStack::Ns3NscStack::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Ns3NscStack") + .SetParent () + ; + return tid; +} + +} // namespace ns3 diff --git a/src/routing/olsr/olsr.cc b/src/internet-stack/nsc-sysctl.h similarity index 51% rename from src/routing/olsr/olsr.cc rename to src/internet-stack/nsc-sysctl.h index 932629743..3c2691967 100644 --- a/src/routing/olsr/olsr.cc +++ b/src/internet-stack/nsc-sysctl.h @@ -1,7 +1,5 @@ /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2007 INESC Porto - * * 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; @@ -15,27 +13,32 @@ * 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 J. A. M. Carneiro + * Author: Mathieu Lacage */ -#include "olsr-agent.h" -#include "olsr.h" +#include -namespace ns3 { namespace olsr { +#include "ns3/attribute.h" +#include "ns3/object.h" +struct INetStack; -void -EnableAllNodes (void) +namespace ns3 { + +// This object represents the underlying nsc stack, +// which is aggregated to a Node object, and which provides access to the +// sysctls of the nsc stack through attributes. +class Ns3NscStack : public Object { - EnableNodes (NodeList::Begin (), NodeList::End ()); -} - -void -EnableNode (Ptr node) -{ - olsr::Agent::CreateDefault (node)->Start (); -} - - -}} // namespace ns3, olsr +public: + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + void SetStack (INetStack *stack) {m_stack = stack;} +private: + friend class NscStackStringAccessor; + void Set (std::string name, std::string value); + std::string Get (std::string name) const; + INetStack *m_stack; +}; +} // namespace ns3 diff --git a/src/internet-stack/nsc-tcp-l4-protocol.cc b/src/internet-stack/nsc-tcp-l4-protocol.cc new file mode 100644 index 000000000..401ef1e8f --- /dev/null +++ b/src/internet-stack/nsc-tcp-l4-protocol.cc @@ -0,0 +1,374 @@ +/* -*- 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 + * + * based on earlier integration work by Tom Henderson and Sam Jansen. + * 2008 Florian Westphal + */ + +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/nstime.h" + +#include "ns3/packet.h" +#include "ns3/node.h" + +#include "tcp-header.h" +#include "ipv4-end-point-demux.h" +#include "ipv4-end-point.h" +#include "ipv4-l3-protocol.h" +#include "nsc-tcp-l4-protocol.h" +#include "nsc-tcp-socket-impl.h" +#include "nsc-sysctl.h" + +#include "tcp-typedefs.h" + +#include +#include +#include +#include + +#include +#include + +NS_LOG_COMPONENT_DEFINE ("NscTcpL4Protocol"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (NscTcpL4Protocol); + +/* see http://www.iana.org/assignments/protocol-numbers */ +const uint8_t NscTcpL4Protocol::PROT_NUMBER = 6; + +ObjectFactory +NscTcpL4Protocol::GetDefaultRttEstimatorFactory (void) +{ + ObjectFactory factory; + factory.SetTypeId (RttMeanDeviation::GetTypeId ()); + return factory; +} + +TypeId +NscTcpL4Protocol::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::NscTcpL4Protocol") + .SetParent () + + .AddAttribute ("RttEstimatorFactory", + "How RttEstimator objects are created.", + ObjectFactoryValue (GetDefaultRttEstimatorFactory ()), + MakeObjectFactoryAccessor (&NscTcpL4Protocol::m_rttFactory), + MakeObjectFactoryChecker ()) + ; + return tid; +} + +int external_rand() +{ + return 1; // TODO +} + +NscTcpL4Protocol::NscTcpL4Protocol () + : m_endPoints (new Ipv4EndPointDemux ()), + m_nscStack (0), + m_softTimer (Timer::CANCEL_ON_DESTROY) +{ + m_dlopenHandle = NULL; + NS_LOG_LOGIC("Made a NscTcpL4Protocol "< node) +{ + m_node = node; + + if (m_nscStack) + { // stack has already been loaded... + return; + } + + NS_ASSERT(m_dlopenHandle); + + FCreateStack create = (FCreateStack)dlsym(m_dlopenHandle, "nsc_create_stack"); + NS_ASSERT(create); + m_nscStack = create(this, this, external_rand); + int hzval = m_nscStack->get_hz(); + + NS_ASSERT(hzval > 0); + + m_softTimer.SetFunction (&NscTcpL4Protocol::SoftInterrupt, this); + m_softTimer.SetDelay (MilliSeconds (1000/hzval)); + m_nscStack->init(hzval); + // This enables stack and NSC debug messages + // m_nscStack->set_diagnostic(1000); + + Ptr nscStack = Create (); + nscStack->SetStack (m_nscStack); + node->AggregateObject (nscStack); + + m_softTimer.Schedule (); + + // its likely no ns-3 interface exits at this point, so + // we dealy adding the nsc interface until the start of the simulation. + Simulator::ScheduleNow (&NscTcpL4Protocol::AddInterface, this); +} + +int +NscTcpL4Protocol::GetProtocolNumber (void) const +{ + return PROT_NUMBER; +} +int +NscTcpL4Protocol::GetVersion (void) const +{ + return 2; +} + +void +NscTcpL4Protocol::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + if (m_endPoints != 0) + { + delete m_endPoints; + m_endPoints = 0; + } + m_node = 0; + Ipv4L4Protocol::DoDispose (); +} + +Ptr +NscTcpL4Protocol::CreateSocket (void) +{ + NS_LOG_FUNCTION (this); + + Ptr rtt = m_rttFactory.Create (); + Ptr socket = CreateObject (); + socket->SetNode (m_node); + socket->SetTcp (this); + socket->SetRtt (rtt); + return socket; +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (void) +{ + NS_LOG_FUNCTION (this); + return m_endPoints->Allocate (); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (Ipv4Address address) +{ + NS_LOG_FUNCTION (this << address); + return m_endPoints->Allocate (address); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (uint16_t port) +{ + NS_LOG_FUNCTION (this << port); + return m_endPoints->Allocate (port); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (Ipv4Address address, uint16_t port) +{ + NS_LOG_FUNCTION (this << address << port); + return m_endPoints->Allocate (address, port); +} + +Ipv4EndPoint * +NscTcpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort, + Ipv4Address peerAddress, uint16_t peerPort) +{ + NS_LOG_FUNCTION (this << localAddress << localPort << peerAddress << peerPort); + return m_endPoints->Allocate (localAddress, localPort, + peerAddress, peerPort); +} + +void +NscTcpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint) +{ + NS_LOG_FUNCTION (this << endPoint); + // NSC m_endPoints->DeAllocate (endPoint); +} + +void +NscTcpL4Protocol::Receive (Ptr packet, + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface) +{ + NS_LOG_FUNCTION (this << packet << source << destination << incomingInterface); + Ipv4Header ipHeader; + uint32_t packetSize = packet->GetSize(); + + // The way things work at the moment, the IP header has been removed + // by the ns-3 IPv4 processing code. However, the NSC stack expects + // a complete IP packet, so we add the IP header back. + // Since the original header is already gone, we create a new one + // based on the information we have. + ipHeader.SetSource (source); + ipHeader.SetDestination (destination); + ipHeader.SetProtocol (PROT_NUMBER); + ipHeader.SetPayloadSize (packetSize); + ipHeader.SetTtl (1); + // all NSC stacks check the IP checksum + ipHeader.EnableChecksum (); + + packet->AddHeader(ipHeader); + packetSize = packet->GetSize(); + + const uint8_t *data = const_cast(packet->PeekData()); + + // deliver complete packet to the NSC network stack + m_nscStack->if_receive_packet(0, data, packetSize); + wakeup (); +} + +void NscTcpL4Protocol::SoftInterrupt (void) +{ + m_nscStack->timer_interrupt (); + m_nscStack->increment_ticks (); + m_softTimer.Schedule (); +} + +void NscTcpL4Protocol::send_callback(const void* data, int datalen) +{ + Ptr p; + uint32_t ipv4Saddr, ipv4Daddr; + + NS_ASSERT(datalen > 20); + + + // create packet, without IP header. The TCP header is not touched. + // Not using the IP header makes integration easier, but it destroys + // eg. ECN. + const uint8_t *rawdata = reinterpret_cast(data); + rawdata += 20; // skip IP header. IP options aren't supported at this time. + datalen -= 20; + p = Create (rawdata, datalen); + + // we need the real source/destination ipv4 addresses for Send (). + const uint32_t *ipheader = reinterpret_cast(data); + ipv4Saddr = *(ipheader+3); + ipv4Daddr = *(ipheader+4); + + Ipv4Address saddr(ntohl(ipv4Saddr)); + Ipv4Address daddr(ntohl(ipv4Daddr)); + + Ptr ipv4 = m_node->GetObject (); + NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object"); + + ipv4->Send (p, saddr, daddr, PROT_NUMBER); + m_nscStack->if_send_finish(0); +} + +void NscTcpL4Protocol::wakeup() +{ + // TODO + // this should schedule a timer to read from all tcp sockets now... this is + // an indication that data might be waiting on the socket + + Ipv4EndPointDemux::EndPoints endPoints = m_endPoints->GetAllEndPoints (); + for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin (); + endPoint != endPoints.end (); endPoint++) { + // NSC HACK: (ab)use TcpSocket::ForwardUp for signalling + (*endPoint)->ForwardUp (NULL, Ipv4Address(), 0); + } +} + +void NscTcpL4Protocol::gettime(unsigned int* sec, unsigned int* usec) +{ + // Only used by the Linux network stack, e.g. during ISN generation + // and in the kernel rng initialization routine. Also used in Linux + // printk output. + Time t = Simulator::Now (); + int64_t us = t.GetMicroSeconds (); + *sec = us / (1000*1000); + *usec = us - *sec * (1000*1000); +} + + +void NscTcpL4Protocol::AddInterface(void) +{ + Ptr ip = m_node->GetObject (); + const uint32_t nInterfaces = ip->GetNInterfaces (); + + NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node"); + + // start from 1, ignore the loopback interface (HACK) + // we really don't need the loop, but its here to illustrate + // how things _should_ be (once nsc can deal with multiple interfaces...) + for (uint32_t i = 1; i < nInterfaces; i++) + { + Ipv4Address addr = ip->GetAddress(i); + Ipv4Mask mask = ip->GetNetworkMask(i); + uint16_t mtu = ip->GetMtu (i); + + std::ostringstream addrOss, maskOss; + + addr.Print(addrOss); + mask.Print(maskOss); + + NS_LOG_LOGIC ("if_attach " << addrOss.str().c_str() << " " << maskOss.str().c_str() << " " << mtu); + + std::string addrStr = addrOss.str(); + std::string maskStr = maskOss.str(); + const char* addrCStr = addrStr.c_str(); + const char* maskCStr = maskStr.c_str(); + m_nscStack->if_attach(addrCStr, maskCStr, mtu); + + if (i == 1) + { + // We need to come up with a default gateway here. Can't guarantee this to be + // correct really... + + uint8_t addrBytes[4]; + addr.Serialize(addrBytes); + + // XXX: this is all a bit of a horrible hack + // + // Just increment the last octet, this gives a decent chance of this being + // 'enough'. + // + // All we need is another address on the same network as the interface. This + // will force the stack to output the packet out of the network interface. + addrBytes[3]++; + addr.Deserialize(addrBytes); + addrOss.str(""); + addr.Print(addrOss); + m_nscStack->add_default_gateway(addrOss.str().c_str()); + } + } +} + +}; // namespace ns3 + diff --git a/src/internet-stack/nsc-tcp-l4-protocol.h b/src/internet-stack/nsc-tcp-l4-protocol.h new file mode 100644 index 000000000..212a62755 --- /dev/null +++ b/src/internet-stack/nsc-tcp-l4-protocol.h @@ -0,0 +1,123 @@ +/* -*- 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 NSC_TCP_L4_PROTOCOL_H +#define NSC_TCP_L4_PROTOCOL_H + +#include + +#include "ns3/packet.h" +#include "ns3/ipv4-address.h" +#include "ns3/ptr.h" +#include "ns3/object-factory.h" +#include "ipv4-end-point-demux.h" +#include "ipv4-l4-protocol.h" +#include "ipv4-interface.h" + +#include "tcp-header.h" + +#include "ns3/timer.h" +#include "sim_interface.h" + +namespace ns3 { + +class Node; +class Socket; +class TcpHeader; +/** + * \ingroup nsctcp + * + * \brief Nsc wrapper glue, to interface with the Ipv4 protocol underneath. + */ +class NscTcpL4Protocol : public Ipv4L4Protocol, ISendCallback, IInterruptCallback { +public: + static const uint8_t PROT_NUMBER; + static TypeId GetTypeId (void); + /** + * \brief Constructor + */ + NscTcpL4Protocol (); + virtual ~NscTcpL4Protocol (); + + void SetNode (Ptr node); + void SetNscLibrary(const std::string &lib); + + virtual int GetProtocolNumber (void) const; + virtual int GetVersion (void) const; + + /** + * \return A smart Socket pointer to a NscTcpSocketImpl, allocated by this instance + * of the TCP protocol + */ + Ptr CreateSocket (void); + + Ipv4EndPoint *Allocate (void); + Ipv4EndPoint *Allocate (Ipv4Address address); + Ipv4EndPoint *Allocate (uint16_t port); + Ipv4EndPoint *Allocate (Ipv4Address address, uint16_t port); + Ipv4EndPoint *Allocate (Ipv4Address localAddress, uint16_t localPort, + Ipv4Address peerAddress, uint16_t peerPort); + + void DeAllocate (Ipv4EndPoint *endPoint); + + /** + * \brief Recieve a packet up the protocol stack + * \param p The Packet to dump the contents into + * \param source The source's Ipv4Address + * \param destination The destinations Ipv4Address + * \param incomingInterface The Ipv4Interface it was received on + */ + virtual void Receive (Ptr p, + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface); + + // NSC callbacks. + // NSC invokes these hooks to interact with the simulator. + // In any case, these methods are only to be called by NSC. + // + // send_callback is invoked by NSCs 'ethernet driver' to re-inject + // a packet (i.e. an octet soup consisting of an IP Header, TCP Header + // and user payload, if any), into ns-3. + virtual void send_callback(const void *data, int datalen); + // This is called by the NSC stack whenever something of interest + // has happened, e.g. when data arrives on a socket, a listen socket + // has a new connection pending, etc. + virtual void wakeup(); + // This is called by the Linux stack RNG initialization. + // Its also used by the cradle code to add a timestamp to + // printk/printf/debug output. + virtual void gettime(unsigned int *, unsigned int *); + +protected: + virtual void DoDispose (void); +private: + Ptr m_node; + Ipv4EndPointDemux *m_endPoints; + ObjectFactory m_rttFactory; +private: + void AddInterface (void); + void SoftInterrupt (void); + static ObjectFactory GetDefaultRttEstimatorFactory (void); + friend class NscTcpSocketImpl; + INetStack* m_nscStack; + void *m_dlopenHandle; + Timer m_softTimer; +}; + +}; // namespace ns3 + +#endif /* NSC_TCP_L4_PROTOCOL_H */ diff --git a/src/core/uid-manager.h b/src/internet-stack/nsc-tcp-socket-factory-impl.cc similarity index 58% rename from src/core/uid-manager.h rename to src/internet-stack/nsc-tcp-socket-factory-impl.cc index bc4b47ddc..60bcbac8d 100644 --- a/src/core/uid-manager.h +++ b/src/internet-stack/nsc-tcp-socket-factory-impl.cc @@ -1,7 +1,5 @@ /* -*- 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; @@ -14,33 +12,39 @@ * 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 */ -#ifndef UID_MANAGER_H -#define UID_MANAGER_H - -#include -#include -#include +#include "nsc-tcp-socket-factory-impl.h" +#include "nsc-tcp-l4-protocol.h" +#include "ns3/socket.h" +#include "ns3/assert.h" namespace ns3 { -/** - * zero is never a valid uid value. - */ -class UidManager +NscTcpSocketFactoryImpl::NscTcpSocketFactoryImpl () + : m_tcp (0) +{} +NscTcpSocketFactoryImpl::~NscTcpSocketFactoryImpl () { -public: - uint32_t LookupByName (std::string name); - std::string LookupByUid (uint32_t uid); - uint32_t Allocate (std::string name); -private: - typedef std::vector NameList; - NameList m_nameList; -}; + NS_ASSERT (m_tcp == 0); +} + +void +NscTcpSocketFactoryImpl::SetTcp (Ptr tcp) +{ + m_tcp = tcp; +} + +Ptr +NscTcpSocketFactoryImpl::CreateSocket (void) +{ + return m_tcp->CreateSocket (); +} + +void +NscTcpSocketFactoryImpl::DoDispose (void) +{ + m_tcp = 0; + TcpSocketFactory::DoDispose (); +} } // namespace ns3 - - -#endif /* UID_MANAGER_H */ diff --git a/src/internet-stack/nsc-tcp-socket-factory-impl.h b/src/internet-stack/nsc-tcp-socket-factory-impl.h new file mode 100644 index 000000000..f64b074e7 --- /dev/null +++ b/src/internet-stack/nsc-tcp-socket-factory-impl.h @@ -0,0 +1,62 @@ +/* -*- 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 NSC_TCP_SOCKET_FACTORY_IMPL_H +#define NSC_TCP_SOCKET_FACTORY_IMPL_H + +#include "ns3/tcp-socket-factory.h" +#include "ns3/ptr.h" + +namespace ns3 { + +class NscTcpL4Protocol; + +/** + * \ingroup internetStack + * \defgroup nsctcp NscTcp + * + * An alternate implementation of TCP for ns-3 is provided by the + * Network Simulation Cradle (NSC) project. NSC is a separately linked + * library that provides ported TCP stacks from popular operating systems + * such as Linux and FreeBSD. Glue code such as the ns-3 NSC code + * allows users to delegate Internet stack processing to the logic + * from these operating systems. This allows a user to reproduce + * with high fidelity the behavior of a real TCP stack. + */ + +/** + * \ingroup nsctcp + * + * \brief socket factory implementation for creating instances of NSC TCP + */ +class NscTcpSocketFactoryImpl : public TcpSocketFactory +{ +public: + NscTcpSocketFactoryImpl (); + virtual ~NscTcpSocketFactoryImpl (); + + void SetTcp (Ptr tcp); + + virtual Ptr CreateSocket (void); + +protected: + virtual void DoDispose (void); +private: + Ptr m_tcp; +}; + +} // namespace ns3 + +#endif /* NSC_TCP_SOCKET_FACTORY_IMPL_H */ diff --git a/src/internet-stack/nsc-tcp-socket-impl.cc b/src/internet-stack/nsc-tcp-socket-impl.cc new file mode 100644 index 000000000..cbb4d777a --- /dev/null +++ b/src/internet-stack/nsc-tcp-socket-impl.cc @@ -0,0 +1,830 @@ +/* -*- 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 + * + * based on tcp-socket-impl.cc, Author: Raj Bhattacharjea + * Author: Florian Westphal + */ + +#include "ns3/node.h" +#include "ns3/inet-socket-address.h" +#include "ns3/log.h" +#include "ns3/ipv4.h" +#include "ipv4-end-point.h" +#include "nsc-tcp-l4-protocol.h" +#include "nsc-tcp-socket-impl.h" +#include "ns3/simulation-singleton.h" +#include "tcp-typedefs.h" +#include "ns3/simulator.h" +#include "ns3/packet.h" +#include "ns3/uinteger.h" +#include "ns3/trace-source-accessor.h" + +#include + +// for ntohs(). +#include +#include + +#include "sim_interface.h" +#include "sim_errno.h" + +NS_LOG_COMPONENT_DEFINE ("NscTcpSocketImpl"); + +using namespace std; + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (NscTcpSocketImpl); + +TypeId +NscTcpSocketImpl::GetTypeId () +{ + static TypeId tid = TypeId("ns3::NscTcpSocketImpl") + .SetParent () + .AddTraceSource ("CongestionWindow", + "The TCP connection's congestion window", + MakeTraceSourceAccessor (&NscTcpSocketImpl::m_cWnd)) + ; + return tid; +} + + NscTcpSocketImpl::NscTcpSocketImpl () + : m_endPoint (0), + m_node (0), + m_tcp (0), + m_localAddress (Ipv4Address::GetZero ()), + m_localPort (0), + m_peerAddress ("0.0.0.0", 0), + m_errno (ERROR_NOTERROR), + m_shutdownSend (false), + m_shutdownRecv (false), + m_connected (false), + m_state (CLOSED), + m_closeOnEmpty (false), + m_txBufferSize (0), + m_rtt (0), + m_lastMeasuredRtt (Seconds(0.0)) +{ + NS_LOG_FUNCTION (this); +} + +NscTcpSocketImpl::NscTcpSocketImpl(const NscTcpSocketImpl& sock) + : TcpSocket(sock), //copy the base class callbacks + m_delAckMaxCount (sock.m_delAckMaxCount), + m_delAckTimeout (sock.m_delAckTimeout), + m_endPoint (0), + m_node (sock.m_node), + m_tcp (sock.m_tcp), + m_remoteAddress (sock.m_remoteAddress), + m_remotePort (sock.m_remotePort), + m_localAddress (sock.m_localAddress), + m_localPort (sock.m_localPort), + m_peerAddress (sock.m_peerAddress), + m_errno (sock.m_errno), + m_shutdownSend (sock.m_shutdownSend), + m_shutdownRecv (sock.m_shutdownRecv), + m_connected (sock.m_connected), + m_state (sock.m_state), + m_closeOnEmpty (sock.m_closeOnEmpty), + m_segmentSize (sock.m_segmentSize), + m_rxWindowSize (sock.m_rxWindowSize), + m_advertisedWindowSize (sock.m_advertisedWindowSize), + m_cWnd (sock.m_cWnd), + m_ssThresh (sock.m_ssThresh), + m_initialCWnd (sock.m_initialCWnd), + m_rtt (0), + m_lastMeasuredRtt (Seconds(0.0)), + m_cnTimeout (sock.m_cnTimeout), + m_cnCount (sock.m_cnCount), + m_rxAvailable (0), + m_nscTcpSocket (0), + m_sndBufSize (sock.m_sndBufSize) +{ + NS_LOG_FUNCTION_NOARGS (); + NS_LOG_LOGIC("Invoked the copy constructor"); + //copy the pending data if necessary + if(!sock.m_txBuffer.empty () ) + { + m_txBuffer = sock.m_txBuffer; + } + //copy the rtt if necessary + if (sock.m_rtt) + { + m_rtt = sock.m_rtt->Copy(); + } + //can't "copy" the endpoint just yes, must do this when we know the peer info + //too; this is in SYN_ACK_TX +} + +NscTcpSocketImpl::~NscTcpSocketImpl () +{ + NS_LOG_FUNCTION(this); + m_node = 0; + if (m_endPoint != 0) + { + NS_ASSERT (m_tcp != 0); + /** + * Note that this piece of code is a bit tricky: + * when DeAllocate is called, it will call into + * Ipv4EndPointDemux::Deallocate which triggers + * a delete of the associated endPoint which triggers + * in turn a call to the method ::Destroy below + * will will zero the m_endPoint field. + */ + NS_ASSERT (m_endPoint != 0); + m_tcp->DeAllocate (m_endPoint); + NS_ASSERT (m_endPoint == 0); + } + m_tcp = 0; +} + +void +NscTcpSocketImpl::SetNode (Ptr node) +{ + m_node = node; + // Initialize some variables + m_cWnd = m_initialCWnd * m_segmentSize; + m_rxWindowSize = m_advertisedWindowSize; +} + +void +NscTcpSocketImpl::SetTcp (Ptr tcp) +{ + m_nscTcpSocket = tcp->m_nscStack->new_tcp_socket(); + m_tcp = tcp; +} +void +NscTcpSocketImpl::SetRtt (Ptr rtt) +{ + m_rtt = rtt; +} + + +enum Socket::SocketErrno +NscTcpSocketImpl::GetErrno (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_errno; +} + +Ptr +NscTcpSocketImpl::GetNode (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_node; +} + +void +NscTcpSocketImpl::Destroy (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_node = 0; + m_endPoint = 0; + m_tcp = 0; +} +int +NscTcpSocketImpl::FinishBind (void) +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_endPoint == 0) + { + return -1; + } + m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr(this))); + m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr(this))); + m_localAddress = m_endPoint->GetLocalAddress (); + m_localPort = m_endPoint->GetLocalPort (); + return 0; +} + +int +NscTcpSocketImpl::Bind (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_endPoint = m_tcp->Allocate (); + return FinishBind (); +} +int +NscTcpSocketImpl::Bind (const Address &address) +{ + NS_LOG_FUNCTION (this<Allocate (); + NS_LOG_LOGIC ("TcpSocketImpl "<Allocate (port); + NS_LOG_LOGIC ("TcpSocketImpl "<Allocate (ipv4); + NS_LOG_LOGIC ("TcpSocketImpl "<Allocate (ipv4, port); + NS_LOG_LOGIC ("TcpSocketImpl "<disconnect(); + m_state = CLOSED; + ShutdownSend (); + return 0; +} + +int +NscTcpSocketImpl::Connect (const Address & address) +{ + NS_LOG_FUNCTION (this << address); + if (m_endPoint == 0) + { + if (Bind () == -1) + { + NS_ASSERT (m_endPoint == 0); + return -1; + } + NS_ASSERT (m_endPoint != 0); + } + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + m_remoteAddress = transport.GetIpv4 (); + m_remotePort = transport.GetPort (); + + std::ostringstream ss; + m_remoteAddress.Print(ss); + std::string ipstring = ss.str (); + + m_nscTcpSocket->connect(ipstring.c_str (), m_remotePort); + m_state = SYN_SENT; + return 0; +} + +int +NscTcpSocketImpl::Send (const Ptr p, uint32_t flags) +{ + NS_LOG_FUNCTION (this << p); + + NS_ASSERT (p->GetSize () > 0); + if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) + { + if (p->GetSize () > GetTxAvailable ()) + { + m_errno = ERROR_MSGSIZE; + return -1; + } + + uint32_t sent = p->GetSize (); + if (m_state == ESTABLISHED) + { + m_txBuffer.push(p); + m_txBufferSize += sent; + SendPendingData(); + } + else + { // SYN_SET -- Queue Data + m_txBuffer.push(p); + m_txBufferSize += sent; + } + return sent; + } + else + { + m_errno = ERROR_NOTCONN; + return -1; + } +} + +int +NscTcpSocketImpl::SendTo (Ptr p, uint32_t flags, const Address &address) +{ + NS_LOG_FUNCTION (this << address << p); + if (!m_connected) + { + m_errno = ERROR_NOTCONN; + return -1; + } + else + { + return Send (p, flags); //drop the address according to BSD manpages + } +} + +uint32_t +NscTcpSocketImpl::GetTxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_txBufferSize != 0) + { + NS_ASSERT (m_txBufferSize <= m_sndBufSize); + return m_sndBufSize - m_txBufferSize; + } + else + { + return m_sndBufSize; + } +} + +int +NscTcpSocketImpl::Listen (void) +{ + NS_LOG_FUNCTION (this); + m_nscTcpSocket->listen(m_localPort); + m_state = LISTEN; + return 0; +} + + +void +NscTcpSocketImpl::NSCWakeup () +{ + switch (m_state) { + case SYN_SENT: + if (!m_nscTcpSocket->is_connected()) + break; + m_state = ESTABLISHED; + Simulator::ScheduleNow(&NscTcpSocketImpl::ConnectionSucceeded, this); + // fall through to schedule read/write events + case ESTABLISHED: + if (!m_txBuffer.empty ()) + Simulator::ScheduleNow(&NscTcpSocketImpl::SendPendingData, this); + Simulator::ScheduleNow(&NscTcpSocketImpl::ReadPendingData, this); + break; + case LISTEN: + Simulator::ScheduleNow(&NscTcpSocketImpl::Accept, this); + break; + case CLOSED: break; + default: + NS_LOG_DEBUG (this << " invalid state: " << m_state); + } +} + +Ptr +NscTcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags) +{ + NS_LOG_FUNCTION_NOARGS (); + if (m_deliveryQueue.empty() ) + { + m_errno = ERROR_AGAIN; + return 0; + } + Ptr p = m_deliveryQueue.front (); + if (p->GetSize () <= maxSize) + { + m_deliveryQueue.pop (); + m_rxAvailable -= p->GetSize (); + } + else + { + m_errno = ERROR_AGAIN; + p = 0; + } + return p; +} + +Ptr +NscTcpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress) +{ + NS_LOG_FUNCTION (this << maxSize << flags); + Ptr packet = Recv (maxSize, flags); + if (packet != 0) + { + SocketAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + fromAddress = tag.GetAddress (); + } + return packet; +} + +int +NscTcpSocketImpl::GetSockName (Address &address) const +{ + NS_LOG_FUNCTION_NOARGS (); + address = InetSocketAddress(m_localAddress, m_localPort); + return 0; +} + +uint32_t +NscTcpSocketImpl::GetRxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + // We separately maintain this state to avoid walking the queue + // every time this might be called + return m_rxAvailable; +} + +void +NscTcpSocketImpl::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) +{ + NSCWakeup(); +} + +void NscTcpSocketImpl::CompleteFork(void) +{ + // The address pairs (m_localAddress, m_localPort, m_remoteAddress, m_remotePort) + // are bogus, but this isn't important at the moment, because + // address <-> Socket handling is done by NSC internally. + // We only need to add the new ns-3 socket to the list of sockets, so + // we use plain Allocate() instead of Allocate(m_localAddress, ... ) + uint8_t buf[4]; + int port; + size_t buflen = sizeof(buf); + + if (0 == m_nscTcpSocket->getpeername((void *) buf, &buflen, &port)) { + m_remotePort = ntohs(port); + m_remoteAddress = m_remoteAddress.Deserialize(buf); + m_peerAddress = InetSocketAddress(m_remoteAddress, m_remotePort); + } + + m_endPoint = m_tcp->Allocate (); + + //the cloned socket with be in listen state, so manually change state + NS_ASSERT(m_state == LISTEN); + m_state = ESTABLISHED; + + buflen = sizeof(buf); + if (0 == m_nscTcpSocket->getsockname((void *) &buf, &buflen, &port)) + m_localAddress = m_localAddress.Deserialize(buf); + + NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " accepted connection from " + << m_remoteAddress << ":" << m_remotePort + << " to " << m_localAddress << ":" << m_localPort); + //equivalent to FinishBind + m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr(this))); + m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr(this))); + + NotifyNewConnectionCreated (this, m_peerAddress); +} + +void NscTcpSocketImpl::ConnectionSucceeded() +{ // We would preferred to have scheduled an event directly to + // NotifyConnectionSucceeded, but (sigh) these are protected + // and we can get the address of it :( + + uint8_t buf[4]; + int port; + size_t buflen = sizeof(buf); + if (0 == m_nscTcpSocket->getsockname((void *) &buf, &buflen, &port)) { + m_localAddress = m_localAddress.Deserialize(buf); + m_localPort = ntohs(port); + } + + NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " connected to " + << m_remoteAddress << ":" << m_remotePort + << " from " << m_localAddress << ":" << m_localPort); + NotifyConnectionSucceeded(); +} + + +bool NscTcpSocketImpl::Accept (void) +{ + if (m_state == CLOSED) + { // Happens if application closes listening socket after Accept() was scheduled. + return false; + } + NS_ASSERT (m_state == LISTEN); + + if (!m_nscTcpSocket->is_listening()) + { + return false; + } + INetStreamSocket *newsock; + int res = m_nscTcpSocket->accept(&newsock); + if (res != 0) + { + return false; + } +// We could obtain a fromAddress using getpeername, but we've already +// finished the tcp handshake here, i.e. this is a new connection +// and not a connection request. +// if (!NotifyConnectionRequest(fromAddress)) +// return true; + + // Clone the socket + Ptr newSock = Copy (); + newSock->m_nscTcpSocket = newsock; + NS_LOG_LOGIC ("Cloned a NscTcpSocketImpl " << newSock); + + Simulator::ScheduleNow (&NscTcpSocketImpl::CompleteFork, newSock); + return true; +} + +bool NscTcpSocketImpl::ReadPendingData (void) +{ + if (m_state != ESTABLISHED) + { + return false; + } + int len, err; + uint8_t buffer[8192]; + len = sizeof(buffer); + m_errno = ERROR_NOTERROR; + err = m_nscTcpSocket->read_data(buffer, &len); + if (err == 0 && len == 0) + { + NS_LOG_LOGIC ("ReadPendingData got EOF from socket"); + m_state = CLOSED; + return false; + } + m_errno = GetNativeNs3Errno(err); + switch (m_errno) + { + case ERROR_NOTERROR: break; // some data was sent + case ERROR_AGAIN: return false; + default: + NS_LOG_WARN ("Error (" << err << ") " << + "during read_data, ns-3 errno set to" << m_errno); + m_state = CLOSED; + return false; + } + + Ptr p = Create (buffer, len); + + SocketAddressTag tag; + + tag.SetAddress (m_peerAddress); + p->AddTag (tag); + m_deliveryQueue.push (p); + m_rxAvailable += p->GetSize (); + + NotifyDataRecv (); + return true; +} + +bool NscTcpSocketImpl::SendPendingData (void) +{ + NS_LOG_FUNCTION (this); + NS_LOG_LOGIC ("ENTERING SendPendingData"); + + if (m_txBuffer.empty ()) + { + return false; + } + + int ret; + size_t size, written = 0; + + do { + NS_ASSERT (!m_txBuffer.empty ()); + Ptr &p = m_txBuffer.front (); + size = p->GetSize (); + NS_ASSERT (size > 0); + + m_errno = ERROR_NOTERROR; + ret = m_nscTcpSocket->send_data((const char *)p->PeekData (), size); + if (ret <= 0) + { + break; + } + written += ret; + + NS_ASSERT (m_txBufferSize >= (size_t)ret); + m_txBufferSize -= ret; + + if ((size_t)ret < size) + { + p->RemoveAtStart(ret); + break; + } + + m_txBuffer.pop (); + + if (m_txBuffer.empty ()) + { + if (m_closeOnEmpty) + { + m_nscTcpSocket->disconnect(); + m_state = CLOSED; + } + break; + } + } while ((size_t) ret == size); + + if (written > 0) + { + Simulator::ScheduleNow(&NscTcpSocketImpl::NotifyDataSent, this, ret); + return true; + } + return false; +} + +Ptr NscTcpSocketImpl::Copy () +{ + return CopyObject (this); +} + +void +NscTcpSocketImpl::SetSndBufSize (uint32_t size) +{ + m_sndBufSize = size; +} + +uint32_t +NscTcpSocketImpl::GetSndBufSize (void) const +{ + return m_sndBufSize; +} + +void +NscTcpSocketImpl::SetRcvBufSize (uint32_t size) +{ + m_rcvBufSize = size; +} + +uint32_t +NscTcpSocketImpl::GetRcvBufSize (void) const +{ + return m_rcvBufSize; +} + +void +NscTcpSocketImpl::SetSegSize (uint32_t size) +{ + m_segmentSize = size; +} + +uint32_t +NscTcpSocketImpl::GetSegSize (void) const +{ + return m_segmentSize; +} + +void +NscTcpSocketImpl::SetAdvWin (uint32_t window) +{ + m_advertisedWindowSize = window; +} + +uint32_t +NscTcpSocketImpl::GetAdvWin (void) const +{ + return m_advertisedWindowSize; +} + +void +NscTcpSocketImpl::SetSSThresh (uint32_t threshold) +{ + m_ssThresh = threshold; +} + +uint32_t +NscTcpSocketImpl::GetSSThresh (void) const +{ + return m_ssThresh; +} + +void +NscTcpSocketImpl::SetInitialCwnd (uint32_t cwnd) +{ + m_initialCWnd = cwnd; +} + +uint32_t +NscTcpSocketImpl::GetInitialCwnd (void) const +{ + return m_initialCWnd; +} + +void +NscTcpSocketImpl::SetConnTimeout (Time timeout) +{ + m_cnTimeout = timeout; +} + +Time +NscTcpSocketImpl::GetConnTimeout (void) const +{ + return m_cnTimeout; +} + +void +NscTcpSocketImpl::SetConnCount (uint32_t count) +{ + m_cnCount = count; +} + +uint32_t +NscTcpSocketImpl::GetConnCount (void) const +{ + return m_cnCount; +} + +void +NscTcpSocketImpl::SetDelAckTimeout (Time timeout) +{ + m_delAckTimeout = timeout; +} + +Time +NscTcpSocketImpl::GetDelAckTimeout (void) const +{ + return m_delAckTimeout; +} + +void +NscTcpSocketImpl::SetDelAckMaxCount (uint32_t count) +{ + m_delAckMaxCount = count; +} + +uint32_t +NscTcpSocketImpl::GetDelAckMaxCount (void) const +{ + return m_delAckMaxCount; +} + +enum Socket::SocketErrno +NscTcpSocketImpl::GetNativeNs3Errno(int error) const +{ + enum nsc_errno err; + + if (error >= 0) + { + return ERROR_NOTERROR; + } + err = (enum nsc_errno) error; + switch (err) + { + case NSC_EADDRINUSE: // fallthrough + case NSC_EADDRNOTAVAIL: return ERROR_AFNOSUPPORT; + case NSC_EINPROGRESS: // Altough nsc sockets are nonblocking, we pretend they're not. + case NSC_EAGAIN: return ERROR_AGAIN; + case NSC_EISCONN: // fallthrough + case NSC_EALREADY: return ERROR_ISCONN; + case NSC_ECONNREFUSED: return ERROR_NOROUTETOHOST; // XXX, better mapping? + case NSC_ECONNRESET: // for no, all of these fall through + case NSC_EHOSTDOWN: + case NSC_ENETUNREACH: + case NSC_EHOSTUNREACH: return ERROR_NOROUTETOHOST; + case NSC_EMSGSIZE: return ERROR_MSGSIZE; + case NSC_ENOTCONN: return ERROR_NOTCONN; + case NSC_ESHUTDOWN: return ERROR_SHUTDOWN; + case NSC_ETIMEDOUT: return ERROR_NOTCONN; // XXX - this mapping isn't correct + case NSC_ENOTDIR: // used by eg. sysctl(2). Shouldn't happen normally, + // but is triggered by e.g. show_config(). + case NSC_EUNKNOWN: return ERROR_INVAL; // Catches stacks that 'return -1' without real mapping + } + NS_ASSERT_MSG(0, "Unknown NSC error"); + return ERROR_INVAL; +} + +}//namespace ns3 diff --git a/src/internet-stack/nsc-tcp-socket-impl.h b/src/internet-stack/nsc-tcp-socket-impl.h new file mode 100644 index 000000000..fa142615c --- /dev/null +++ b/src/internet-stack/nsc-tcp-socket-impl.h @@ -0,0 +1,180 @@ +/* -*- 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 NSC_TCP_SOCKET_IMPL_H +#define NSC_TCP_SOCKET_IMPL_H + +#include +#include +#include + +#include "ns3/callback.h" +#include "ns3/traced-value.h" +#include "ns3/tcp-socket.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/event-id.h" +#include "tcp-typedefs.h" +#include "pending-data.h" +#include "sequence-number.h" +#include "rtt-estimator.h" + +namespace ns3 { + +class Ipv4EndPoint; +class Node; +class Packet; +class NscTcpL4Protocol; +class TcpHeader; + +/** + * \ingroup socket + * \ingroup nsctcp + * + * \brief Socket logic for the NSC TCP sockets. + * + * Most of the TCP internal + * logic is handled by the NSC tcp library itself; this class maps ns3::Socket + * calls to the NSC TCP library. + */ +class NscTcpSocketImpl : public TcpSocket +{ +public: + static TypeId GetTypeId (void); + /** + * Create an unbound tcp socket. + */ + NscTcpSocketImpl (); + NscTcpSocketImpl (const NscTcpSocketImpl& sock); + virtual ~NscTcpSocketImpl (); + + void SetNode (Ptr node); + void SetTcp (Ptr tcp); + void SetRtt (Ptr rtt); + + virtual enum SocketErrno GetErrno (void) const; + virtual Ptr GetNode (void) const; + virtual int Bind (void); + virtual int Bind (const Address &address); + virtual int Close (void); + virtual int ShutdownSend (void); + virtual int ShutdownRecv (void); + virtual int Connect(const Address &address); + virtual int Listen(void); + virtual uint32_t GetTxAvailable (void) const; + virtual int Send (Ptr p, uint32_t flags); + virtual int SendTo(Ptr p, uint32_t flags, const Address &toAddress); + virtual uint32_t GetRxAvailable (void) const; + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual Ptr RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress); + virtual int GetSockName (Address &address) const; + +private: + void NSCWakeup(void); + friend class Tcp; + // invoked by Tcp class + int FinishBind (void); + void ForwardUp (Ptr p, Ipv4Address ipv4, uint16_t port); + void Destroy (void); + //methods for state + bool SendPendingData(void); + bool ReadPendingData(void); + bool Accept(void); + void CompleteFork(void); + void ConnectionSucceeded(); + + // Manage data tx/rx + // XXX This should be virtual and overridden + Ptr Copy (); + + // attribute related + virtual void SetSndBufSize (uint32_t size); + virtual uint32_t GetSndBufSize (void) const; + virtual void SetRcvBufSize (uint32_t size); + virtual uint32_t GetRcvBufSize (void) const; + virtual void SetSegSize (uint32_t size); + virtual uint32_t GetSegSize (void) const; + virtual void SetAdvWin (uint32_t window); + virtual uint32_t GetAdvWin (void) const; + virtual void SetSSThresh (uint32_t threshold); + virtual uint32_t GetSSThresh (void) const; + virtual void SetInitialCwnd (uint32_t cwnd); + virtual uint32_t GetInitialCwnd (void) const; + virtual void SetConnTimeout (Time timeout); + virtual Time GetConnTimeout (void) const; + virtual void SetConnCount (uint32_t count); + virtual uint32_t GetConnCount (void) const; + virtual void SetDelAckTimeout (Time timeout); + virtual Time GetDelAckTimeout (void) const; + virtual void SetDelAckMaxCount (uint32_t count); + virtual uint32_t GetDelAckMaxCount (void) const; + + enum Socket::SocketErrno GetNativeNs3Errno(int err) const; + uint32_t m_delAckMaxCount; + Time m_delAckTimeout; + + Ipv4EndPoint *m_endPoint; + Ptr m_node; + Ptr m_tcp; + Ipv4Address m_remoteAddress; + uint16_t m_remotePort; + //these two are so that the socket/endpoint cloning works + Ipv4Address m_localAddress; + uint16_t m_localPort; + InetSocketAddress m_peerAddress; + enum SocketErrno m_errno; + bool m_shutdownSend; + bool m_shutdownRecv; + bool m_connected; + + //manage the state infomation + States_t m_state; + bool m_closeOnEmpty; + + //needed to queue data when in SYN_SENT state + std::queue > m_txBuffer; + uint32_t m_txBufferSize; + + // Window management + uint32_t m_segmentSize; //SegmentSize + uint32_t m_rxWindowSize; + uint32_t m_advertisedWindowSize; //Window to advertise + TracedValue m_cWnd; //Congestion window + uint32_t m_ssThresh; //Slow Start Threshold + uint32_t m_initialCWnd; //Initial cWnd value + + // Round trip time estimation + Ptr m_rtt; + Time m_lastMeasuredRtt; + + // Timer-related members + Time m_cnTimeout; + uint32_t m_cnCount; + + // Temporary queue for delivering data to application + std::queue > m_deliveryQueue; + uint32_t m_rxAvailable; + INetStreamSocket* m_nscTcpSocket; + + // Attributes + uint32_t m_sndBufSize; // buffer limit for the outgoing queue + uint32_t m_rcvBufSize; // maximum receive socket buffer size +}; + +}//namespace ns3 + +#endif /* NSC_TCP_SOCKET_IMPL_H */ diff --git a/src/internet-stack/pending-data.cc b/src/internet-stack/pending-data.cc index bbfde0d77..c97c85968 100644 --- a/src/internet-stack/pending-data.cc +++ b/src/internet-stack/pending-data.cc @@ -131,7 +131,7 @@ Ptr PendingData::CopyFromOffset (uint32_t s, uint32_t o) uint32_t s1 = std::min (s, SizeFromOffset (o)); // Insure not beyond end of data if (s1 == 0) { - return 0; // No data requested + return Create (); // No data requested } if (data.size() != 0) { // Actual data exists, make copy and return it diff --git a/src/internet-stack/pending-data.h b/src/internet-stack/pending-data.h index 7cdbe6495..4adec2f5c 100644 --- a/src/internet-stack/pending-data.h +++ b/src/internet-stack/pending-data.h @@ -32,7 +32,12 @@ namespace ns3 { class Packet; -//Doc:ClassXRef + +/** + * \ingroup tcp + * + * \brief class for managing I/O between applications and TCP + */ class PendingData { public: PendingData (); diff --git a/src/internet-stack/rtt-estimator.h b/src/internet-stack/rtt-estimator.h index 9daf4584f..6ee3ad48b 100644 --- a/src/internet-stack/rtt-estimator.h +++ b/src/internet-stack/rtt-estimator.h @@ -21,7 +21,6 @@ // Georgia Tech Network Simulator - Round Trip Time Estimation Class // George F. Riley. Georgia Tech, Spring 2002 -// Implements several variations of round trip time estimators #ifndef __rtt_estimator_h__ #define __rtt_estimator_h__ @@ -33,6 +32,11 @@ namespace ns3 { +/** + * \ingroup tcp + * + * \brief Implements several variations of round trip time estimators + */ class RttHistory { public: RttHistory (SequenceNumber s, uint32_t c, Time t); diff --git a/src/internet-stack/sequence-number.h b/src/internet-stack/sequence-number.h index bca46e7a3..23093954e 100644 --- a/src/internet-stack/sequence-number.h +++ b/src/internet-stack/sequence-number.h @@ -22,8 +22,6 @@ // Georgia Tech Network Simulator - Manage 32 bit unsigned sequence numbers // George F. Riley. Georgia Tech, Spring 2002 -// Class to manage arithmetic operations on sequence numbers (mod 2^32) - #ifndef __seq_h__ #define __seq_h__ @@ -31,6 +29,11 @@ #define MAX_SEQ ((uint32_t)0xffffffff) +/** + * \ingroup tcp + * + * \brief Class to manage arithmetic operations on sequence numbers (mod 2^32) + */ class SequenceNumber { public: SequenceNumber () : seq(0) { } diff --git a/src/internet-stack/sgi-hashmap.h b/src/internet-stack/sgi-hashmap.h index 375d25fee..642fb5f5b 100644 --- a/src/internet-stack/sgi-hashmap.h +++ b/src/internet-stack/sgi-hashmap.h @@ -20,8 +20,14 @@ namespace sgi = std; // GCC 3.0 namespace sgi = ::__gnu_cxx; // GCC 3.1 and later #endif #else // gcc 4.x and later + #if __GNUC_MINOR__ < 3 #include - namespace sgi = ::__gnu_cxx; +namespace sgi = ::__gnu_cxx; + #else +#undef __DEPRECATED + #include +namespace sgi = ::__gnu_cxx; + #endif #endif #endif #else // ... there are other compilers, right? diff --git a/src/internet-stack/sim_errno.h b/src/internet-stack/sim_errno.h new file mode 100644 index 000000000..7c7443d26 --- /dev/null +++ b/src/internet-stack/sim_errno.h @@ -0,0 +1,35 @@ +#ifndef NETWORK_SIMULATION_CRADLE_ERR_H_ +#define NETWORK_SIMULATION_CRADLE_ERR_H_ + +// list of network stack errors that may happen in a simulation, +// and can be handled by the simulator in a sane way. +// Note that NSC handles several errors internally though +// nsc_assert, BUG() and friends, because they (should) never +// happen in a simulation (e.g. ESOCKTNOSUPPORT). +// +// These values are returned by the various methods provided by nsc. +// They must always be < 0, as values >= 0 are a success indicator; +// e.g. send_data() will return the number of bytes sent or one of +// the nsc_errno numbers below, accept() will return 0 on success or +// one of the nsc_errno numbers below, etc. +enum nsc_errno { + NSC_EUNKNOWN = -1, + NSC_EADDRINUSE = -10, + NSC_EADDRNOTAVAIL = -11, + NSC_EAGAIN = -12, + NSC_EALREADY = -25, + NSC_ECONNREFUSED = -32, + NSC_ECONNRESET = -33, + NSC_EHOSTDOWN = -50, + NSC_EHOSTUNREACH = -51, + NSC_EINPROGRESS = -60, + NSC_EISCONN = -61, + NSC_EMSGSIZE = -70, + NSC_ENETUNREACH = -82, + NSC_ENOTCONN = -86, + NSC_ENOTDIR = -87, // used by sysctl(2) + NSC_ESHUTDOWN = -130, + NSC_ETIMEDOUT = -140, +}; + +#endif diff --git a/src/internet-stack/sim_interface.h b/src/internet-stack/sim_interface.h new file mode 100644 index 000000000..4ba15c44d --- /dev/null +++ b/src/internet-stack/sim_interface.h @@ -0,0 +1,211 @@ +#ifndef __SIM_INTERFACE_H__ +#define __SIM_INTERFACE_H__ +/* + Network Simulation Cradle + Copyright (C) 2003-2005 Sam Jansen + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + 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 + +*/ + +#define NSC_VERSION 0x000400 + +struct INetStack +{ + virtual ~INetStack() {} + + virtual void init(int hz) = 0; + + virtual void if_receive_packet(int if_id, const void *data, int datalen) = 0; + + virtual void if_send_packet(const void *data, int datalen) = 0; + virtual void if_send_finish(int if_id) = 0; + + virtual void if_attach(const char *addr, const char *mask, int mtu) = 0; + virtual void add_default_gateway(const char *addr) = 0; + + /** Purely for debugging/diagnostic purposes. This returns the internal id + * of the stack instance. + */ + virtual int get_id() = 0; + + /** Should return a short one-word name of the stack. Eg. Linux 2.4.x -> + * linux24, FreeBSD 5.x -> freebsd5. This can be used to identify output + * from a stack, for example a packet trace file. */ + virtual const char *get_name() = 0; + + /** This is used so the simulator can call the stack timer_interrupt function + * the correct amount of times per second. For example, lwip has a hz of 10, + * which it returns here to say that it's timer_interrupt should be called + * 10 times a second. FreeBSD uses 100, as does Linux 2.4, while Linux 2.6 + * uses 1000. (This is often configurable in the kernel in question, also.) + */ + virtual int get_hz() = 0; + + virtual void timer_interrupt() = 0; + virtual void increment_ticks() = 0; + + virtual void buffer_size(int size) = 0; + + virtual struct INetDatagramSocket *new_udp_socket() { return NULL; } + virtual struct INetStreamSocket *new_tcp_socket() { return NULL; } + virtual struct INetStreamSocket *new_sctp_socket() { return NULL; } + + // The following I've made optional to implement for now. Eases + // integration of new features. + virtual int sysctl(const char *sysctl_name, void *oldval, size_t *oldlenp, + void *newval, size_t newlen) + { + return -1; + } + + // alternate, simpler interface. the stack cradle code is expected + // to convert the string-value to something that the stack can handle. + // The idea here is that this is a front-end to the sysctl(2) call, + // much like the sysctl(8) program. + virtual int sysctl_set(const char *name, const char *value) + { + return -1; + } + + // same as above, cradle code is expected to convert the sysctl value + // into a string. + // returns length of the string in value, i.e. retval > len: 'output truncated'. + virtual int sysctl_get(const char *name, char *value, size_t len) + { + return -1; + } + + // this tells the cradle code to put the name of sysctl number 'idx' + // into name[]. + // The idea is that this can be used to get a list of all available sysctls: + // char buf[256] + // for (i=0; sysctl_getnum(i, buf, sizeof(buf)) > 0 ;i++) + // puts(buf); + // returns -1 if idx is out of range and the length of the sysctl name otherwise. + virtual int sysctl_getnum(size_t idx, char *name, size_t len) + { + return -1; + } + + virtual void show_config() + { + ; + } + + /* Optional functions used to get and set variables for this stack */ + virtual bool get_var(const char *var, char *result, int result_len) + { + return false; + } + + virtual bool set_var(const char *var, const char *val) + { + return false; + } + + /** The level of debugging or diagnostic information to print out. This + * normally means kernel messages printed out during initialisation but + * may also include extra debugging messages that are part of NSC. */ + virtual void set_diagnostic(int level) {} + + /** Simple interface to support sending any textual command to a stack + * + * @returns 0 on success + */ + virtual int cmd(const char *) + { + return 1; + } +}; + +struct INetStreamSocket +{ + virtual ~INetStreamSocket() {} + + virtual void connect(const char *, int) = 0; + virtual void disconnect() = 0; + virtual void listen(int) = 0; + virtual int accept(INetStreamSocket **) = 0; + virtual int send_data(const void *data, int datalen) = 0; + virtual int read_data(void *buf, int *buflen) = 0; + /* We need to pass the option name in as a string here. The reason for + * this is that different operating systems you compile on will have + * different numbers defined for the constants SO_SNDBUF and so on. */ + virtual int setsockopt(char *optname, void *val, size_t valsize) = 0; + virtual void print_state(FILE *) = 0; + virtual bool is_connected() = 0; + virtual bool is_listening() = 0; + + /* + * addrspace points to a byte buffer of *addrs_len bytes. + * It is filled with a (network order) byte representation of the ip address, + * addrs_len is updated to reflect the length (i.e. 4 or eventually 16 for ipv6). + * *port is updated with the TCP/SCTP etc. port number. + * + * The reason that this doesn't use a *struct sockaddr is that the BSDs + * have an sa_len member in there, Linux does not, so the struct layout is + * different depending on the actual NSC stack and the real host operating + * system. + */ + virtual int getpeername(void *addrspace, size_t *addrs_len, int *port) { + return -1; + } + virtual int getsockname(void *addrspace, size_t *addrs_len, int *port) { + return -1; + } + /* Optional functions used to get and set variables for this TCP + * connection. */ + virtual bool get_var(const char *var, char *result, int result_len) + { + return false; + } + + virtual bool set_var(const char *var, const char *val) + { + return false; + } +}; + +struct INetDatagramSocket +{ + virtual ~INetDatagramSocket() {} + + virtual void set_destination(const char *, int) = 0; + virtual void send_data(const void *data, int datalen) = 0; +}; +struct ISendCallback +{ + virtual ~ISendCallback() {} + + virtual void send_callback(const void *data, int datalen) = 0; +}; + +struct IInterruptCallback +{ + virtual ~IInterruptCallback() {} + + virtual void wakeup() = 0; + virtual void gettime(unsigned int *, unsigned int *) = 0; +}; + +typedef int (*FRandom)(); +typedef INetStack *(*FCreateStack)(ISendCallback *, IInterruptCallback *, + FRandom); + +#define CREATE_STACK_FUNC(a,b,c) extern "C" INetStack *nsc_create_stack(\ + ISendCallback *a, IInterruptCallback *b, FRandom c) + +#endif diff --git a/src/internet-stack/tcp-header.cc b/src/internet-stack/tcp-header.cc index c0f476220..93c2428ca 100644 --- a/src/internet-stack/tcp-header.cc +++ b/src/internet-stack/tcp-header.cc @@ -23,13 +23,12 @@ #include "tcp-socket-impl.h" #include "tcp-header.h" #include "ns3/buffer.h" +#include "ns3/address-utils.h" namespace ns3 { NS_OBJECT_ENSURE_REGISTERED (TcpHeader); -bool TcpHeader::m_calcChecksum = false; - TcpHeader::TcpHeader () : m_sourcePort (0), m_destinationPort (0), @@ -38,8 +37,9 @@ TcpHeader::TcpHeader () m_length (5), m_flags (0), m_windowSize (0xffff), - m_checksum (0), - m_urgentPointer (0) + m_urgentPointer (0), + m_calcChecksum(false), + m_goodChecksum(true) {} TcpHeader::~TcpHeader () @@ -79,10 +79,6 @@ void TcpHeader::SetWindowSize (uint16_t windowSize) { m_windowSize = windowSize; } -void TcpHeader::SetChecksum (uint16_t checksum) -{ - m_checksum = checksum; -} void TcpHeader::SetUrgentPointer (uint16_t urgentPointer) { m_urgentPointer = urgentPointer; @@ -116,10 +112,6 @@ uint16_t TcpHeader::GetWindowSize () const { return m_windowSize; } -uint16_t TcpHeader::GetChecksum () const -{ - return m_checksum; -} uint16_t TcpHeader::GetUrgentPointer () const { return m_urgentPointer; @@ -127,11 +119,37 @@ uint16_t TcpHeader::GetUrgentPointer () const void TcpHeader::InitializeChecksum (Ipv4Address source, - Ipv4Address destination, - uint8_t protocol) + Ipv4Address destination, + uint8_t protocol) { - m_checksum = 0; -//XXX requires peeking into IP to get length of the TCP segment + m_source = source; + m_destination = destination; + m_protocol = protocol; +} + +uint16_t +TcpHeader::CalculateHeaderChecksum (uint16_t size) const +{ + Buffer buf = Buffer (12); + buf.AddAtStart (12); + Buffer::Iterator it = buf.Begin (); + + WriteTo (it, m_source); + WriteTo (it, m_destination); + it.WriteU8 (0); /* protocol */ + it.WriteU8 (m_protocol); /* protocol */ + it.WriteU8 (size >> 8); /* length */ + it.WriteU8 (size & 0xff); /* length */ + + it = buf.Begin (); + /* we don't CompleteChecksum ( ~ ) now */ + return ~(it.CalculateIpChecksum (12)); +} + +bool +TcpHeader::IsChecksumOk (void) const +{ + return m_goodChecksum; } TypeId @@ -188,28 +206,49 @@ uint32_t TcpHeader::GetSerializedSize (void) const } void TcpHeader::Serialize (Buffer::Iterator start) const { - start.WriteHtonU16 (m_sourcePort); - start.WriteHtonU16 (m_destinationPort); - start.WriteHtonU32 (m_sequenceNumber); - start.WriteHtonU32 (m_ackNumber); - start.WriteHtonU16 (m_length << 12 | m_flags); //reserved bits are all zero - start.WriteHtonU16 (m_windowSize); - //XXX calculate checksum here - start.WriteHtonU16 (m_checksum); - start.WriteHtonU16 (m_urgentPointer); + Buffer::Iterator i = start; + i.WriteHtonU16 (m_sourcePort); + i.WriteHtonU16 (m_destinationPort); + i.WriteHtonU32 (m_sequenceNumber); + i.WriteHtonU32 (m_ackNumber); + i.WriteHtonU16 (m_length << 12 | m_flags); //reserved bits are all zero + i.WriteHtonU16 (m_windowSize); + i.WriteHtonU16 (0); + i.WriteHtonU16 (m_urgentPointer); + + if(m_calcChecksum) + { + uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ()); + i = start; + uint16_t checksum = i.CalculateIpChecksum(start.GetSize (), headerChecksum); + + i = start; + i.Next(16); + i.WriteU16(checksum); + } } uint32_t TcpHeader::Deserialize (Buffer::Iterator start) { - m_sourcePort = start.ReadNtohU16 (); - m_destinationPort = start.ReadNtohU16 (); - m_sequenceNumber = start.ReadNtohU32 (); - m_ackNumber = start.ReadNtohU32 (); - uint16_t field = start.ReadNtohU16 (); + Buffer::Iterator i = start; + m_sourcePort = i.ReadNtohU16 (); + m_destinationPort = i.ReadNtohU16 (); + m_sequenceNumber = i.ReadNtohU32 (); + m_ackNumber = i.ReadNtohU32 (); + uint16_t field = i.ReadNtohU16 (); m_flags = field & 0x3F; m_length = field>>12; - m_windowSize = start.ReadNtohU16 (); - m_checksum = start.ReadNtohU16 (); - m_urgentPointer = start.ReadNtohU16 (); + m_windowSize = i.ReadNtohU16 (); + i.Next (2); + m_urgentPointer = i.ReadNtohU16 (); + + if(m_calcChecksum) + { + uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ()); + i = start; + uint16_t checksum = i.CalculateIpChecksum(start.GetSize (), headerChecksum); + m_goodChecksum = (checksum == 0); + } + return GetSerializedSize (); } diff --git a/src/internet-stack/tcp-header.h b/src/internet-stack/tcp-header.h index e676287f6..e88c1a17e 100644 --- a/src/internet-stack/tcp-header.h +++ b/src/internet-stack/tcp-header.h @@ -30,6 +30,15 @@ namespace ns3 { +/** + * \ingroup tcp + * \brief Header for the Transmission Control Protocol + * + * This class has fields corresponding to those in a network TCP header + * (port numbers, sequence and acknowledgement numbers, flags, etc) as well + * as methods for serialization to and deserialization from a byte buffer. + */ + class TcpHeader : public Header { public: @@ -39,7 +48,7 @@ public: /** * \brief Enable checksum calculation for TCP (XXX currently has no effect) */ - static void EnableChecksums (void); + void EnableChecksums (void); //Setters /** * \param port The source port for this TcpHeader @@ -69,10 +78,6 @@ public: * \param windowSize the window size for this TcpHeader */ void SetWindowSize (uint16_t windowSize); - /** - * \param checksum the checksum for this TcpHeader - */ - void SetChecksum (uint16_t checksum); /** * \param urgentPointer the urgent pointer for this TcpHeader */ @@ -108,10 +113,6 @@ public: * \return the window size for this TcpHeader */ uint16_t GetWindowSize () const; - /** - * \return the checksum for this TcpHeader - */ - uint16_t GetChecksum () const; /** * \return the urgent pointer for this TcpHeader */ @@ -142,7 +143,14 @@ public: virtual void Serialize (Buffer::Iterator start) const; virtual uint32_t Deserialize (Buffer::Iterator start); + /** + * \brief Is the TCP checksum correct ? + * \returns true if the checksum is correct, false otherwise. + */ + bool IsChecksumOk (void) const; + private: + uint16_t CalculateHeaderChecksum (uint16_t size) const; uint16_t m_sourcePort; uint16_t m_destinationPort; uint32_t m_sequenceNumber; @@ -150,10 +158,15 @@ private: uint8_t m_length; // really a uint4_t uint8_t m_flags; // really a uint6_t uint16_t m_windowSize; - uint16_t m_checksum; uint16_t m_urgentPointer; - static bool m_calcChecksum; + Ipv4Address m_source; + Ipv4Address m_destination; + uint8_t m_protocol; + + uint16_t m_initialChecksum; + bool m_calcChecksum; + bool m_goodChecksum; }; }; // namespace ns3 diff --git a/src/internet-stack/tcp-l4-protocol.cc b/src/internet-stack/tcp-l4-protocol.cc index 2898b09f4..9b0d56a1f 100644 --- a/src/internet-stack/tcp-l4-protocol.cc +++ b/src/internet-stack/tcp-l4-protocol.cc @@ -21,6 +21,7 @@ #include "ns3/assert.h" #include "ns3/log.h" #include "ns3/nstime.h" +#include "ns3/boolean.h" #include "ns3/packet.h" #include "ns3/node.h" @@ -328,6 +329,11 @@ TcpL4Protocol::GetTypeId (void) ObjectFactoryValue (GetDefaultRttEstimatorFactory ()), MakeObjectFactoryAccessor (&TcpL4Protocol::m_rttFactory), MakeObjectFactoryChecker ()) + .AddAttribute ("CalcChecksum", "If true, we calculate the checksum of outgoing packets" + " and verify the checksum of incoming packets.", + BooleanValue (false), + MakeBooleanAccessor (&TcpL4Protocol::m_calcChecksum), + MakeBooleanChecker ()) ; return tid; } @@ -355,11 +361,6 @@ TcpL4Protocol::GetProtocolNumber (void) const { return PROT_NUMBER; } -int -TcpL4Protocol::GetVersion (void) const -{ - return 2; -} void TcpL4Protocol::DoDispose (void) @@ -439,14 +440,26 @@ TcpL4Protocol::Receive (Ptr packet, NS_LOG_FUNCTION (this << packet << source << destination << incomingInterface); TcpHeader tcpHeader; - //these two do a peek, so that the packet can be forwarded up - packet->RemoveHeader (tcpHeader); + if(m_calcChecksum) + { + tcpHeader.EnableChecksums(); + tcpHeader.InitializeChecksum (source, destination, PROT_NUMBER); + } + + packet->PeekHeader (tcpHeader); + NS_LOG_LOGIC("TcpL4Protocol " << this << " receiving seq " << tcpHeader.GetSequenceNumber() << " ack " << tcpHeader.GetAckNumber() << " flags "<< std::hex << (int)tcpHeader.GetFlags() << std::dec << " data size " << packet->GetSize()); - packet->AddHeader (tcpHeader); + + if(!tcpHeader.IsChecksumOk ()) + { + NS_LOG_INFO("Bad checksum, dropping packet!"); + return; + } + NS_LOG_LOGIC ("TcpL4Protocol "<Lookup (destination, tcpHeader.GetDestinationPort (), @@ -478,6 +491,10 @@ TcpL4Protocol::Send (Ptr packet, TcpHeader tcpHeader; tcpHeader.SetDestinationPort (dport); tcpHeader.SetSourcePort (sport); + if(m_calcChecksum) + { + tcpHeader.EnableChecksums(); + } tcpHeader.InitializeChecksum (saddr, daddr, PROT_NUMBER); @@ -507,8 +524,12 @@ TcpL4Protocol::SendPacket (Ptr packet, TcpHeader outgoingHeader, // XXX outgoingHeader cannot be logged outgoingHeader.SetLength (5); //header length in units of 32bit words - outgoingHeader.SetChecksum (0); //XXX - outgoingHeader.SetUrgentPointer (0); //XXX + /* outgoingHeader.SetUrgentPointer (0); //XXX */ + if(m_calcChecksum) + { + outgoingHeader.EnableChecksums(); + } + outgoingHeader.InitializeChecksum(saddr, daddr, PROT_NUMBER); packet->AddHeader (outgoingHeader); diff --git a/src/internet-stack/tcp-l4-protocol.h b/src/internet-stack/tcp-l4-protocol.h index 4555b004e..b567aaf6a 100644 --- a/src/internet-stack/tcp-l4-protocol.h +++ b/src/internet-stack/tcp-l4-protocol.h @@ -39,9 +39,17 @@ namespace ns3 { class Node; class Socket; class TcpHeader; + /** - * \brief Implementation of the TCP protocol - */ + * \ingroup tcp + * \brief A layer between the sockets interface and IP + * + * This class allocates "endpoint" objects (ns3::Ipv4EndPoint) for TCP, + * and SHOULD checksum packets its receives from the socket layer going down + * the stack , but currently checksumming is disabled. It also recieves + * packets from IP, and forwards them up to the endpoints. +*/ + class TcpL4Protocol : public Ipv4L4Protocol { public: static TypeId GetTypeId (void); @@ -55,7 +63,6 @@ public: void SetNode (Ptr node); virtual int GetProtocolNumber (void) const; - virtual int GetVersion (void) const; /** * \return A smart Socket pointer to a TcpSocketImpl, allocated by this instance @@ -110,6 +117,9 @@ private: void SendPacket (Ptr, TcpHeader, Ipv4Address, Ipv4Address); static ObjectFactory GetDefaultRttEstimatorFactory (void); + + bool m_goodChecksum; + bool m_calcChecksum; }; }; // namespace ns3 diff --git a/src/internet-stack/tcp-socket-factory-impl.h b/src/internet-stack/tcp-socket-factory-impl.h index 673010f9f..b459e4ac8 100644 --- a/src/internet-stack/tcp-socket-factory-impl.h +++ b/src/internet-stack/tcp-socket-factory-impl.h @@ -28,18 +28,23 @@ namespace ns3 { class TcpL4Protocol; /** - * \ingroup internetNode - * \defgroup Tcp Tcp - */ -/** - * \ingroup Tcp - * \section Tcp Overview + * \ingroup internetStack + * \defgroup tcp Tcp * - * The TCP code in ns3::InternetNode is ported from the + * The TCP code in ns3's internet stack is ported from the * * Georgia Tech Network Simulator (GTNetS). - * + * * Most of the logic is in class ns3::TcpSocketImpl. + * This class serves to create sockets of the TcpSocketImpl + * type. That is, it creates sockets which use the GTNetS Tahoe code. + */ + +/** + * \ingroup tcp + * + * \brief socket factory implementation for native ns-3 TCP + * */ class TcpSocketFactoryImpl : public TcpSocketFactory { diff --git a/src/internet-stack/tcp-socket-impl.cc b/src/internet-stack/tcp-socket-impl.cc index 959b793c5..6df006671 100644 --- a/src/internet-stack/tcp-socket-impl.cc +++ b/src/internet-stack/tcp-socket-impl.cc @@ -26,7 +26,6 @@ #include "tcp-socket-impl.h" #include "tcp-l4-protocol.h" #include "ipv4-end-point.h" -#include "ipv4-l4-demux.h" #include "ns3/simulation-singleton.h" #include "tcp-typedefs.h" #include "ns3/simulator.h" @@ -63,6 +62,8 @@ TcpSocketImpl::GetTypeId () m_endPoint (0), m_node (0), m_tcp (0), + m_localAddress (Ipv4Address::GetZero ()), + m_localPort (0), m_errno (ERROR_NOTERROR), m_shutdownSend (false), m_shutdownRecv (false), @@ -77,17 +78,19 @@ TcpSocketImpl::GetTypeId () m_highestRxAck (0), m_lastRxAck (0), m_nextRxSequence (0), + m_rxAvailable (0), + m_rxBufSize (0), m_pendingData (0), + m_rxWindowSize (0), + m_persistTime (Seconds(6)), //XXX hook this into attributes? m_rtt (0), - m_lastMeasuredRtt (Seconds(0.0)), - m_rxAvailable (0), - m_wouldBlock (false) + m_lastMeasuredRtt (Seconds(0.0)) { NS_LOG_FUNCTION (this); } TcpSocketImpl::TcpSocketImpl(const TcpSocketImpl& sock) - : TcpSocket(sock), //copy the base class callbacks + : TcpSocket(sock), //copy object::m_tid, copy socket::callbacks m_skipRetxResched (sock.m_skipRetxResched), m_dupAckCount (sock.m_dupAckCount), m_delAckCount (0), @@ -114,21 +117,21 @@ TcpSocketImpl::TcpSocketImpl(const TcpSocketImpl& sock) m_highestRxAck (sock.m_highestRxAck), m_lastRxAck (sock.m_lastRxAck), m_nextRxSequence (sock.m_nextRxSequence), + m_rxAvailable (0), + m_rxBufSize (0), m_pendingData (0), m_segmentSize (sock.m_segmentSize), m_rxWindowSize (sock.m_rxWindowSize), - m_advertisedWindowSize (sock.m_advertisedWindowSize), m_cWnd (sock.m_cWnd), m_ssThresh (sock.m_ssThresh), m_initialCWnd (sock.m_initialCWnd), + m_persistTime (sock.m_persistTime), m_rtt (0), m_lastMeasuredRtt (Seconds(0.0)), m_cnTimeout (sock.m_cnTimeout), m_cnCount (sock.m_cnCount), - m_rxAvailable (0), - m_wouldBlock (false), m_sndBufSize (sock.m_sndBufSize), - m_rcvBufSize(sock.m_rcvBufSize) + m_rxBufMaxSize(sock.m_rxBufMaxSize) { NS_LOG_FUNCTION_NOARGS (); NS_LOG_LOGIC("Invoked the copy constructor"); @@ -142,6 +145,9 @@ TcpSocketImpl::TcpSocketImpl(const TcpSocketImpl& sock) { m_rtt = sock.m_rtt->Copy(); } + //null out the socket base class recvcallback, + //make user of the socket register this explicitly + SetRecvCallback (MakeNullCallback > () ); //can't "copy" the endpoint just yes, must do this when we know the peer info //too; this is in SYN_ACK_TX } @@ -176,7 +182,6 @@ TcpSocketImpl::SetNode (Ptr node) m_node = node; // Initialize some variables m_cWnd = m_initialCWnd * m_segmentSize; - m_rxWindowSize = m_advertisedWindowSize; } void @@ -212,6 +217,9 @@ TcpSocketImpl::Destroy (void) m_node = 0; m_endPoint = 0; m_tcp = 0; + NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " + << (Simulator::Now () + + Simulator::GetDelayLeft (m_retxEvent)).GetSeconds()); m_retxEvent.Cancel (); } int @@ -290,10 +298,6 @@ int TcpSocketImpl::Close (void) { NS_LOG_FUNCTION_NOARGS (); - if (m_state == CLOSED) - { - return -1; - } if (m_pendingData && m_pendingData->Size() != 0) { // App close with pending data must wait until all data transmitted m_closeOnEmpty = true; @@ -346,15 +350,16 @@ TcpSocketImpl::Connect (const Address & address) } return -1; } + +//p here is just data, no headers int -TcpSocketImpl::Send (const Ptr p) //p here is just data, no headers +TcpSocketImpl::Send (Ptr p, uint32_t flags) { NS_LOG_FUNCTION (this << p); if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT) { if (p->GetSize() > GetTxAvailable ()) { - m_wouldBlock = true; m_errno = ERROR_MSGSIZE; return -1; } @@ -382,11 +387,6 @@ TcpSocketImpl::Send (const Ptr p) //p here is just data, no headers } } -int TcpSocketImpl::Send (const uint8_t* buf, uint32_t size) -{ - return Send (Create (buf, size)); -} - int TcpSocketImpl::DoSendTo (Ptr p, const Address &address) { NS_LOG_FUNCTION (this << p << address); @@ -420,7 +420,7 @@ int TcpSocketImpl::DoSendTo (Ptr p, Ipv4Address ipv4, uint16_t port) } int -TcpSocketImpl::SendTo (Ptr p, const Address &address) +TcpSocketImpl::SendTo (Ptr p, uint32_t flags, const Address &address) { NS_LOG_FUNCTION (this << address << p); if (!m_connected) @@ -430,7 +430,7 @@ TcpSocketImpl::SendTo (Ptr p, const Address &address) } else { - return Send (p); //drop the address according to BSD manpages + return Send (p, flags); //drop the address according to BSD manpages } } @@ -452,9 +452,9 @@ TcpSocketImpl::GetTxAvailable (void) const } int -TcpSocketImpl::Listen (uint32_t q) +TcpSocketImpl::Listen (void) { - NS_LOG_FUNCTION (this << q); + NS_LOG_FUNCTION (this); Actions_t action = ProcessEvent (APP_LISTEN); ProcessAction (action); return 0; @@ -496,6 +496,7 @@ TcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags) out[i->first] = i->second; } m_rxAvailable -= i->second->GetSize (); + m_rxBufSize -= i->second->GetSize (); m_bufferedData.erase (i); // Remove from list } if (out.size() == 0) @@ -518,6 +519,7 @@ TcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags) m_bufferedData[i->first+SequenceNumber(avail)] = i->second->CreateFragment(avail,i->second->GetSize()-avail); m_rxAvailable += i->second->GetSize()-avail; + m_rxBufSize += i->second->GetSize()-avail; } } return outPacket; @@ -532,6 +534,31 @@ TcpSocketImpl::GetRxAvailable (void) const return m_rxAvailable; } +Ptr +TcpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress) +{ + NS_LOG_FUNCTION (this << maxSize << flags); + Ptr packet = Recv (maxSize, flags); + if (packet != 0) + { + SocketAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + fromAddress = tag.GetAddress (); + } + return packet; +} + +int +TcpSocketImpl::GetSockName (Address &address) const +{ + NS_LOG_FUNCTION_NOARGS (); + address = InetSocketAddress(m_localAddress, m_localPort); + return 0; +} + void TcpSocketImpl::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) { @@ -558,6 +585,13 @@ TcpSocketImpl::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) } } + if (m_rxWindowSize == 0 && tcpHeader.GetWindowSize () != 0) + { //persist probes end + NS_LOG_LOGIC (this<<" Leaving zerowindow persist state"); + m_persistEvent.Cancel (); + } + m_rxWindowSize = tcpHeader.GetWindowSize (); //update the flow control window + Events_t event = SimulationSingleton::Get ()->FlagsEvent (tcpHeader.GetFlags () ); Actions_t action = ProcessEvent (event); //updates the state Address address = InetSocketAddress (ipv4, port); @@ -606,7 +640,6 @@ Actions_t TcpSocketImpl::ProcessEvent (Events_t e) NS_LOG_LOGIC ("TcpSocketImpl " << this << " transition to CLOSED from " << m_state << " event " << e << " closeNot " << m_closeNotified << " action " << stateAction.action); - NotifyCloseCompleted (); m_closeNotified = true; NS_LOG_LOGIC ("TcpSocketImpl " << this << " calling Closed from PE" << " origState " << saveState @@ -620,7 +653,7 @@ Actions_t TcpSocketImpl::ProcessEvent (Events_t e) void TcpSocketImpl::SendEmptyPacket (uint8_t flags) { - NS_LOG_FUNCTION (this << flags); + NS_LOG_FUNCTION (this << (uint32_t)flags); Ptr p = Create (); TcpHeader header; @@ -629,17 +662,21 @@ void TcpSocketImpl::SendEmptyPacket (uint8_t flags) header.SetAckNumber (m_nextRxSequence); header.SetSourcePort (m_endPoint->GetLocalPort ()); header.SetDestinationPort (m_remotePort); - header.SetWindowSize (m_advertisedWindowSize); + header.SetWindowSize (AdvertisedWindowSize()); m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), m_remoteAddress); Time rto = m_rtt->RetransmitTimeout (); - if (flags & TcpHeader::SYN) + bool hasSyn = flags & TcpHeader::SYN; + bool hasFin = flags & TcpHeader::FIN; + bool isAck = flags == TcpHeader::ACK; + if (hasSyn) { rto = m_cnTimeout; m_cnTimeout = m_cnTimeout + m_cnTimeout; m_cnCount--; } - if (m_retxEvent.IsExpired () ) //no outstanding timer + if (m_retxEvent.IsExpired () && (hasSyn || hasFin) && !isAck ) + //no outstanding timer { NS_LOG_LOGIC ("Schedule retransmission timeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " @@ -733,6 +770,13 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, Ptr ipv4 = m_node->GetObject (); switch (a) { + case ACK_TX: + if(tcpHeader.GetFlags() & TcpHeader::FIN) + { + ++m_nextRxSequence; //bump this to account for the FIN + } + SendEmptyPacket (TcpHeader::ACK); + break; case SYN_ACK_TX: NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SYN_ACK_TX"); // m_remotePort = InetSocketAddress::ConvertFrom (fromAddress).GetPort (); @@ -755,19 +799,20 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, p, tcpHeader,fromAddress); return true; } - // This is the cloned endpoint - m_endPoint->SetPeer (m_remoteAddress, m_remotePort); - if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex)) - { - m_localAddress = ipv4->GetAddress (localIfIndex); - m_endPoint->SetLocalAddress (m_localAddress); - // Leave local addr in the portmap to any, as the path from - // remote can change and packets can arrive on different interfaces - //m_endPoint->SetLocalAddress (Ipv4Address::GetAny()); - } - // TCP SYN consumes one byte - m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1); - SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); + // This is the cloned endpoint + NS_ASSERT (m_state == SYN_RCVD); + m_endPoint->SetPeer (m_remoteAddress, m_remotePort); + if (ipv4->GetIfIndexForDestination (m_remoteAddress, localIfIndex)) + { + m_localAddress = ipv4->GetAddress (localIfIndex); + m_endPoint->SetLocalAddress (m_localAddress); + // Leave local addr in the portmap to any, as the path from + // remote can change and packets can arrive on different interfaces + //m_endPoint->SetLocalAddress (Ipv4Address::GetAny()); + } + // TCP SYN consumes one byte + m_nextRxSequence = tcpHeader.GetSequenceNumber() + SequenceNumber(1); + SendEmptyPacket (TcpHeader::SYN | TcpHeader::ACK); break; case ACK_TX_1: NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action ACK_TX_1"); @@ -778,15 +823,13 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, NS_LOG_DEBUG ("TcpSocketImpl " << this << " ACK_TX_1" << " nextRxSeq " << m_nextRxSequence); SendEmptyPacket (TcpHeader::ACK); - m_rxWindowSize = tcpHeader.GetWindowSize (); if (tcpHeader.GetAckNumber () > m_highestRxAck) { m_highestRxAck = tcpHeader.GetAckNumber (); // Data freed from the send buffer; notify any blocked sender - if (m_wouldBlock) + if (GetTxAvailable () > 0) { NotifySend (GetTxAvailable ()); - m_wouldBlock = false; } } SendPendingData (); @@ -797,13 +840,17 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, { break; } - if (tcpHeader.GetAckNumber () == m_highestRxAck && - tcpHeader.GetAckNumber () < m_nextTxSequence) + if (tcpHeader.GetAckNumber () == m_highestRxAck) { - DupAck (tcpHeader, ++m_dupAckCount); + if (tcpHeader.GetAckNumber () < m_nextTxSequence) + { + DupAck (tcpHeader, ++m_dupAckCount); + } + NS_ASSERT(tcpHeader.GetAckNumber () <= m_nextTxSequence); + //if the ack is precisely equal to the nextTxSequence break; } - if (tcpHeader.GetAckNumber () > m_highestRxAck) + if (tcpHeader.GetAckNumber () > m_highestRxAck) { m_dupAckCount = 0; } @@ -833,6 +880,7 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, { NewRx (p, tcpHeader, fromAddress); } + ++m_nextRxSequence; //bump this to account for the FIN States_t saveState = m_state; // Used to see if app responds NS_LOG_LOGIC ("TcpSocketImpl " << this << " peer close, state " << m_state); @@ -840,7 +888,6 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, { NS_LOG_LOGIC ("TCP " << this << " calling AppCloseRequest"); - NotifyCloseRequested(); m_closeRequestNotified = true; } NS_LOG_LOGIC ("TcpSocketImpl " << this @@ -861,14 +908,14 @@ bool TcpSocketImpl::ProcessPacketAction (Actions_t a, Ptr p, case SERV_NOTIFY: NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action SERV_NOTIFY"); NS_LOG_LOGIC ("TcpSocketImpl " << this << " Connected!"); - NotifyNewConnectionCreated (this, fromAddress); m_connected = true; // ! This is bogus; fix when we clone the tcp m_endPoint->SetPeer (m_remoteAddress, m_remotePort); //treat the connection orientation final ack as a newack CommonNewAck (tcpHeader.GetAckNumber (), true); + NotifyNewConnectionCreated (this, fromAddress); break; default: - break; + return ProcessAction (a); } return true; } @@ -918,7 +965,7 @@ bool TcpSocketImpl::SendPendingData (bool withAck) << " highestRxAck " << m_highestRxAck << " pd->Size " << m_pendingData->Size () << " pd->SFS " << m_pendingData->SizeFromSeq (m_firstPendingSequence, m_nextTxSequence)); - +//XXX pd->Size is probably a bug, should be SizeFromSeq(...) if (w < m_segmentSize && m_pendingData->Size () > w) { break; // No more @@ -951,6 +998,7 @@ bool TcpSocketImpl::SendPendingData (bool withAck) header.SetAckNumber (m_nextRxSequence); header.SetSourcePort (m_endPoint->GetLocalPort()); header.SetDestinationPort (m_remotePort); + header.SetWindowSize (AdvertisedWindowSize()); if (m_shutdownSend) { m_errno = ERROR_SHUTDOWN; @@ -961,7 +1009,7 @@ bool TcpSocketImpl::SendPendingData (bool withAck) if (m_retxEvent.IsExpired () ) //go ahead and schedule the retransmit { Time rto = m_rtt->RetransmitTimeout (); - NS_LOG_LOGIC ("SendPendingData Schedule retransmission timeout at time " << + NS_LOG_LOGIC (this<<" SendPendingData Schedule ReTxTimeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds () ); m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this); @@ -1014,6 +1062,17 @@ uint32_t TcpSocketImpl::AvailableWindow () return (win - unack); // Amount of window space available } +uint32_t TcpSocketImpl::RxBufferFreeSpace() +{ + return m_rxBufMaxSize - m_rxBufSize; +} + +uint16_t TcpSocketImpl::AdvertisedWindowSize() +{ + uint32_t max = 0xffff; + return std::min(RxBufferFreeSpace(), max); +} + void TcpSocketImpl::NewRx (Ptr p, const TcpHeader& tcpHeader, const Address& fromAddress) @@ -1029,9 +1088,20 @@ void TcpSocketImpl::NewRx (Ptr p, " ack " << tcpHeader.GetAckNumber() << " p.size is " << p->GetSize()); States_t origState = m_state; + if (RxBufferFreeSpace() < p->GetSize()) + { //if not enough room, fragment + p = p->CreateFragment(0, RxBufferFreeSpace()); + } + //XXX + //fragmenting here MIGHT not be the right thing to do, since possibly we trim + //the front and back off the packet below if it isn't all new data, so the + //check against RxBufferFreeSpace and fragmentation should ideally occur + //just before insertion into m_bufferedData, but this strategy is more + //agressive in rejecting oversized packets and still gives acceptable TCP uint32_t s = p->GetSize (); // Size of associated data if (s == 0) - {// Nothing to do if no associated data + {//if there is no data or no rx buffer space, just ack anyway + SendEmptyPacket (TcpHeader::ACK); return; } // Log sequence received if enabled @@ -1042,46 +1112,34 @@ void TcpSocketImpl::NewRx (Ptr p, // 3) Received seq is > expected, just re-ack previous and buffer data if (tcpHeader.GetSequenceNumber () == m_nextRxSequence) { // If seq is expected seq + // Trim the end if necessary // 1) Update nextRxSeq // 2) Buffer this packet so Recv can read it // 3) Send the ack + UnAckData_t::iterator next = m_bufferedData.upper_bound (m_nextRxSequence); + if (next != m_bufferedData.end ()) + { + SequenceNumber nextBufferedSeq = next->first; + if (m_nextRxSequence + SequenceNumber(s) > nextBufferedSeq) + {//tail end isn't all new, trim enough off the end + s = nextBufferedSeq - m_nextRxSequence; + } + } + p = p->CreateFragment (0,s); m_nextRxSequence += s; // Advance next expected sequence - //bytesReceived += s; // Statistics NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence ); - SocketRxAddressTag tag; + SocketAddressTag tag; tag.SetAddress (fromAddress); p->AddTag (tag); //buffer this, it'll be read by call to Recv UnAckData_t::iterator i = m_bufferedData.find (tcpHeader.GetSequenceNumber () ); - if (i != m_bufferedData.end () ) //we found it already in the buffer - { - i->second = 0; // relase reference to already buffered - } - // Save for later delivery - m_bufferedData[tcpHeader.GetSequenceNumber () ] = p; + NS_ASSERT(i == m_bufferedData.end ()); //no way it should have been found + // Save for later delivery if there is room + m_bufferedData[tcpHeader.GetSequenceNumber () ] = p; m_rxAvailable += p->GetSize (); - //putting this into the buffer might have filled in a sequence gap - //so we have to iterate through the list to find the largest contiguous - //sequenced chunk, and update m_rxAvailable appropriately - i = m_bufferedData.find (tcpHeader.GetSequenceNumber () ); - UnAckData_t::iterator next = i; - next++; - while(next != m_bufferedData.end()) - { - if(i->first + SequenceNumber(i->second->GetSize ()) == next->first) - { - //next packet is in sequence, count it - m_rxAvailable += next->second->GetSize(); - m_nextRxSequence += next->second->GetSize(); - } - else - { - break; //no more in this contiguous chunk - } - ++i; - ++next; - } + RxBufFinishInsert (tcpHeader.GetSequenceNumber ()); + m_rxBufSize += p->GetSize (); NotifyDataRecv (); if (m_closeNotified) { @@ -1096,20 +1154,94 @@ void TcpSocketImpl::NewRx (Ptr p, } } } - else if (SequenceNumber (tcpHeader.GetSequenceNumber ()) >= m_nextRxSequence) - { // Need to buffer this one + else if (tcpHeader.GetSequenceNumber () > m_nextRxSequence) + { // Need to buffer this one, but trim off the front and back if necessary NS_LOG_LOGIC ("Case 2, buffering " << tcpHeader.GetSequenceNumber () ); + UnAckData_t::iterator previous = + m_bufferedData.lower_bound (tcpHeader.GetSequenceNumber ()); + SequenceNumber startSeq = tcpHeader.GetSequenceNumber(); + if (previous != m_bufferedData.begin ()) + { + --previous; + startSeq = previous->first + SequenceNumber(previous->second->GetSize()); + if (startSeq > tcpHeader.GetSequenceNumber ()) + { + s = tcpHeader.GetSequenceNumber () + SequenceNumber(s) - startSeq; + } + else + { + startSeq = tcpHeader.GetSequenceNumber(); + } + } + //possibly trim off the end + UnAckData_t::iterator next = m_bufferedData.upper_bound (tcpHeader.GetSequenceNumber()); + if (next != m_bufferedData.end ()) + { + SequenceNumber nextBufferedSeq = next->first; + if (startSeq + SequenceNumber(s) > nextBufferedSeq) + {//tail end isn't all new either, trim enough off the end + s = nextBufferedSeq - startSeq; + } + } + p = p->CreateFragment (startSeq - tcpHeader.GetSequenceNumber (),s); UnAckData_t::iterator i = - m_bufferedData.find (tcpHeader.GetSequenceNumber () ); + m_bufferedData.find (startSeq); if (i != m_bufferedData.end () ) + { + if(p->GetSize() > i->second->GetSize()) + { + i->second = 0; // relase reference to already buffered + } + else + { + p = i->second; + } + } + // Save for later delivery + SocketAddressTag tag; + tag.SetAddress (fromAddress); + p->AddTag (tag); + m_bufferedData[startSeq] = p; + i = m_bufferedData.find (startSeq); + next = i; + ++next; + if(next != m_bufferedData.end()) + { + NS_ASSERT(next->first >= i->first + SequenceNumber(i->second->GetSize ())); + } + } + else if (tcpHeader.GetSequenceNumber () + SequenceNumber(s) > m_nextRxSequence) + {//parial new data case, only part of the packet is new data + //trim the beginning + s = tcpHeader.GetSequenceNumber () + SequenceNumber(s) - m_nextRxSequence; //how much new + //possibly trim off the end + UnAckData_t::iterator next = m_bufferedData.upper_bound (m_nextRxSequence); + if (next != m_bufferedData.end ()) + { + SequenceNumber nextBufferedSeq = next->first; + if (m_nextRxSequence + SequenceNumber(s) > nextBufferedSeq) + {//tail end isn't all new either, trim enough off the end + s = nextBufferedSeq - m_nextRxSequence; + } + } + p = p->CreateFragment (m_nextRxSequence - tcpHeader.GetSequenceNumber (),s); + SequenceNumber start = m_nextRxSequence; + m_nextRxSequence += s; // Advance next expected sequence + SocketAddressTag tag; + tag.SetAddress (fromAddress); + p->AddTag (tag); + //buffer the new fragment, it'll be read by call to Recv + UnAckData_t::iterator i = m_bufferedData.find (start); + if (i != m_bufferedData.end () ) //we found it already in the buffer { i->second = 0; // relase reference to already buffered } // Save for later delivery - SocketRxAddressTag tag; - tag.SetAddress (fromAddress); - p->AddTag (tag); - m_bufferedData[tcpHeader.GetSequenceNumber () ] = p; + m_bufferedData[start] = p; + m_rxAvailable += p->GetSize (); + m_rxBufSize += p->GetSize(); + RxBufFinishInsert(start); + NotifyDataRecv (); } else { // debug @@ -1131,6 +1263,36 @@ void TcpSocketImpl::NewRx (Ptr p, } } +void TcpSocketImpl::RxBufFinishInsert (SequenceNumber seq) +{ + //putting data into the buffer might have filled in a sequence gap so we have + //to iterate through the list to find the largest contiguous sequenced chunk, + //and update m_rxAvailable and m_nextRxSequence appropriately + UnAckData_t::iterator i = m_bufferedData.find (seq); + UnAckData_t::iterator next = i; + ++next; + //make sure the buffer is logically sequenced + if(next != m_bufferedData.end()) + { + NS_ASSERT(next->first >= i->first + SequenceNumber(i->second->GetSize ())); + } + while(next != m_bufferedData.end()) + { + if(i->first + SequenceNumber(i->second->GetSize ()) == next->first) + { + //next packet is in sequence, count it + m_rxAvailable += next->second->GetSize(); + m_nextRxSequence += next->second->GetSize(); + } + else + { + break; //no more in this contiguous chunk + } + ++i; + ++next; + } +} + void TcpSocketImpl::DelAckTimeout () { m_delAckCount = 0; @@ -1145,23 +1307,38 @@ void TcpSocketImpl::CommonNewAck (SequenceNumber ack, bool skipTimer) //DEBUG(1,(cout << "TCP " << this << "Cancelling retx timer " << endl)); if (!skipTimer) { - m_retxEvent.Cancel (); + NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " + << (Simulator::Now () + + Simulator::GetDelayLeft (m_retxEvent)).GetSeconds()); + m_retxEvent.Cancel (); //On recieving a "New" ack we restart retransmission timer .. RFC 2988 Time rto = m_rtt->RetransmitTimeout (); - NS_LOG_LOGIC ("Schedule retransmission timeout at time " + NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); - m_retxEvent = Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this); + m_retxEvent = + Simulator::Schedule (rto, &TcpSocketImpl::ReTxTimeout, this); + } + if (m_rxWindowSize == 0 && m_persistEvent.IsExpired ()) //zerowindow + { + NS_LOG_LOGIC (this<<"Enter zerowindow persist state"); + NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " + << (Simulator::Now () + + Simulator::GetDelayLeft (m_retxEvent)).GetSeconds()); + m_retxEvent.Cancel (); + NS_LOG_LOGIC ("Schedule persist timeout at time " + < 0) { - // m_highestRxAck advancing means some data was acked, and the size - // of free space in the buffer has increased NotifySend (GetTxAvailable ()); - m_wouldBlock = false; } if (ack > m_nextTxSequence) { @@ -1176,6 +1353,9 @@ void TcpSocketImpl::CommonNewAck (SequenceNumber ack, bool skipTimer) delete m_pendingData; m_pendingData = 0; // Insure no re-tx timer + NS_LOG_LOGIC (this<<" Cancelled ReTxTimeout event which was set to expire at " + << (Simulator::Now () + + Simulator::GetDelayLeft (m_retxEvent)).GetSeconds()); m_retxEvent.Cancel (); } } @@ -1241,6 +1421,7 @@ void TcpSocketImpl::DupAck (const TcpHeader& t, uint32_t count) void TcpSocketImpl::ReTxTimeout () { // Retransmit timeout NS_LOG_FUNCTION (this); + NS_LOG_LOGIC (this<<" ReTxTimeout Expired at time "< p = + m_pendingData->CopyFromSeq(1,m_firstPendingSequence,m_nextTxSequence); + TcpHeader tcpHeader; + tcpHeader.SetSequenceNumber (m_nextTxSequence); + tcpHeader.SetAckNumber (m_nextRxSequence); + tcpHeader.SetSourcePort (m_endPoint->GetLocalPort()); + tcpHeader.SetDestinationPort (m_remotePort); + tcpHeader.SetWindowSize (AdvertisedWindowSize()); + + m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (), + m_remoteAddress); + NS_LOG_LOGIC ("Schedule persist timeout at time " + < p = m_pendingData->CopyFromSeq (m_segmentSize, m_firstPendingSequence, - m_highestRxAck); + m_nextTxSequence); // Calculate remaining data for COE check uint32_t remainingData = m_pendingData->SizeFromSeq ( m_firstPendingSequence, @@ -1306,7 +1513,7 @@ void TcpSocketImpl::Retransmit () if (m_retxEvent.IsExpired () ) { Time rto = m_rtt->RetransmitTimeout (); - NS_LOG_LOGIC ("Schedule retransmission timeout at time " + NS_LOG_LOGIC (this<<" Schedule ReTxTimeout at time " << Simulator::Now ().GetSeconds () << " to expire at time " << (Simulator::Now () + rto).GetSeconds ()); m_retxEvent = Simulator::Schedule (rto,&TcpSocketImpl::ReTxTimeout,this); @@ -1319,7 +1526,7 @@ void TcpSocketImpl::Retransmit () tcpHeader.SetSourcePort (m_endPoint->GetLocalPort()); tcpHeader.SetDestinationPort (m_remotePort); tcpHeader.SetFlags (flags); - tcpHeader.SetWindowSize (m_advertisedWindowSize); + tcpHeader.SetWindowSize (AdvertisedWindowSize()); m_tcp->SendPacket (p, tcpHeader, m_endPoint->GetLocalAddress (), m_remoteAddress); @@ -1340,13 +1547,13 @@ TcpSocketImpl::GetSndBufSize (void) const void TcpSocketImpl::SetRcvBufSize (uint32_t size) { - m_rcvBufSize = size; + m_rxBufMaxSize = size; } uint32_t TcpSocketImpl::GetRcvBufSize (void) const { - return m_rcvBufSize; + return m_rxBufMaxSize; } void @@ -1361,18 +1568,6 @@ TcpSocketImpl::GetSegSize (void) const return m_segmentSize; } -void -TcpSocketImpl::SetAdvWin (uint32_t window) -{ - m_advertisedWindowSize = window; -} - -uint32_t -TcpSocketImpl::GetAdvWin (void) const -{ - return m_advertisedWindowSize; -} - void TcpSocketImpl::SetSSThresh (uint32_t threshold) { @@ -1446,3 +1641,310 @@ TcpSocketImpl::GetDelAckMaxCount (void) const } }//namespace ns3 + +#ifdef RUN_SELF_TESTS + +#include "ns3/test.h" +#include "ns3/socket-factory.h" +#include "ns3/tcp-socket-factory.h" +#include "ns3/simulator.h" +#include "ns3/simple-channel.h" +#include "ns3/simple-net-device.h" +#include "ns3/drop-tail-queue.h" +#include "ns3/config.h" +#include "internet-stack.h" +#include + +namespace ns3 { + +class TcpSocketImplTest: public Test +{ + public: + TcpSocketImplTest (); + virtual bool RunTests (void); + private: + //test 1, which sends string "Hello world" server->client + void Test1 (void); + void Test1_HandleConnectionCreated (Ptr, const Address &); + void Test1_HandleRecv (Ptr sock); + + //test 2, which sends a number of bytes server->client + void Test2 (uint32_t payloadSize); + void Test2_HandleConnectionCreated (Ptr, const Address &); + void Test2_HandleRecv (Ptr sock); + uint32_t test2_payloadSize; + + //test 3, which makes sure the rx buffer is finite + void Test3 (uint32_t payloadSize); + void Test3_HandleConnectionCreated (Ptr, const Address &); + void Test3_HandleRecv (Ptr sock); + uint32_t test3_payloadSize; + + //helpers to make topology construction easier + Ptr CreateInternetNode (); + Ptr AddSimpleNetDevice (Ptr,const char*,const char*); + void SetupDefaultSim (); + + //reset all of the below state for another run + void Reset (); + + //all of the state this class needs; basically both ends of the connection, + //and this test kind of acts as an single application running on both nodes + //simultaneously + Ptr node0; + Ptr node1; + Ptr dev0; + Ptr dev1; + Ptr channel; + Ptr listeningSock; + Ptr sock0; + Ptr sock1; + uint32_t rxBytes0; + uint32_t rxBytes1; + + uint8_t* rxPayload; + + bool result; +}; + +TcpSocketImplTest::TcpSocketImplTest () + : Test ("TcpSocketImpl"), + rxBytes0 (0), + rxBytes1 (0), + rxPayload (0), + result (true) +{ +} + +bool +TcpSocketImplTest::RunTests (void) +{ + Test1(); + if (!result) return false; + Test2(600); + if (!result) return false; + Test3(20000); + return result; +} + +//----------------------------------------------------------------------------- +//test 1----------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void +TcpSocketImplTest::Test1 () +{ + SetupDefaultSim (); + listeningSock->SetAcceptCallback + (MakeNullCallback, const Address &> (), + MakeCallback(&TcpSocketImplTest::Test1_HandleConnectionCreated,this)); + sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test1_HandleRecv, this)); + + Simulator::Run (); + Simulator::Destroy (); + + result = result && (rxBytes1 == 13); + result = result && (strcmp((const char*) rxPayload,"Hello World!") == 0); + + Reset (); +} + +void +TcpSocketImplTest::Test1_HandleConnectionCreated (Ptr s, const Address & addr) +{ + NS_ASSERT(s != listeningSock); + NS_ASSERT(sock0 == 0); + sock0 = s; + const uint8_t* hello = (uint8_t*)"Hello World!"; + Ptr p = Create (hello, 13); + sock0->Send(p); + + sock0->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test1_HandleRecv, this)); +} + +void +TcpSocketImplTest::Test1_HandleRecv (Ptr sock) +{ + NS_ASSERT (sock == sock0 || sock == sock1); + Ptr p = sock->Recv(); + uint32_t sz = p->GetSize(); + if (sock == sock1) + { + rxBytes1 += sz; + rxPayload = new uint8_t[sz]; + memcpy (rxPayload, p->PeekData(), sz); + } + else + { + NS_FATAL_ERROR ("Recv from unknown socket "<SetAcceptCallback + (MakeNullCallback, const Address &> (), + MakeCallback(&TcpSocketImplTest::Test2_HandleConnectionCreated,this)); + sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test2_HandleRecv, this)); + + Simulator::Run (); + Simulator::Destroy (); + + result = result && (rxBytes1 == test2_payloadSize); + + Reset (); +} + +void +TcpSocketImplTest::Test2_HandleConnectionCreated (Ptr s, const Address & addr) +{ + NS_ASSERT(s != listeningSock); + NS_ASSERT(sock0 == 0); + sock0 = s; + Ptr p = Create (test2_payloadSize); + sock0->Send(p); + + sock0->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test2_HandleRecv, this)); +} + +void +TcpSocketImplTest::Test2_HandleRecv (Ptr sock) +{ + NS_ASSERT (sock == sock0 || sock == sock1); + Ptr p = sock->Recv(); + uint32_t sz = p->GetSize(); + if (sock == sock1) + { + rxBytes1 += sz; + } + else + { + NS_FATAL_ERROR ("Not supposed to be back traffic in test 2..."<SetAcceptCallback + (MakeNullCallback, const Address &> (), + MakeCallback(&TcpSocketImplTest::Test3_HandleConnectionCreated,this)); + sock1->SetRecvCallback (MakeCallback(&TcpSocketImplTest::Test3_HandleRecv, this)); + + Simulator::Run (); + Simulator::Destroy (); + + result = result && (rxBytes1 == test3_payloadSize); + + Reset(); +} +void +TcpSocketImplTest::Test3_HandleConnectionCreated (Ptr s, const Address &) +{ + NS_ASSERT(s != listeningSock); + NS_ASSERT(sock0 == 0); + sock0 = s; + Ptr p = Create (test3_payloadSize); + sock0->Send(p); +} +void +TcpSocketImplTest::Test3_HandleRecv (Ptr sock) +{ + NS_ASSERT_MSG (sock == sock1, "Not supposed to be back traffic in test 3... "); + if(sock->GetRxAvailable() >= 10000 ) //perform batch reads every 10000 bytes + { + Ptr p = sock->Recv(); + uint32_t sz = p->GetSize(); + rxBytes1 += sz; + } +} + +//----------------------------------------------------------------------------- +//helpers---------------------------------------------------------------------- +//----------------------------------------------------------------------------- +Ptr +TcpSocketImplTest::CreateInternetNode () +{ + Ptr node = CreateObject (); + AddInternetStack (node); + return node; +} + +Ptr +TcpSocketImplTest::AddSimpleNetDevice (Ptr node, const char* ipaddr, const char* netmask) +{ + Ptr dev = CreateObject (); + dev->SetAddress (Mac48Address::Allocate ()); + node->AddDevice (dev); + Ptr ipv4 = node->GetObject (); + uint32_t ndid = ipv4->AddInterface (dev); + ipv4->SetAddress (ndid, Ipv4Address (ipaddr)); + ipv4->SetNetworkMask (ndid, Ipv4Mask (netmask)); + ipv4->SetUp (ndid); + return dev; +} + +void +TcpSocketImplTest::SetupDefaultSim () +{ + const char* netmask = "255.255.255.0"; + const char* ipaddr0 = "192.168.1.1"; + const char* ipaddr1 = "192.168.1.2"; + node0 = CreateInternetNode (); + node1 = CreateInternetNode (); + dev0 = AddSimpleNetDevice (node0, ipaddr0, netmask); + dev1 = AddSimpleNetDevice (node1, ipaddr1, netmask); + + channel = CreateObject (); + dev0->SetChannel (channel); + dev1->SetChannel (channel); + + Ptr sockFactory0 = node0->GetObject (); + Ptr sockFactory1 = node1->GetObject (); + + listeningSock = sockFactory0->CreateSocket(); + sock1 = sockFactory1->CreateSocket(); + + uint16_t port = 50000; + InetSocketAddress serverlocaladdr (Ipv4Address::GetAny(), port); + InetSocketAddress serverremoteaddr (Ipv4Address(ipaddr0), port); + + listeningSock->Bind(serverlocaladdr); + listeningSock->Listen (); + + sock1->Connect(serverremoteaddr); +} + +void +TcpSocketImplTest::Reset () +{ + node0 = 0; + node1 = 0; + dev0 = 0; + dev1 = 0; + channel = 0; + listeningSock = 0; + sock0 = 0; + sock1 = 0; + rxBytes0 = 0; + rxBytes1 = 0; + delete[] rxPayload; + rxPayload = 0; +} + +static TcpSocketImplTest gTcpSocketImplTest; + +}//namespace ns3 + +#endif /* RUN_SELF_TESTS */ diff --git a/src/internet-stack/tcp-socket-impl.h b/src/internet-stack/tcp-socket-impl.h index 8f1f832f5..81d75fce6 100644 --- a/src/internet-stack/tcp-socket-impl.h +++ b/src/internet-stack/tcp-socket-impl.h @@ -42,6 +42,27 @@ class Packet; class TcpL4Protocol; class TcpHeader; +/** + * \ingroup socket + * \ingroup tcp + * + * \brief An implementation of a stream socket using TCP. + * + * This class contains an implementation of TCP Tahoe, as well as a sockets + * interface for talking to TCP. Features include connection orientation, + * reliability through cumulative acknowledgements, congestion and flow + * control. Finite send buffer semantics are modeled, but as of yet, finite + * receive buffer modelling is unimplemented. + * + * The closedown of these sockets is as of yet not compliant with the relevent + * RFCs, i.e. the FIN handshaking isn't correct. While this is visible at the + * PCAP tracing level, it has no effect on the statistics users are interested + * in, i.e. throughput, delay, etc. of actual payload data. + * + * Asynchronous callbacks to provide notifications to higher layers that a + * protocol event has occured, such as space freeing up in the send buffer + * or new data arriving in the receive buffer. + */ class TcpSocketImpl : public TcpSocket { public: @@ -65,14 +86,15 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Send (Ptr p); - virtual int Send (const uint8_t* buf, uint32_t size); - virtual int SendTo(Ptr p, const Address &address); + virtual int Listen(void); virtual uint32_t GetTxAvailable (void) const; - virtual int Listen(uint32_t queueLimit); - - virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual int Send (Ptr p, uint32_t flags); + virtual int SendTo(Ptr p, uint32_t flags, const Address &toAddress); virtual uint32_t GetRxAvailable (void) const; + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual Ptr RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress); + virtual int GetSockName (Address &address) const; private: friend class Tcp; @@ -101,8 +123,13 @@ private: virtual uint32_t Window(); // Return window size (integer) virtual uint32_t AvailableWindow();// Return unfilled portion of window + //methods for Rx buffer management + uint32_t RxBufferFreeSpace(); + uint16_t AdvertisedWindowSize(); + // Manage data tx/rx void NewRx (Ptr, const TcpHeader&, const Address&); + void RxBufFinishInsert (SequenceNumber); // XXX This should be virtual and overridden Ptr Copy (); void NewAck (SequenceNumber seq); @@ -111,6 +138,7 @@ private: void ReTxTimeout (); void DelAckTimeout (); void LastAckTimeout (); + void PersistTimeout (); void Retransmit (); void CommonNewAck (SequenceNumber seq, bool skipTimer = false); @@ -121,8 +149,6 @@ private: virtual uint32_t GetRcvBufSize (void) const; virtual void SetSegSize (uint32_t size); virtual uint32_t GetSegSize (void) const; - virtual void SetAdvWin (uint32_t window); - virtual uint32_t GetAdvWin (void) const; virtual void SetSSThresh (uint32_t threshold); virtual uint32_t GetSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); @@ -174,23 +200,33 @@ private: SequenceNumber m_lastRxAck; //sequence info, reciever side - SequenceNumber m_nextRxSequence; + SequenceNumber m_nextRxSequence; //next expected sequence + + //Rx buffer + UnAckData_t m_bufferedData; //buffer which sorts out of sequence data + //Rx buffer state + uint32_t m_rxAvailable; // amount of data available for reading through Recv + uint32_t m_rxBufSize; //size in bytes of the data in the rx buf + //note that these two are not the same: rxAvailbale is the number of + //contiguous sequenced bytes that can be read, rxBufSize is the TOTAL size + //including out of sequence data, such that m_rxAvailable <= m_rxBufSize - //history data - //this is the incoming data buffer which sorts out of sequence data - UnAckData_t m_bufferedData; //this is kind of the tx buffer PendingData* m_pendingData; SequenceNumber m_firstPendingSequence; // Window management uint32_t m_segmentSize; //SegmentSize - uint32_t m_rxWindowSize; - uint32_t m_advertisedWindowSize; //Window to advertise + uint32_t m_rxWindowSize; //Flow control window TracedValue m_cWnd; //Congestion window uint32_t m_ssThresh; //Slow Start Threshold uint32_t m_initialCWnd; //Initial cWnd value + //persist timer management + Time m_persistTime; + EventId m_persistEvent; + + // Round trip time estimation Ptr m_rtt; Time m_lastMeasuredRtt; @@ -199,14 +235,9 @@ private: Time m_cnTimeout; uint32_t m_cnCount; - // Temporary queue for delivering data to application - uint32_t m_rxAvailable; - - bool m_wouldBlock; // set to true whenever socket would block on send() - // Attributes uint32_t m_sndBufSize; // buffer limit for the outgoing queue - uint32_t m_rcvBufSize; // maximum receive socket buffer size + uint32_t m_rxBufMaxSize; // maximum receive socket buffer size }; }//namespace ns3 diff --git a/src/internet-stack/tcp-typedefs.h b/src/internet-stack/tcp-typedefs.h index 277511c26..ff538710e 100644 --- a/src/internet-stack/tcp-typedefs.h +++ b/src/internet-stack/tcp-typedefs.h @@ -63,21 +63,21 @@ typedef enum { typedef enum { NO_ACT, // 0 ACK_TX, // 1 - ACK_TX_1, // ACK response to syn - RST_TX, // 2 - SYN_TX, // 3 - SYN_ACK_TX, // 4 - FIN_TX, // 5 - FIN_ACK_TX, // 6 - NEW_ACK, // 7 - NEW_SEQ_RX, // 8 - RETX, // 9 - TX_DATA, // 10 - PEER_CLOSE, // 11 - APP_CLOSED, // 12 - CANCEL_TM, // 13 - APP_NOTIFY, // 14 - Notify app that connection failed - SERV_NOTIFY, // 15 - Notify server tcp that connection completed + ACK_TX_1, // 2 - ACK response to syn + RST_TX, // 3 + SYN_TX, // 4 + SYN_ACK_TX, // 5 + FIN_TX, // 6 + FIN_ACK_TX, // 7 + NEW_ACK, // 8 + NEW_SEQ_RX, // 9 + RETX, // 10 + TX_DATA, // 11 + PEER_CLOSE, // 12 + APP_CLOSED, // 13 + CANCEL_TM, // 14 + APP_NOTIFY, // 15 - Notify app that connection failed + SERV_NOTIFY, // 16 - Notify server tcp that connection completed LAST_ACTION } Actions_t; class SA // State/Action pair diff --git a/src/internet-stack/udp-header.cc b/src/internet-stack/udp-header.cc index 92cd4164b..ce0af0766 100644 --- a/src/internet-stack/udp-header.cc +++ b/src/internet-stack/udp-header.cc @@ -19,14 +19,12 @@ */ #include "udp-header.h" -#include "ipv4-checksum.h" +#include "ns3/address-utils.h" namespace ns3 { NS_OBJECT_ENSURE_REGISTERED (UdpHeader); -bool UdpHeader::m_calcChecksum = false; - /* 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. @@ -35,7 +33,8 @@ UdpHeader::UdpHeader () : m_sourcePort (0xfffd), m_destinationPort (0xfffd), m_payloadSize (0xfffd), - m_initialChecksum (0) + m_calcChecksum(false), + m_goodChecksum(true) {} UdpHeader::~UdpHeader () { @@ -71,26 +70,39 @@ UdpHeader::GetDestinationPort (void) const return m_destinationPort; } void -UdpHeader::SetPayloadSize (uint16_t size) -{ - m_payloadSize = size; -} -void UdpHeader::InitializeChecksum (Ipv4Address source, Ipv4Address destination, uint8_t protocol) { - uint8_t buf[12]; - source.Serialize (buf); - destination.Serialize (buf+4); - buf[8] = 0; - buf[9] = protocol; - uint16_t udpLength = m_payloadSize + GetSerializedSize (); - buf[10] = udpLength >> 8; - buf[11] = udpLength & 0xff; - - m_initialChecksum = Ipv4ChecksumCalculate (0, buf, 12); + m_source = source; + m_destination = destination; + m_protocol = protocol; } +uint16_t +UdpHeader::CalculateHeaderChecksum (uint16_t size) const +{ + Buffer buf = Buffer (12); + buf.AddAtStart (12); + Buffer::Iterator it = buf.Begin (); + + WriteTo (it, m_source); + WriteTo (it, m_destination); + it.WriteU8 (0); /* protocol */ + it.WriteU8 (m_protocol); /* protocol */ + it.WriteU8 (size >> 8); /* length */ + it.WriteU8 (size & 0xff); /* length */ + + it = buf.Begin (); + /* we don't CompleteChecksum ( ~ ) now */ + return ~(it.CalculateIpChecksum (12)); +} + +bool +UdpHeader::IsChecksumOk (void) const +{ + return m_goodChecksum; +} + TypeId UdpHeader::GetTypeId (void) @@ -125,23 +137,21 @@ void UdpHeader::Serialize (Buffer::Iterator start) const { Buffer::Iterator i = start; + i.WriteHtonU16 (m_sourcePort); i.WriteHtonU16 (m_destinationPort); - i.WriteHtonU16 (m_payloadSize + GetSerializedSize ()); + i.WriteHtonU16 (start.GetSize ()); i.WriteU16 (0); - if (m_calcChecksum) + if (m_calcChecksum) { -#if 0 - //XXXX - uint16_t checksum = Ipv4ChecksumCalculate (m_initialChecksum, - buffer->PeekData (), - GetSerializedSize () + m_payloadSize); - checksum = Ipv4ChecksumComplete (checksum); - i = buffer->Begin (); - i.Next (6); - i.WriteU16 (checksum); -#endif + uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ()); + i = start; + uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum); + + i = start; + i.Next(6); + i.WriteU16(checksum); } } uint32_t @@ -151,10 +161,17 @@ UdpHeader::Deserialize (Buffer::Iterator start) m_sourcePort = i.ReadNtohU16 (); m_destinationPort = i.ReadNtohU16 (); m_payloadSize = i.ReadNtohU16 () - GetSerializedSize (); - if (m_calcChecksum) - { - // XXX verify checksum. - } + i.Next (2); + + if(m_calcChecksum) + { + uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ()); + i = start; + uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum); + + m_goodChecksum = (checksum == 0); + } + return GetSerializedSize (); } diff --git a/src/internet-stack/udp-header.h b/src/internet-stack/udp-header.h index a7bbf23e2..c6cd232b5 100644 --- a/src/internet-stack/udp-header.h +++ b/src/internet-stack/udp-header.h @@ -28,7 +28,12 @@ namespace ns3 { /** + * \ingroup udp * \brief Packet header for UDP packets + * + * This class has fields corresponding to those in a network UDP header + * (port numbers, payload size, checksum) as well as methods for serialization + * to and deserialization from a byte buffer. */ class UdpHeader : public Header { @@ -45,7 +50,7 @@ public: /** * \brief Enable checksum calculation for UDP (XXX currently has no effect) */ - static void EnableChecksums (void); + void EnableChecksums (void); /** * \param port the destination port for this UdpHeader */ @@ -62,10 +67,6 @@ public: * \return the destination port for this UdpHeader */ uint16_t GetDestinationPort (void) const; - /** - * \param size The payload size in bytes - */ - void SetPayloadSize (uint16_t size); /** * \param source the ip source to use in the underlying @@ -89,13 +90,23 @@ public: virtual void Serialize (Buffer::Iterator start) const; virtual uint32_t Deserialize (Buffer::Iterator start); + /** + * \brief Is the UDP checksum correct ? + * \returns true if the checksum is correct, false otherwise. + */ + bool IsChecksumOk (void) const; + private: + uint16_t CalculateHeaderChecksum (uint16_t size) const; uint16_t m_sourcePort; uint16_t m_destinationPort; uint16_t m_payloadSize; - uint16_t m_initialChecksum; - static bool m_calcChecksum; + Ipv4Address m_source; + Ipv4Address m_destination; + uint8_t m_protocol; + bool m_calcChecksum; + bool m_goodChecksum; }; } // namespace ns3 diff --git a/src/internet-stack/udp-l4-protocol.cc b/src/internet-stack/udp-l4-protocol.cc index 7a8c58152..080813b2c 100644 --- a/src/internet-stack/udp-l4-protocol.cc +++ b/src/internet-stack/udp-l4-protocol.cc @@ -22,6 +22,7 @@ #include "ns3/assert.h" #include "ns3/packet.h" #include "ns3/node.h" +#include "ns3/boolean.h" #include "udp-l4-protocol.h" #include "udp-header.h" @@ -45,6 +46,11 @@ UdpL4Protocol::GetTypeId (void) static TypeId tid = TypeId ("ns3::UdpL4Protocol") .SetParent () .AddConstructor () + .AddAttribute ("CalcChecksum", "If true, we calculate the checksum of outgoing packets" + " and verify the checksum of incoming packets.", + BooleanValue (false), + MakeBooleanAccessor (&UdpL4Protocol::m_calcChecksum), + MakeBooleanChecker ()) ; return tid; } @@ -71,11 +77,6 @@ UdpL4Protocol::GetProtocolNumber (void) const { return PROT_NUMBER; } -int -UdpL4Protocol::GetVersion (void) const -{ - return 2; -} void @@ -151,9 +152,22 @@ UdpL4Protocol::Receive(Ptr packet, Ptr interface) { NS_LOG_FUNCTION (this << packet << source << destination); - UdpHeader udpHeader; + if(m_calcChecksum) + { + udpHeader.EnableChecksums(); + } + + udpHeader.InitializeChecksum (source, destination, PROT_NUMBER); + packet->RemoveHeader (udpHeader); + + if(!udpHeader.IsChecksumOk ()) + { + NS_LOG_INFO("Bad checksum : dropping packet!"); + return; + } + Ipv4EndPointDemux::EndPoints endPoints = m_endPoints->Lookup (destination, udpHeader.GetDestinationPort (), source, udpHeader.GetSourcePort (), interface); @@ -172,12 +186,15 @@ UdpL4Protocol::Send (Ptr packet, NS_LOG_FUNCTION (this << packet << saddr << daddr << sport << dport); UdpHeader udpHeader; + if(m_calcChecksum) + { + udpHeader.EnableChecksums(); + udpHeader.InitializeChecksum (saddr, + daddr, + PROT_NUMBER); + } udpHeader.SetDestinationPort (dport); udpHeader.SetSourcePort (sport); - udpHeader.SetPayloadSize (packet->GetSize ()); - udpHeader.InitializeChecksum (saddr, - daddr, - PROT_NUMBER); packet->AddHeader (udpHeader); diff --git a/src/internet-stack/udp-l4-protocol.h b/src/internet-stack/udp-l4-protocol.h index ce6ec7cae..c92f83a61 100644 --- a/src/internet-stack/udp-l4-protocol.h +++ b/src/internet-stack/udp-l4-protocol.h @@ -34,6 +34,7 @@ namespace ns3 { class Node; class Socket; /** + * \ingroup udp * \brief Implementation of the UDP protocol */ class UdpL4Protocol : public Ipv4L4Protocol { @@ -47,7 +48,6 @@ public: void SetNode (Ptr node); virtual int GetProtocolNumber (void) const; - virtual int GetVersion (void) const; /** * \return A smart Socket pointer to a UdpSocket, allocated by this instance @@ -93,6 +93,7 @@ protected: private: Ptr m_node; Ipv4EndPointDemux *m_endPoints; + bool m_calcChecksum; }; }; // namespace ns3 diff --git a/src/internet-stack/udp-socket-factory-impl.h b/src/internet-stack/udp-socket-factory-impl.h index b4366fc31..e05e6443c 100644 --- a/src/internet-stack/udp-socket-factory-impl.h +++ b/src/internet-stack/udp-socket-factory-impl.h @@ -28,6 +28,23 @@ namespace ns3 { class UdpL4Protocol; /** + * \ingroup internetStack + * \defgroup udp Udp + * + * This is an implementation of the User Datagram Protocol described in + * RFC 768. It implements a connectionless, unreliable datagram packet + * service. Packets may be reordered or duplicated before they arrive. + * UDP generates and checks checksums to catch transmission errors. + * + * The following options are not presently part of this implementation: + * UDP_CORK, MSG_DONTROUTE, path MTU discovery control (e.g. + * IP_MTU_DISCOVER). MTU handling is also weak in ns-3 for the moment; + * it is best to send datagrams that do not exceed 1500 byte MTU (e.g. + * 1472 byte UDP datagrams) + */ + +/** + * \ingroup udp * \brief Object to create UDP socket instances * \internal * diff --git a/src/internet-stack/udp-socket-impl.cc b/src/internet-stack/udp-socket-impl.cc index 03b0da18f..3feb6b3f5 100644 --- a/src/internet-stack/udp-socket-impl.cc +++ b/src/internet-stack/udp-socket-impl.cc @@ -30,7 +30,7 @@ #include "udp-socket-impl.h" #include "udp-l4-protocol.h" #include "ipv4-end-point.h" -#include "ipv4-l4-demux.h" +#include NS_LOG_COMPONENT_DEFINE ("UdpSocketImpl"); @@ -199,7 +199,6 @@ int UdpSocketImpl::Close(void) { NS_LOG_FUNCTION_NOARGS (); - NotifyCloseCompleted (); return 0; } @@ -217,16 +216,16 @@ UdpSocketImpl::Connect(const Address & address) } int -UdpSocketImpl::Listen (uint32_t queueLimit) +UdpSocketImpl::Listen (void) { m_errno = Socket::ERROR_OPNOTSUPP; return -1; } int -UdpSocketImpl::Send (Ptr p) +UdpSocketImpl::Send (Ptr p, uint32_t flags) { - NS_LOG_FUNCTION (this << p); + NS_LOG_FUNCTION (this << p << flags); if (!m_connected) { @@ -239,7 +238,7 @@ UdpSocketImpl::Send (Ptr p) int UdpSocketImpl::DoSend (Ptr p) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (this << p); if (m_endPoint == 0) { if (Bind () == -1) @@ -346,6 +345,7 @@ UdpSocketImpl::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) m_udp->Send (p->Copy (), addri, bcast, m_endPoint->GetLocalPort (), port); NotifyDataSent (p->GetSize ()); + NotifySend (GetTxAvailable ()); } NS_LOG_LOGIC ("Limited broadcast end."); return p->GetSize(); @@ -356,6 +356,7 @@ UdpSocketImpl::DoSendTo (Ptr p, Ipv4Address dest, uint16_t port) m_udp->Send (p->Copy (), ipv4->GetAddress (localIfIndex), dest, m_endPoint->GetLocalPort (), port); NotifyDataSent (p->GetSize ()); + NotifySend (GetTxAvailable ()); return p->GetSize();; } else @@ -380,19 +381,28 @@ UdpSocketImpl::GetTxAvailable (void) const } int -UdpSocketImpl::SendTo (Ptr p, const Address &address) +UdpSocketImpl::SendTo (Ptr p, uint32_t flags, const Address &address) { - NS_LOG_FUNCTION (this << address << p); + NS_LOG_FUNCTION (this << p << flags << address); InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendTo (p, ipv4, port); } +uint32_t +UdpSocketImpl::GetRxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + // We separately maintain this state to avoid walking the queue + // every time this might be called + return m_rxAvailable; +} + Ptr UdpSocketImpl::Recv (uint32_t maxSize, uint32_t flags) { - NS_LOG_FUNCTION_NOARGS (); + NS_LOG_FUNCTION (this << maxSize << flags); if (m_deliveryQueue.empty() ) { return 0; @@ -410,13 +420,36 @@ UdpSocketImpl::Recv (uint32_t maxSize, uint32_t flags) return p; } -uint32_t -UdpSocketImpl::GetRxAvailable (void) const +Ptr +UdpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress) +{ + NS_LOG_FUNCTION (this << maxSize << flags); + Ptr packet = Recv (maxSize, flags); + if (packet != 0) + { + SocketAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + fromAddress = tag.GetAddress (); + } + return packet; +} + +int +UdpSocketImpl::GetSockName (Address &address) const { NS_LOG_FUNCTION_NOARGS (); - // We separately maintain this state to avoid walking the queue - // every time this might be called - return m_rxAvailable; + if (m_endPoint != 0) + { + address = InetSocketAddress (m_endPoint->GetLocalAddress (), m_endPoint->GetLocalPort()); + } + else + { + address = InetSocketAddress(Ipv4Address::GetZero(), 0); + } + return 0; } void @@ -431,7 +464,7 @@ UdpSocketImpl::ForwardUp (Ptr packet, Ipv4Address ipv4, uint16_t port) if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize) { Address address = InetSocketAddress (ipv4, port); - SocketRxAddressTag tag; + SocketAddressTag tag; tag.SetAddress (address); packet->AddTag (tag); m_deliveryQueue.push (packet); @@ -638,7 +671,7 @@ UdpSocketImplTest::RunTests (void) // Unicast test m_receivedPacket = Create (); m_receivedPacket2 = Create (); - NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create (123), + NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create (123), 0, InetSocketAddress (Ipv4Address("10.0.0.1"), 1234)), 123); Simulator::Run (); NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123); @@ -651,7 +684,7 @@ UdpSocketImplTest::RunTests (void) m_receivedPacket = Create (); m_receivedPacket2 = Create (); - NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create (123), + NS_TEST_ASSERT_EQUAL (txSocket->SendTo ( Create (123), 0, InetSocketAddress (Ipv4Address("255.255.255.255"), 1234)), 123); Simulator::Run (); NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123); @@ -673,7 +706,7 @@ UdpSocketImplTest::RunTests (void) m_receivedPacket = Create (); m_receivedPacket2 = Create (); - NS_TEST_ASSERT_EQUAL (txSocket->SendTo (Create (123), + NS_TEST_ASSERT_EQUAL (txSocket->SendTo (Create (123), 0, InetSocketAddress (Ipv4Address("255.255.255.255"), 1234)), 123); Simulator::Run (); NS_TEST_ASSERT_EQUAL (m_receivedPacket->GetSize (), 123); diff --git a/src/internet-stack/udp-socket-impl.h b/src/internet-stack/udp-socket-impl.h index f7b185215..03fae2e56 100644 --- a/src/internet-stack/udp-socket-impl.h +++ b/src/internet-stack/udp-socket-impl.h @@ -36,6 +36,14 @@ class Node; class Packet; class UdpL4Protocol; +/** + * \ingroup udp + * \brief A sockets interface to UDP + * + * This class subclasses ns3::UdpSocket, and provides a socket interface + * to ns3's implementation of UDP. + */ + class UdpSocketImpl : public UdpSocket { public: @@ -57,13 +65,15 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Listen (uint32_t queueLimit); - virtual int Send (Ptr p); - virtual int SendTo (Ptr p, const Address &address); + virtual int Listen (void); virtual uint32_t GetTxAvailable (void) const; - - virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual int Send (Ptr p, uint32_t flags); + virtual int SendTo (Ptr p, uint32_t flags, const Address &address); virtual uint32_t GetRxAvailable (void) const; + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual Ptr RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress); + virtual int GetSockName (Address &address) const; private: // Attributes set through UdpSocket base class diff --git a/src/internet-stack/wscript b/src/internet-stack/wscript index 780a84a98..077a35859 100644 --- a/src/internet-stack/wscript +++ b/src/internet-stack/wscript @@ -1,11 +1,129 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +import Params +import Task +import os +import urllib + +# Mercurial repository of the network simulation cradle +NSC_REPO = "https://secure.wand.net.nz/mercurial/nsc" +NSC_RELEASE_URL = "http://research.wand.net.nz/software/nsc" +NSC_RELEASE_NAME = "nsc-0.4.0" + +# directory that contains network simulation cradle source +# note, this path is relative to the project root +NSC_DIR = "nsc" + + +def set_options(opt): + opt.add_option('--enable-nsc', + help=('Enable Network Simulation Cradle to allow the use real-world network stacks'), + action="store_true", default=False, + dest='enable_nsc') + + +def nsc_fetch(): + def nsc_clone(): + print "Retrieving nsc from " + NSC_REPO + if os.system("hg version > /dev/null 2>&1") != 0: + Params.fatal("Mercurial not installed, http fallback not yet implemented") + if os.system("hg clone " + NSC_REPO) != 0: + Params.fatal("hg -q clone %s failed" % NSC_REPO) + + def nsc_update(): + if os.system("hg version > /dev/null 2>&1") != 0: + Params.warning("Mercurial not installed, not updating nsc source") + + print "Pulling nsc updates from " + NSC_REPO + if os.system("cd nsc && hg pull %s && hg update" % NSC_REPO) != 0: + Params.warning("Updating nsc using mercurial failed") + + def nsc_download(): + local_file = NSC_RELEASE_NAME + ".tar.bz2" + remote_file = NSC_RELEASE_URL + "/" + local_file + print "Retrieving nsc from " + remote_file + urllib.urlretrieve(remote_file, local_file) + print "Uncompressing " + local_file + os.system("tar -xjf " + local_file) + os.system('mv ' + NSC_RELEASE_NAME + ' nsc') + + if not os.path.exists('.hg'): + nsc_download () + elif not os.path.exists("nsc"): + nsc_clone() + else: + nsc_update() + +def configure(conf): + conf.env['ENABLE_NSC'] = False + + # checks for flex and bison, which is needed to build NSCs globaliser + def check_nsc_buildutils(): + import flex + import bison + conf.check_tool('flex bison') + e = conf.create_library_configurator() + e.mandatory = True + e.name = 'fl' + e.run() + + if not Params.g_options.enable_nsc: + conf.report_optional_feature("nsc", "Network Simulation Cradle", False, + "--enable-nsc configure option not given") + return + + check_nsc_buildutils() + + arch = os.uname()[4] + ok = False + if arch == 'x86_64' or arch == 'i686' or arch == 'i586' or arch == 'i486' or arch == 'i386': + conf.env['NSC_ENABLED'] = 'yes' + conf.env.append_value('CXXDEFINES', 'NETWORK_SIMULATION_CRADLE') + e = conf.create_library_configurator() + e.mandatory = True + e.name = 'dl' + e.define = 'HAVE_DL' + e.uselib = 'DL' + e.run() + conf.env['ENABLE_NSC'] = True + ok = True + conf.check_message('NSC supported architecture', arch, ok) + conf.report_optional_feature("nsc", "Network Simulation Cradle", ok, + "architecture %r not supported" % arch) + nsc_fetch() + + + +class NscBuildTask(Task.TaskBase): + """task that builds nsc + """ + def __init__(self, builddir): + self.m_display = 'build-nsc' + self.prio = 1000 # build after the rest of ns-3 + self.builddir = builddir + super(NscBuildTask, self).__init__() + + def run(self): + # XXX: Detect gcc major version(s) available to build supported stacks + builddir = self.builddir + kernels = [['linux-2.6.18', 'linux2.6.18'], + ['linux-2.6.26', 'linux2.6.26']] + for dir, name in kernels: + soname = 'lib' + name + '.so' + if not os.path.exists(os.path.join("..", NSC_DIR, dir, soname)): + if os.system('cd ../%s && python scons.py %s' % (NSC_DIR, dir)) != 0: + Params.fatal("Building NSC stack failed") + + if not os.path.exists(builddir + '/' + soname): + try: + os.symlink('../../' + NSC_DIR + '/' + dir + '/' + soname, builddir + '/' + soname) + except: + Params.fatal("Error linking " + builddir + '/' + soname) def build(bld): obj = bld.create_ns3_module('internet-stack', ['node']) obj.source = [ 'internet-stack.cc', - 'ipv4-l4-demux.cc', 'ipv4-l4-protocol.cc', 'udp-header.cc', 'tcp-header.cc', @@ -39,4 +157,16 @@ def build(bld): 'udp-header.h', 'tcp-header.h', 'sequence-number.h', + 'ipv4-interface.h', + 'ipv4-l3-protocol.h', + 'ipv4-static-routing.h', ] + + if bld.env()['NSC_ENABLED']: + obj.source.append ('nsc-tcp-socket-impl.cc') + obj.source.append ('nsc-tcp-l4-protocol.cc') + obj.source.append ('nsc-tcp-socket-factory-impl.cc') + obj.source.append ('nsc-sysctl.cc') + obj.uselib = 'DL' + builddir = os.path.abspath(os.path.join(bld.env()['NS3_BUILDDIR'], bld.env ().variant())) + NscBuildTask(builddir) diff --git a/src/mobility/mobility-model.cc b/src/mobility/mobility-model.cc index 9af62c66a..b88d74710 100644 --- a/src/mobility/mobility-model.cc +++ b/src/mobility/mobility-model.cc @@ -31,7 +31,7 @@ MobilityModel::GetTypeId (void) static TypeId tid = TypeId ("ns3::MobilityModel") .SetParent () .AddAttribute ("Position", "The current position of the mobility model.", - TypeId::ATTR_SGC, + TypeId::ATTR_SET | TypeId::ATTR_GET, VectorValue (Vector (0.0, 0.0, 0.0)), MakeVectorAccessor (&MobilityModel::SetPosition, &MobilityModel::GetPosition), diff --git a/src/mobility/random-direction-2d-mobility-model.cc b/src/mobility/random-direction-2d-mobility-model.cc index 3ae572073..221118cf7 100644 --- a/src/mobility/random-direction-2d-mobility-model.cc +++ b/src/mobility/random-direction-2d-mobility-model.cc @@ -76,8 +76,9 @@ RandomDirection2dMobilityModel::Start (void) void RandomDirection2dMobilityModel::BeginPause (void) { - Time pause = Seconds (m_pause.GetValue ()); + m_helper.Update (); m_helper.Pause (); + Time pause = Seconds (m_pause.GetValue ()); m_event = Simulator::Schedule (pause, &RandomDirection2dMobilityModel::ResetDirectionAndSpeed, this); NotifyCourseChange (); } @@ -86,12 +87,14 @@ void RandomDirection2dMobilityModel::SetDirectionAndSpeed (double direction) { NS_LOG_FUNCTION_NOARGS (); + m_helper.UpdateWithBounds (m_bounds); + Vector position = m_helper.GetCurrentPosition (); double speed = m_speed.GetValue (); const Vector vector (std::cos (direction) * speed, std::sin (direction) * speed, 0.0); - Vector position = m_helper.GetCurrentPosition (m_bounds); - m_helper.Reset (vector); + m_helper.SetVelocity (vector); + m_helper.Unpause (); Vector next = m_bounds.CalculateIntersection (position, vector); Time delay = Seconds (CalculateDistance (position, next) / speed); m_event = Simulator::Schedule (delay, @@ -103,7 +106,8 @@ RandomDirection2dMobilityModel::ResetDirectionAndSpeed (void) { double direction = UniformVariable::GetSingleValue (0, PI); - Vector position = m_helper.GetCurrentPosition (m_bounds); + m_helper.UpdateWithBounds (m_bounds); + Vector position = m_helper.GetCurrentPosition (); switch (m_bounds.GetClosestSide (position)) { case Rectangle::RIGHT: @@ -124,12 +128,13 @@ RandomDirection2dMobilityModel::ResetDirectionAndSpeed (void) Vector RandomDirection2dMobilityModel::DoGetPosition (void) const { - return m_helper.GetCurrentPosition (m_bounds); + m_helper.UpdateWithBounds (m_bounds); + return m_helper.GetCurrentPosition (); } void RandomDirection2dMobilityModel::DoSetPosition (const Vector &position) { - m_helper.InitializePosition (position); + m_helper.SetPosition (position); Simulator::Remove (m_event); m_event = Simulator::ScheduleNow (&RandomDirection2dMobilityModel::Start, this); } diff --git a/src/mobility/random-walk-2d-mobility-model.cc b/src/mobility/random-walk-2d-mobility-model.cc index 59824a4f1..e426a6575 100644 --- a/src/mobility/random-walk-2d-mobility-model.cc +++ b/src/mobility/random-walk-2d-mobility-model.cc @@ -80,12 +80,14 @@ RandomWalk2dMobilityModel::RandomWalk2dMobilityModel () void RandomWalk2dMobilityModel::Start (void) { + m_helper.Update (); double speed = m_speed.GetValue (); double direction = m_direction.GetValue (); Vector vector (std::cos (direction) * speed, std::sin (direction) * speed, 0.0); - m_helper.Reset (vector); + m_helper.SetVelocity (vector); + m_helper.Unpause (); Time delayLeft; if (m_mode == RandomWalk2dMobilityModel::MODE_TIME) @@ -124,7 +126,8 @@ RandomWalk2dMobilityModel::DoWalk (Time delayLeft) void RandomWalk2dMobilityModel::Rebound (Time delayLeft) { - Vector position = m_helper.GetCurrentPosition (m_bounds); + m_helper.UpdateWithBounds (m_bounds); + Vector position = m_helper.GetCurrentPosition (); Vector speed = m_helper.GetVelocity (); switch (m_bounds.GetClosestSide (position)) { @@ -137,7 +140,8 @@ RandomWalk2dMobilityModel::Rebound (Time delayLeft) speed.y = - speed.y; break; } - m_helper.Reset (speed); + m_helper.SetVelocity (speed); + m_helper.Unpause (); DoWalk (delayLeft); } @@ -150,13 +154,14 @@ RandomWalk2dMobilityModel::DoDispose (void) Vector RandomWalk2dMobilityModel::DoGetPosition (void) const { - return m_helper.GetCurrentPosition (m_bounds); + m_helper.UpdateWithBounds (m_bounds); + return m_helper.GetCurrentPosition (); } void RandomWalk2dMobilityModel::DoSetPosition (const Vector &position) { NS_ASSERT (m_bounds.IsInside (position)); - m_helper.InitializePosition (position); + m_helper.SetPosition (position); Simulator::Remove (m_event); m_event = Simulator::ScheduleNow (&RandomWalk2dMobilityModel::Start, this); } diff --git a/src/mobility/random-waypoint-mobility-model.cc b/src/mobility/random-waypoint-mobility-model.cc index fd29f82e9..a7c6e1537 100644 --- a/src/mobility/random-waypoint-mobility-model.cc +++ b/src/mobility/random-waypoint-mobility-model.cc @@ -62,6 +62,7 @@ RandomWaypointMobilityModel::RandomWaypointMobilityModel () void RandomWaypointMobilityModel::BeginWalk (void) { + m_helper.Update (); Vector m_current = m_helper.GetCurrentPosition (); Vector destination = m_position->GetNext (); double speed = m_speed.GetValue (); @@ -70,7 +71,7 @@ RandomWaypointMobilityModel::BeginWalk (void) double dz = (destination.z - m_current.z); double k = speed / std::sqrt (dx*dx + dy*dy + dz*dz); - m_helper.Reset (Vector (k*dx, k*dy, k*dz)); + m_helper.SetVelocity (Vector (k*dx, k*dy, k*dz)); Time travelDelay = Seconds (CalculateDistance (destination, m_current) / speed); m_event = Simulator::Schedule (travelDelay, &RandomWaypointMobilityModel::Start, this); @@ -80,21 +81,23 @@ RandomWaypointMobilityModel::BeginWalk (void) void RandomWaypointMobilityModel::Start (void) { - Time pause = Seconds (m_pause.GetValue ()); + m_helper.Update (); m_helper.Pause (); - NotifyCourseChange (); + Time pause = Seconds (m_pause.GetValue ()); m_event = Simulator::Schedule (pause, &RandomWaypointMobilityModel::BeginWalk, this); + NotifyCourseChange (); } Vector RandomWaypointMobilityModel::DoGetPosition (void) const { + m_helper.Update (); return m_helper.GetCurrentPosition (); } void RandomWaypointMobilityModel::DoSetPosition (const Vector &position) { - m_helper.InitializePosition (position); + m_helper.SetPosition (position); Simulator::Remove (m_event); Simulator::ScheduleNow (&RandomWaypointMobilityModel::Start, this); } diff --git a/src/mobility/static-speed-helper.cc b/src/mobility/static-speed-helper.cc index d781494f6..0a207b77b 100644 --- a/src/mobility/static-speed-helper.cc +++ b/src/mobility/static-speed-helper.cc @@ -29,67 +29,56 @@ StaticSpeedHelper::StaticSpeedHelper (const Vector &position) : m_position (position) {} StaticSpeedHelper::StaticSpeedHelper (const Vector &position, - const Vector &speed) + const Vector &vel) : m_position (position), - m_speed (speed), + m_velocity (vel), m_paused (true) {} void -StaticSpeedHelper::InitializePosition (const Vector &position) +StaticSpeedHelper::SetPosition (const Vector &position) { m_position = position; - m_speed.x = 0.0; - m_speed.y = 0.0; - m_speed.z = 0.0; + m_velocity = Vector (0.0, 0.0, 0.0); m_lastUpdate = Simulator::Now (); - m_paused = true; } Vector StaticSpeedHelper::GetCurrentPosition (void) const { - Update (); return m_position; } Vector StaticSpeedHelper::GetVelocity (void) const { - return m_paused? Vector (0.0, 0.0, 0.0) : m_speed; + return m_paused? Vector (0.0, 0.0, 0.0) : m_velocity; } void -StaticSpeedHelper::SetSpeed (const Vector &speed) +StaticSpeedHelper::SetVelocity (const Vector &vel) { - Update (); - m_speed = speed; + m_velocity = vel; + m_lastUpdate = Simulator::Now (); } void StaticSpeedHelper::Update (void) const { - if (m_paused) - { - return; - } Time now = Simulator::Now (); NS_ASSERT (m_lastUpdate <= now); Time deltaTime = now - m_lastUpdate; m_lastUpdate = now; + if (m_paused) + { + return; + } double deltaS = deltaTime.GetSeconds (); - m_position.x += m_speed.x * deltaS; - m_position.y += m_speed.y * deltaS; - m_position.z += m_speed.z * deltaS; + m_position.x += m_velocity.x * deltaS; + m_position.y += m_velocity.y * deltaS; + m_position.z += m_velocity.z * deltaS; } -void -StaticSpeedHelper::Reset (const Vector &speed) -{ - Update (); - m_speed = speed; - Unpause (); -} void -StaticSpeedHelper::UpdateFull (const Rectangle &bounds) const +StaticSpeedHelper::UpdateWithBounds (const Rectangle &bounds) const { Update (); m_position.x = std::min (bounds.xMax, m_position.x); @@ -98,28 +87,16 @@ StaticSpeedHelper::UpdateFull (const Rectangle &bounds) const m_position.y = std::max (bounds.yMin, m_position.y); } -Vector -StaticSpeedHelper::GetCurrentPosition (const Rectangle &bounds) const -{ - UpdateFull (bounds); - return m_position; -} - void StaticSpeedHelper::Pause (void) { - Update (); m_paused = true; } void StaticSpeedHelper::Unpause (void) { - if (m_paused) - { - m_lastUpdate = Simulator::Now (); - m_paused = false; - } + m_paused = false; } } // namespace ns3 diff --git a/src/mobility/static-speed-helper.h b/src/mobility/static-speed-helper.h index d743460f4..e2c149231 100644 --- a/src/mobility/static-speed-helper.h +++ b/src/mobility/static-speed-helper.h @@ -33,23 +33,21 @@ class StaticSpeedHelper StaticSpeedHelper (); StaticSpeedHelper (const Vector &position); StaticSpeedHelper (const Vector &position, - const Vector &speed); - void InitializePosition (const Vector &position); + const Vector &vel); - void Reset (const Vector &speed); - Vector GetCurrentPosition (const Rectangle &bounds) const; + void SetPosition (const Vector &position); Vector GetCurrentPosition (void) const; Vector GetVelocity (void) const; - void SetSpeed (const Vector &speed); + void SetVelocity (const Vector &vel); void Pause (void); void Unpause (void); - private: + void UpdateWithBounds (const Rectangle &rectangle) const; void Update (void) const; - void UpdateFull (const Rectangle &rectangle) const; + private: mutable Time m_lastUpdate; mutable Vector m_position; - Vector m_speed; + Vector m_velocity; bool m_paused; }; diff --git a/src/mobility/static-speed-mobility-model.cc b/src/mobility/static-speed-mobility-model.cc index 4dcc77012..50e153328 100644 --- a/src/mobility/static-speed-mobility-model.cc +++ b/src/mobility/static-speed-mobility-model.cc @@ -39,9 +39,11 @@ StaticSpeedMobilityModel::~StaticSpeedMobilityModel () {} void -StaticSpeedMobilityModel::SetSpeed (const Vector &speed) +StaticSpeedMobilityModel::SetVelocity (const Vector &speed) { - m_helper.SetSpeed (speed); + m_helper.Update (); + m_helper.SetVelocity (speed); + m_helper.Unpause (); NotifyCourseChange (); } @@ -49,12 +51,13 @@ StaticSpeedMobilityModel::SetSpeed (const Vector &speed) Vector StaticSpeedMobilityModel::DoGetPosition (void) const { + m_helper.Update (); return m_helper.GetCurrentPosition (); } void StaticSpeedMobilityModel::DoSetPosition (const Vector &position) { - m_helper.InitializePosition (position); + m_helper.SetPosition (position); NotifyCourseChange (); } Vector diff --git a/src/mobility/static-speed-mobility-model.h b/src/mobility/static-speed-mobility-model.h index 3da5b466e..b222f1268 100644 --- a/src/mobility/static-speed-mobility-model.h +++ b/src/mobility/static-speed-mobility-model.h @@ -49,7 +49,7 @@ public: * Set the current speed now to (dx,dy,dz) * Unit is meters/s */ - void SetSpeed (const Vector &speed); + void SetVelocity (const Vector &speed); private: virtual Vector DoGetPosition (void) const; virtual void DoSetPosition (const Vector &position); diff --git a/src/node/address.cc b/src/node/address.cc index 365161e63..f7e981055 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -1,5 +1,26 @@ +/* -*- 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 + */ + #include "ns3/assert.h" #include "address.h" +#include #include #include @@ -9,7 +30,7 @@ Address::Address () : m_type (0), m_len (0) { - memset (m_data, 0, m_len); + // Buffer left uninitialized } Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len) @@ -17,7 +38,6 @@ Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len) 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) @@ -25,7 +45,6 @@ Address::Address (const Address & address) 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 & @@ -35,7 +54,6 @@ Address::operator = (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); return *this; } @@ -77,12 +95,13 @@ Address::CopyFrom (const uint8_t *buffer, uint8_t len) m_len = len; return m_len; } -uint32_t + 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; diff --git a/src/node/address.h b/src/node/address.h index 7e1b5c3ef..98b858796 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -1,3 +1,23 @@ +/* -*- 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 + */ + #ifndef ADDRESS_H #define ADDRESS_H @@ -66,11 +86,11 @@ namespace ns3 { class Address { public: - enum { - /** - * The maximum size of a byte buffer which - * can be stored in an Address instance. - */ + /** + * The maximum size of a byte buffer which + * can be stored in an Address instance. + */ + enum MaxSize_e { MAX_SIZE = 30 }; @@ -115,6 +135,11 @@ public: * \param buffer buffer to copy the whole address data structure to * \param len the size of the buffer * \returns the number of bytes copied. + * + * Copies the type to buffer[0], the length of the address internal buffer + * to buffer[1] and copies the internal buffer starting at buffer[2]. len + * must be at least the size of the internal buffer plus a byte for the type + * and a byte for the length. */ uint32_t CopyAllTo (uint8_t *buffer, uint8_t len) const; /** @@ -124,8 +149,8 @@ public: * \param len length of buffer * \returns the number of bytes copied. * - * Copy the input buffer to the internal buffer of this address - * instance. + * Copy the address bytes from buffer into to the internal buffer of this + * address instance. */ uint32_t CopyFrom (const uint8_t *buffer, uint8_t len); /** @@ -133,6 +158,10 @@ public: * a copy of all the members of this Address class. * \param len the length of the buffer * \returns the number of bytes copied. + * + * The inverse of CopyAllTo(). + * + * \see CopyAllTo */ uint32_t CopyAllFrom (const uint8_t *buffer, uint8_t len); /** diff --git a/src/node/application.h b/src/node/application.h index 1fb243691..bb706cd4f 100644 --- a/src/node/application.h +++ b/src/node/application.h @@ -33,17 +33,13 @@ class Node; class RandomVariable; /** - * \ingroup node - * \defgroup application Application - */ -/** - * \ingroup application - * \brief The base class for all ns3 applications + * \addtogroup applications Applications + * + * Class ns3::Application can be used as a base class for ns3 applications. + * Applications are associated with individual nodes. Each node + * holds a list of references (smart pointers) to its applications. * - * Class Application is the base class for all ns3 applications. - * Applications are associated with individual nodes. - * - * Conceptually, an application has zero or more Socket + * Conceptually, an application has zero or more ns3::Socket * objects associated with it, that are created using the Socket * creation API of the Kernel capability. The Socket object * API is modeled after the @@ -53,6 +49,14 @@ class RandomVariable; * in ns3. A set of "upcalls" are defined that will be called when * the previous blocking call would normally exit. THis is documented * in more detail Socket class in socket.h. + * + * The main purpose of the base class application public API is to + * provide a uniform way to start and stop applications. + */ + + /** + * \brief The base class for all ns3 applications + * */ class Application : public Object { diff --git a/src/node/channel.h b/src/node/channel.h index 78c3fc5f0..1e4a0cd6a 100644 --- a/src/node/channel.h +++ b/src/node/channel.h @@ -14,8 +14,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef CHANNEL_H -#define CHANNEL_H +#ifndef NS3_CHANNEL_H +#define NS3_CHANNEL_H #include #include @@ -44,6 +44,7 @@ public: Channel (); Channel (std::string name); + virtual ~Channel (); void SetName(std::string); std::string GetName(void); @@ -62,11 +63,10 @@ public: */ virtual Ptr GetDevice (uint32_t i) const = 0; -protected: - virtual ~Channel (); +private: std::string m_name; }; }; // namespace ns3 -#endif /* CHANNEL_H */ +#endif /* NS3_CHANNEL_H */ diff --git a/src/node/drop-tail-queue.cc b/src/node/drop-tail-queue.cc index 8c5a0a8cf..5a119c9e6 100644 --- a/src/node/drop-tail-queue.cc +++ b/src/node/drop-tail-queue.cc @@ -87,7 +87,7 @@ DropTailQueue::DoDequeue (void) return p; } -Ptr +Ptr DropTailQueue::DoPeek (void) const { NS_LOG_FUNCTION (this); diff --git a/src/node/drop-tail-queue.h b/src/node/drop-tail-queue.h index 0fe245105..17d97c85f 100644 --- a/src/node/drop-tail-queue.h +++ b/src/node/drop-tail-queue.h @@ -47,7 +47,7 @@ public: private: virtual bool DoEnqueue (Ptr p); virtual Ptr DoDequeue (void); - virtual Ptr DoPeek (void) const; + virtual Ptr DoPeek (void) const; private: std::queue > m_packets; diff --git a/src/node/ipv4-header.cc b/src/node/ipv4-header.cc index 758358f98..393921c4d 100644 --- a/src/node/ipv4-header.cc +++ b/src/node/ipv4-header.cc @@ -38,6 +38,7 @@ Ipv4Header::Ipv4Header () m_protocol (0), m_flags (0), m_fragmentOffset (0), + m_checksum(0), m_goodChecksum (true) {} @@ -177,23 +178,6 @@ Ipv4Header::IsChecksumOk (void) const return m_goodChecksum; } -uint16_t -Ipv4Header::ChecksumCalculate(Buffer::Iterator &i, uint16_t size) -{ - /* see RFC 1071 to understand this code. */ - uint32_t sum = 0; - - for (int j = 0; j < size/2; j++) - sum += i.ReadU16 (); - - if (size & 1) - sum += i.ReadU8 (); - - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - return ~sum; -} - TypeId Ipv4Header::GetTypeId (void) { @@ -237,6 +221,7 @@ Ipv4Header::Print (std::ostream &os) const os << "tos 0x" << std::hex << m_tos << std::dec << " " << "ttl " << m_ttl << " " << "id " << m_identification << " " + << "protocol " << m_protocol << " " << "offset " << m_fragmentOffset << " " << "flags [" << flags << "] " << "length: " << (m_payloadSize + 5 * 4) @@ -282,7 +267,7 @@ Ipv4Header::Serialize (Buffer::Iterator start) const if (m_calcChecksum) { i = start; - uint16_t checksum = ChecksumCalculate(i, 20); + uint16_t checksum = i.CalculateIpChecksum(20); NS_LOG_LOGIC ("checksum=" < #include +#include namespace ns3 { @@ -142,6 +143,18 @@ Mac48Address::IsBroadcast (void) const } bool Mac48Address::IsMulticast (void) const +{ + uint8_t mcBuf[6]; + CopyTo (mcBuf); + mcBuf[3] &= 0x80; + mcBuf[4] = 0; + mcBuf[5] = 0; + Mac48Address prefix; + prefix.CopyFrom (mcBuf); + return prefix == Mac48Address::GetMulticastPrefix (); +} +bool +Mac48Address::IsGroup (void) const { return (m_address[0] & 0x01) == 0x01; } @@ -151,6 +164,48 @@ Mac48Address::GetBroadcast (void) static Mac48Address broadcast = Mac48Address ("ff:ff:ff:ff:ff:ff"); return broadcast; } +Mac48Address +Mac48Address::GetMulticastPrefix (void) +{ + static Mac48Address multicast = Mac48Address ("01:00:5e:00:00:00"); + return multicast; +} +Mac48Address +Mac48Address::GetMulticast (Ipv4Address multicastGroup) +{ + Mac48Address etherAddr = Mac48Address::GetMulticastPrefix (); + // + // We now have the multicast address in an abstract 48-bit container. We + // need to pull it out so we can play with it. When we're done, we have the + // high order bits in etherBuffer[0], etc. + // + uint8_t etherBuffer[6]; + etherAddr.CopyTo (etherBuffer); + + // + // Now we need to pull the raw bits out of the Ipv4 destination address. + // + uint8_t ipBuffer[4]; + multicastGroup.Serialize (ipBuffer); + + // + // RFC 1112 says that an Ipv4 host group address is mapped to an EUI-48 + // multicast address by placing the low-order 23-bits of the IP address into + // the low-order 23 bits of the Ethernet multicast address + // 01-00-5E-00-00-00 (hex). + // + etherBuffer[3] |= ipBuffer[1] & 0x7f; + etherBuffer[4] = ipBuffer[2]; + etherBuffer[5] = ipBuffer[3]; + + // + // Now, etherBuffer has the desired ethernet multicast address. We have to + // suck these bits back into the Mac48Address, + // + Mac48Address result; + result.CopyFrom (etherBuffer); + return result; +} bool operator == (const Mac48Address &a, const Mac48Address &b) { diff --git a/src/node/mac48-address.h b/src/node/mac48-address.h index 4572ab484..78084bac4 100644 --- a/src/node/mac48-address.h +++ b/src/node/mac48-address.h @@ -24,6 +24,7 @@ #include #include "ns3/attribute.h" #include "ns3/attribute-helper.h" +#include "ipv4-address.h" namespace ns3 { @@ -92,12 +93,25 @@ public: * \returns true if this is a multicast address, false otherwise. */ bool IsMulticast (void) const; + /** + * \returns true if the group bit is set, false otherwise. + */ + bool IsGroup (void) const; /** * \returns the broadcast address */ static Mac48Address GetBroadcast (void); + /** + * \returns a multicast address + */ + static Mac48Address GetMulticast (Ipv4Address address); + + /** + * \returns the multicast prefix (01:00:5e:00:00:00). + */ + static Mac48Address GetMulticastPrefix (void); private: /** * \returns a new Address instance diff --git a/src/node/mac64-address.cc b/src/node/mac64-address.cc index 13c4913eb..666397624 100644 --- a/src/node/mac64-address.cc +++ b/src/node/mac64-address.cc @@ -22,6 +22,7 @@ #include "ns3/assert.h" #include #include +#include namespace ns3 { diff --git a/src/node/net-device.cc b/src/node/net-device.cc index 410cc3f49..431a5e5bc 100644 --- a/src/node/net-device.cc +++ b/src/node/net-device.cc @@ -20,6 +20,7 @@ #include "ns3/object.h" #include "ns3/log.h" +#include "ns3/uinteger.h" #include "net-device.h" NS_LOG_COMPONENT_DEFINE ("NetDevice"); @@ -31,7 +32,15 @@ NS_OBJECT_ENSURE_REGISTERED (NetDevice); TypeId NetDevice::GetTypeId (void) { static TypeId tid = TypeId ("ns3::NetDevice") - .SetParent (); + .SetParent () + .AddAttribute ("Mtu", "The MAC-level Maximum Transmission Unit", + TypeId::ATTR_SET | TypeId::ATTR_GET, + UintegerValue (0xffff), + MakeUintegerAccessor (&NetDevice::SetMtu, + &NetDevice::GetMtu), + MakeUintegerChecker ()) + + ; return tid; } diff --git a/src/node/net-device.h b/src/node/net-device.h index 67fc73982..35c81f4f0 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -215,6 +215,20 @@ public: * \return whether the Send operation succeeded */ virtual bool Send(Ptr packet, const Address& dest, uint16_t protocolNumber) = 0; + /** + * \param packet packet sent from above down to Network Device + * \param source source mac address (so called "MAC spoofing") + * \param dest mac address of the destination (already resolved) + * \param protocolNumber identifies the type of payload contained in + * this packet. Used to call the right L3Protocol when the packet + * is received. + * + * Called from higher layer to send packet into Network Device + * with the specified source and destination Addresses. + * + * \return whether the Send operation succeeded + */ + virtual bool SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) = 0; /** * \returns the node base class which contains this network * interface. @@ -225,6 +239,11 @@ public: */ virtual Ptr GetNode (void) const = 0; + /** + * \param node the node associated to this netdevice. + * + * This method is called from ns3::Node::AddDevice. + */ virtual void SetNode (Ptr node) = 0; /** @@ -235,17 +254,27 @@ public: */ virtual bool NeedsArp (void) const = 0; + + /** Packet types */ + enum PacketType + { + PACKET_HOST = 1, /* To us */ + PACKET_BROADCAST, /* To all */ + PACKET_MULTICAST, /* To group */ + PACKET_OTHERHOST, /* To someone else */ + }; + /** * \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 + * \param sender the address of the sender * \returns true if the callback could handle the packet successfully, false * otherwise. */ - typedef Callback,Ptr,uint16_t,const Address &> ReceiveCallback; + typedef Callback,Ptr,uint16_t,const Address &> ReceiveCallback; /** * \param cb callback to invoke whenever a packet has been received and must @@ -254,6 +283,39 @@ public: */ virtual void SetReceiveCallback (ReceiveCallback cb) = 0; + + /** + * \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 sender the address of the sender + * \param receiver the address of the receiver + * \param packetType type of packet received (broadcast/multicast/unicast/otherhost) + * \returns true if the callback could handle the packet successfully, false + * otherwise. + */ + typedef Callback< bool, Ptr, Ptr, uint16_t, + const Address &, const Address &, enum PacketType > PromiscReceiveCallback; + + /** + * \param cb callback to invoke whenever a packet has been received in promiscuous mode and must + * be forwarded to the higher layers. + * + * Enables netdevice promiscuous mode and sets the callback that + * will handle promiscuous mode packets. Note, promiscuous mode + * packets means _all_ packets, including those packets that can be + * sensed by the netdevice but which are intended to be received by + * other hosts. + */ + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb) = 0; + + /** + * \return true if this interface supports a bridging mode, false otherwise. + */ + virtual bool SupportsSendFrom (void) const = 0; + }; } // namespace ns3 diff --git a/src/node/node-list.cc b/src/node/node-list.cc index e99a94b35..57e4dc07b 100644 --- a/src/node/node-list.cc +++ b/src/node/node-list.cc @@ -23,6 +23,7 @@ #include "ns3/object-vector.h" #include "ns3/config.h" #include "ns3/log.h" +#include "ns3/assert.h" #include "node-list.h" #include "node.h" @@ -140,6 +141,8 @@ NodeListPriv::GetNNodes (void) Ptr NodeListPriv::GetNode (uint32_t n) { + NS_ASSERT_MSG (n < m_nodes.size (), "Node index " << n << + " is out of range (only have " << m_nodes.size () << " nodes)."); return m_nodes[n]; } @@ -172,5 +175,10 @@ NodeList::GetNode (uint32_t n) { return NodeListPriv::Get ()->GetNode (n); } +uint32_t +NodeList::GetNNodes (void) +{ + return NodeListPriv::Get ()->GetNNodes (); +} }//namespace ns3 diff --git a/src/node/node-list.h b/src/node/node-list.h index 137363dff..2d74b67df 100644 --- a/src/node/node-list.h +++ b/src/node/node-list.h @@ -65,6 +65,10 @@ public: * \returns the Node associated to index n. */ static Ptr GetNode (uint32_t n); + /** + * \returns the number of nodes currently in the list. + */ + static uint32_t GetNNodes (void); }; }//namespace ns3 diff --git a/src/node/node.cc b/src/node/node.cc index ef56ec6db..9cecbab14 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -26,6 +26,10 @@ #include "ns3/simulator.h" #include "ns3/object-vector.h" #include "ns3/uinteger.h" +#include "ns3/log.h" +#include "ns3/assert.h" + +NS_LOG_COMPONENT_DEFINE ("Node"); namespace ns3{ @@ -95,13 +99,15 @@ Node::AddDevice (Ptr device) m_devices.push_back (device); device->SetNode (this); device->SetIfIndex(index); - device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this)); + device->SetReceiveCallback (MakeCallback (&Node::NonPromiscReceiveFromDevice, this)); NotifyDeviceAdded (device); return index; } Ptr Node::GetDevice (uint32_t index) const { + NS_ASSERT_MSG (index < m_devices.size (), "Device index " << index << + " is out of range (only have " << m_devices.size () << " devices)."); return m_devices[index]; } uint32_t @@ -121,6 +127,8 @@ Node::AddApplication (Ptr application) Ptr Node::GetApplication (uint32_t index) const { + NS_ASSERT_MSG (index < m_applications.size (), "Application index " << index << + " is out of range (only have " << m_applications.size () << " applications)."); return m_applications[index]; } uint32_t @@ -158,12 +166,44 @@ Node::NotifyDeviceAdded (Ptr device) void Node::RegisterProtocolHandler (ProtocolHandler handler, uint16_t protocolType, - Ptr device) + Ptr device, + bool promiscuous) { struct Node::ProtocolHandlerEntry entry; entry.handler = handler; entry.protocol = protocolType; entry.device = device; + entry.promiscuous = promiscuous; + + // On demand enable promiscuous mode in netdevices + if (promiscuous) + { + if (device == 0) + { + for (std::vector >::iterator i = m_devices.begin (); + i != m_devices.end (); i++) + { + Ptr dev = *i; + if (dev->SupportsSendFrom ()) + { + dev->SetPromiscReceiveCallback (MakeCallback (&Node::PromiscReceiveFromDevice, this)); + } + } + } + else + { + if (device->SupportsSendFrom ()) + { + device->SetPromiscReceiveCallback (MakeCallback (&Node::PromiscReceiveFromDevice, this)); + } + else + { + NS_LOG_WARN ("Protocol handler request promiscuous mode for a specific netdevice," + " but netdevice does not support promiscuous mode."); + } + } + } + m_handlers.push_back (entry); } @@ -182,14 +222,30 @@ Node::UnregisterProtocolHandler (ProtocolHandler handler) } bool -Node::ReceiveFromDevice (Ptr device, Ptr packet, - uint16_t protocol, const Address &from) +Node::PromiscReceiveFromDevice (Ptr device, Ptr packet, uint16_t protocol, + const Address &from, const Address &to, NetDevice::PacketType packetType) { + NS_LOG_FUNCTION(device->GetName ()); + return ReceiveFromDevice (device, packet, protocol, from, to, packetType, true); +} + +bool +Node::NonPromiscReceiveFromDevice (Ptr device, Ptr packet, uint16_t protocol, + const Address &from) +{ + NS_LOG_FUNCTION(device->GetName ()); + return ReceiveFromDevice (device, packet, protocol, from, from, NetDevice::PacketType (0), false); +} + +bool +Node::ReceiveFromDevice (Ptr device, Ptr packet, uint16_t protocol, + const Address &from, const Address &to, NetDevice::PacketType packetType, bool promiscuous) +{ + NS_LOG_DEBUG("Node " << GetId () << " ReceiveFromDevice: dev " + << device->GetIfIndex () << " (" + << device->GetName () << " type " << device->GetInstanceTypeId ().GetName () + << ") Packet UID " << packet->GetUid ()); bool found = false; - // if there are (potentially) multiple handlers, we need to copy the - // packet before passing it to each handler, because handlers may - // modify it. - bool copyNeeded = (m_handlers.size () > 1); for (ProtocolHandlerList::iterator i = m_handlers.begin (); i != m_handlers.end (); i++) @@ -200,8 +256,11 @@ Node::ReceiveFromDevice (Ptr device, Ptr packet, if (i->protocol == 0 || i->protocol == protocol) { - i->handler (device, (copyNeeded ? packet->Copy () : packet), protocol, from); - found = true; + if (promiscuous == i->promiscuous) + { + i->handler (device, packet, protocol, from, to, packetType); + found = true; + } } } } diff --git a/src/node/node.h b/src/node/node.h index 7ffa8e0e7..b740a175b 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -26,10 +26,10 @@ #include "ns3/object.h" #include "ns3/callback.h" #include "ns3/ptr.h" +#include "ns3/net-device.h" namespace ns3 { -class NetDevice; class Application; class Packet; class Address; @@ -90,9 +90,6 @@ public: * NetDevice. * * 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 device); /** @@ -125,6 +122,7 @@ public: * within this Node. */ Ptr GetApplication (uint32_t index) const; + /** * \returns the number of applications associated to this Node. */ @@ -132,8 +130,23 @@ public: /** * A protocol handler + * + * \param device a pointer to the net device which received the packet + * \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 sender the address of the sender + * \param receiver the address of the receiver; Note: this value is + * only valid for promiscuous mode protocol + * handlers. + * \param packetType type of packet received + * (broadcast/multicast/unicast/otherhost); Note: + * this value is only valid for promiscuous mode + * protocol handlers. */ - typedef Callback, Ptr,uint16_t,const Address &> ProtocolHandler; + typedef Callback, Ptr,uint16_t,const Address &, + const Address &, NetDevice::PacketType> ProtocolHandler; /** * \param handler the handler to register * \param protocolType the type of protocol this handler is @@ -145,10 +158,12 @@ public: * \param device the device attached to this handler. If the * value is zero, the handler is attached to all * devices on this node. + * \param promiscuous whether to register a promiscuous mode handler */ void RegisterProtocolHandler (ProtocolHandler handler, uint16_t protocolType, - Ptr device); + Ptr device, + bool promiscuous=false); /** * \param handler the handler to unregister * @@ -157,6 +172,7 @@ public: */ void UnregisterProtocolHandler (ProtocolHandler handler); + protected: /** * The dispose method. Subclasses must override this method @@ -173,14 +189,19 @@ private: */ virtual void NotifyDeviceAdded (Ptr device); - bool ReceiveFromDevice (Ptr device, Ptr, - uint16_t protocol, const Address &from); + bool NonPromiscReceiveFromDevice (Ptr device, Ptr, uint16_t protocol, const Address &from); + bool PromiscReceiveFromDevice (Ptr device, Ptr, uint16_t protocol, + const Address &from, const Address &to, NetDevice::PacketType packetType); + bool ReceiveFromDevice (Ptr device, Ptr, uint16_t protocol, + const Address &from, const Address &to, NetDevice::PacketType packetType, bool promisc); + void Construct (void); struct ProtocolHandlerEntry { ProtocolHandler handler; - uint16_t protocol; Ptr device; + uint16_t protocol; + bool promiscuous; }; typedef std::vector ProtocolHandlerList; uint32_t m_id; // Node id for this node @@ -188,6 +209,7 @@ private: std::vector > m_devices; std::vector > m_applications; ProtocolHandlerList m_handlers; + }; } //namespace ns3 diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index d4824e36c..6aef802e6 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -57,6 +57,8 @@ PacketSocket::PacketSocket () : m_rxAvailable (0) m_shutdownSend = false; m_shutdownRecv = false; m_errno = ERROR_NOTERROR; + m_isSingleDevice = false; + m_device = 0; } void @@ -184,7 +186,6 @@ PacketSocket::Close(void) return -1; } m_state = STATE_CLOSED; - NotifyCloseCompleted (); return 0; } @@ -223,14 +224,14 @@ PacketSocket::Connect(const Address &ad) return -1; } int -PacketSocket::Listen(uint32_t queueLimit) +PacketSocket::Listen(void) { m_errno = Socket::ERROR_OPNOTSUPP; return -1; } int -PacketSocket::Send (Ptr p) +PacketSocket::Send (Ptr p, uint32_t flags) { NS_LOG_FUNCTION_NOARGS (); if (m_state == STATE_OPEN || @@ -239,7 +240,7 @@ PacketSocket::Send (Ptr p) m_errno = ERROR_NOTCONN; return -1; } - return SendTo (p, m_destAddr); + return SendTo (p, flags, m_destAddr); } uint32_t @@ -275,7 +276,7 @@ PacketSocket::GetTxAvailable (void) const } int -PacketSocket::SendTo(Ptr p, const Address &address) +PacketSocket::SendTo (Ptr p, uint32_t flags, const Address &address) { NS_LOG_FUNCTION_NOARGS (); PacketSocketAddress ad; @@ -330,6 +331,7 @@ PacketSocket::SendTo(Ptr p, const Address &address) if (!error) { NotifyDataSent (p->GetSize ()); + NotifySend (GetTxAvailable ()); } if (error) @@ -345,8 +347,9 @@ PacketSocket::SendTo(Ptr p, const Address &address) } void -PacketSocket::ForwardUp (Ptr device, Ptr packet, - uint16_t protocol, const Address &from) +PacketSocket::ForwardUp (Ptr device, Ptr packet, + uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType) { NS_LOG_FUNCTION_NOARGS (); if (m_shutdownRecv) @@ -354,6 +357,7 @@ PacketSocket::ForwardUp (Ptr device, Ptr packet, return; } + PacketSocketAddress address; address.SetPhysicalAddress (from); address.SetSingleDevice (device->GetIfIndex ()); @@ -361,10 +365,10 @@ PacketSocket::ForwardUp (Ptr device, Ptr packet, if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize) { - SocketRxAddressTag tag; + SocketAddressTag tag; tag.SetAddress (address); packet->AddTag (tag); - m_deliveryQueue.push (packet); + m_deliveryQueue.push (packet->Copy ()); m_rxAvailable += packet->GetSize (); NS_LOG_LOGIC ("UID is " << packet->GetUid() << " PacketSocket " << this); NotifyDataRecv (); @@ -381,6 +385,15 @@ PacketSocket::ForwardUp (Ptr device, Ptr packet, } } +uint32_t +PacketSocket::GetRxAvailable (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + // We separately maintain this state to avoid walking the queue + // every time this might be called + return m_rxAvailable; +} + Ptr PacketSocket::Recv (uint32_t maxSize, uint32_t flags) { @@ -402,13 +415,43 @@ PacketSocket::Recv (uint32_t maxSize, uint32_t flags) return p; } -uint32_t -PacketSocket::GetRxAvailable (void) const +Ptr +PacketSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress) { NS_LOG_FUNCTION_NOARGS (); - // We separately maintain this state to avoid walking the queue - // every time this might be called - return m_rxAvailable; + Ptr packet = Recv (maxSize, flags); + if (packet != 0) + { + SocketAddressTag tag; + bool found; + found = packet->FindFirstMatchingTag (tag); + NS_ASSERT (found); + fromAddress = tag.GetAddress (); + } + return packet; +} + +int +PacketSocket::GetSockName (Address &address) const +{ + NS_LOG_FUNCTION_NOARGS (); + PacketSocketAddress ad = PacketSocketAddress::ConvertFrom(address); + + ad.SetProtocol (m_protocol); + if (m_isSingleDevice) + { + Ptr device = m_node->GetDevice (ad.GetSingleDevice ()); + ad.SetPhysicalAddress(device->GetAddress()); + ad.SetSingleDevice (m_device); + } + else + { + ad.SetPhysicalAddress(Address()); + ad.SetAllDevices (); + } + address = ad; + + return 0; } }//namespace ns3 diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h index f0647ae81..3835a7132 100644 --- a/src/node/packet-socket.h +++ b/src/node/packet-socket.h @@ -27,6 +27,7 @@ #include "ns3/traced-callback.h" #include "ns3/ptr.h" #include "ns3/socket.h" +#include "ns3/net-device.h" namespace ns3 { @@ -92,18 +93,20 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Listen(uint32_t queueLimit); - virtual int Send (Ptr p); + virtual int Listen(void); virtual uint32_t GetTxAvailable (void) const; - - virtual int SendTo(Ptr p, const Address &address); - - virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual int Send (Ptr p, uint32_t flags); + virtual int SendTo(Ptr p, uint32_t flags, const Address &toAddress); virtual uint32_t GetRxAvailable (void) const; + virtual Ptr Recv (uint32_t maxSize, uint32_t flags); + virtual Ptr RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress); + virtual int GetSockName (Address &address) const; private: - void ForwardUp (Ptr device, Ptr packet, - uint16_t protocol, const Address &from); + void ForwardUp (Ptr device, Ptr packet, + uint16_t protocol, const Address &from, const Address &to, + NetDevice::PacketType packetType); int DoBind (const PacketSocketAddress &address); uint32_t GetMinMtu (PacketSocketAddress ad) const; virtual void DoDispose (void); diff --git a/src/node/queue.cc b/src/node/queue.cc index 082641b2d..6ec837914 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -107,7 +107,7 @@ Queue::DequeueAll (void) } } -Ptr +Ptr Queue::Peek (void) const { NS_LOG_FUNCTION (this); diff --git a/src/node/queue.h b/src/node/queue.h index 5b5081fee..d12f60068 100644 --- a/src/node/queue.h +++ b/src/node/queue.h @@ -68,7 +68,7 @@ public: * Get a copy of the item at the front of the queue without removing it * \return 0 if the operation was not successful; the packet otherwise. */ - Ptr Peek (void) const; + Ptr Peek (void) const; /** * Flush the queue. @@ -142,7 +142,7 @@ private: virtual bool DoEnqueue (Ptr p) = 0; virtual Ptr DoDequeue (void) = 0; - virtual Ptr DoPeek (void) const = 0; + virtual Ptr DoPeek (void) const = 0; protected: // called by subclasses to notify parent of packet drops. diff --git a/src/node/simple-channel.cc b/src/node/simple-channel.cc index 642780370..2e51fb0f7 100644 --- a/src/node/simple-channel.cc +++ b/src/node/simple-channel.cc @@ -1,5 +1,25 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ #include "simple-channel.h" #include "simple-net-device.h" +#include "ns3/simulator.h" #include "ns3/packet.h" namespace ns3 { @@ -29,7 +49,7 @@ SimpleChannel::Send (Ptr p, uint16_t protocol, { continue; } - tmp->Receive (p->Copy (), protocol, to, from); + Simulator::ScheduleNow (&SimpleNetDevice::Receive, tmp, p->Copy (), protocol, to, from); } } diff --git a/src/node/simple-channel.h b/src/node/simple-channel.h index 4680e54ca..b75383f80 100644 --- a/src/node/simple-channel.h +++ b/src/node/simple-channel.h @@ -1,5 +1,24 @@ -#ifndef TEST_CHANNEL_H -#define TEST_CHANNEL_H +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef SIMPLE_CHANNEL_H +#define SIMPLE_CHANNEL_H #include "channel.h" #include "mac48-address.h" @@ -25,14 +44,14 @@ public: void Add (Ptr device); + // inherited from ns3::Channel virtual uint32_t GetNDevices (void) const; virtual Ptr GetDevice (uint32_t i) const; private: - std::vector > m_devices; }; } // namespace ns3 -#endif /* TEST_CHANNEL_H */ +#endif /* SIMPLE_CHANNEL_H */ diff --git a/src/node/simple-net-device.cc b/src/node/simple-net-device.cc index 50e4c3611..42004ac83 100644 --- a/src/node/simple-net-device.cc +++ b/src/node/simple-net-device.cc @@ -46,9 +46,27 @@ void SimpleNetDevice::Receive (Ptr packet, uint16_t protocol, Mac48Address to, Mac48Address from) { - if (to == m_address || to == Mac48Address::GetBroadcast ()) + NetDevice::PacketType packetType; + if (to == m_address) { - m_rxCallback (this, packet, protocol, from); + packetType = NetDevice::PACKET_HOST; + } + else if (to.IsBroadcast ()) + { + packetType = NetDevice::PACKET_HOST; + } + else if (to.IsMulticast ()) + { + packetType = NetDevice::PACKET_MULTICAST; + } + else + { + packetType = NetDevice::PACKET_OTHERHOST; + } + m_rxCallback (this, packet, protocol, from); + if (!m_promiscCallback.IsNull ()) + { + m_promiscCallback (this, packet, protocol, from, to, packetType); } } @@ -132,12 +150,12 @@ SimpleNetDevice::IsMulticast (void) const Address SimpleNetDevice::GetMulticast (void) const { - return Mac48Address ("01:00:5e:00:00:00"); + return Mac48Address::GetMulticastPrefix (); } Address SimpleNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const { - return Mac48Address ("01:00:5e:00:00:00"); + return Mac48Address::GetMulticast (multicastGroup); } bool SimpleNetDevice::IsPointToPoint (void) const @@ -151,6 +169,15 @@ SimpleNetDevice::Send(Ptr packet, const Address& dest, uint16_t protocol m_channel->Send (packet, protocolNumber, to, m_address, this); return true; } +bool +SimpleNetDevice::SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) +{ + Mac48Address to = Mac48Address::ConvertFrom (dest); + Mac48Address from = Mac48Address::ConvertFrom (source); + m_channel->Send (packet, protocolNumber, to, from, this); + return true; +} + Ptr SimpleNetDevice::GetNode (void) const { @@ -181,5 +208,16 @@ SimpleNetDevice::DoDispose (void) } +void +SimpleNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb) +{ + m_promiscCallback = cb; +} + +bool +SimpleNetDevice::SupportsSendFrom (void) const +{ + return true; +} } // namespace ns3 diff --git a/src/node/simple-net-device.h b/src/node/simple-net-device.h index 19ce5ef3a..208080b2b 100644 --- a/src/node/simple-net-device.h +++ b/src/node/simple-net-device.h @@ -63,16 +63,20 @@ public: virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const; virtual bool IsPointToPoint (void) const; virtual bool Send(Ptr packet, const Address& dest, uint16_t protocolNumber); + virtual bool SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); virtual Ptr GetNode (void) const; virtual void SetNode (Ptr node); virtual bool NeedsArp (void) const; virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb); + virtual bool SupportsSendFrom (void) const; protected: virtual void DoDispose (void); private: Ptr m_channel; NetDevice::ReceiveCallback m_rxCallback; + NetDevice::PromiscReceiveCallback m_promiscCallback; Ptr m_node; uint16_t m_mtu; std::string m_name; diff --git a/src/node/socket.cc b/src/node/socket.cc index 0bdc167a0..c7f9511e5 100644 --- a/src/node/socket.cc +++ b/src/node/socket.cc @@ -25,6 +25,7 @@ #include "node.h" #include "socket.h" #include "socket-factory.h" +#include NS_LOG_COMPONENT_DEFINE ("Socket"); @@ -40,13 +41,6 @@ Socket::~Socket () NS_LOG_FUNCTION_NOARGS (); } -void -Socket::SetCloseUnblocksCallback (Callback > closeUnblocks) -{ - NS_LOG_FUNCTION_NOARGS (); - m_closeUnblocks = closeUnblocks; -} - Ptr Socket::CreateSocket (Ptr node, TypeId tid) { @@ -57,43 +51,31 @@ Socket::CreateSocket (Ptr node, TypeId tid) return s; } -void -Socket::SetCloseCallback (Callback > closeCompleted) -{ - NS_LOG_FUNCTION_NOARGS (); - m_closeCompleted = closeCompleted; -} - void Socket::SetConnectCallback ( Callback > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose) + Callback > connectionFailed) { NS_LOG_FUNCTION_NOARGS (); m_connectionSucceeded = connectionSucceeded; m_connectionFailed = connectionFailed; - m_halfClose = halfClose; } void Socket::SetAcceptCallback ( Callback, const Address &> connectionRequest, - Callback, const Address&> newConnectionCreated, - Callback > closeRequested) + Callback, const Address&> newConnectionCreated) { NS_LOG_FUNCTION_NOARGS (); m_connectionRequest = connectionRequest; m_newConnectionCreated = newConnectionCreated; - m_closeRequested = closeRequested; } -bool +void Socket::SetDataSentCallback (Callback, uint32_t> dataSent) { NS_LOG_FUNCTION_NOARGS (); m_dataSent = dataSent; - return true; } void @@ -110,22 +92,15 @@ Socket::SetRecvCallback (Callback > receivedData) m_receivedData = receivedData; } -void -Socket::NotifyCloseUnblocks (void) +int +Socket::Send (Ptr p) { NS_LOG_FUNCTION_NOARGS (); - if (!m_closeUnblocks.IsNull ()) - { - m_closeUnblocks (this); - } + return Send (p, 0); } -int Socket::Listen (uint32_t queueLimit) -{ - return 0; //XXX the base class version does nothing -} - -int Socket::Send (const uint8_t* buf, uint32_t size) +int +Socket::Send (const uint8_t* buf, uint32_t size, uint32_t flags) { NS_LOG_FUNCTION_NOARGS (); Ptr p; @@ -137,24 +112,12 @@ int Socket::Send (const uint8_t* buf, uint32_t size) { p = Create (size); } - return Send (p); -} - -Ptr -Socket::Recv (void) -{ - return Recv (std::numeric_limits::max(), 0); + return Send (p, flags); } int -Socket::Recv (uint8_t* buf, uint32_t size, uint32_t flags) -{ - Ptr p = Recv (size, flags); // read up to "size" bytes - memcpy (buf, p->PeekData (), p->GetSize()); - return p->GetSize (); -} - -int Socket::SendTo (const uint8_t* buf, uint32_t size, const Address &address) +Socket::SendTo (const uint8_t* buf, uint32_t size, uint32_t flags, + const Address &toAddress) { NS_LOG_FUNCTION_NOARGS (); Ptr p; @@ -166,19 +129,51 @@ int Socket::SendTo (const uint8_t* buf, uint32_t size, const Address &address) { p = Create (size); } - return SendTo (p, address); + return SendTo (p, flags, toAddress); } -void -Socket::NotifyCloseCompleted (void) +Ptr +Socket::Recv (void) { NS_LOG_FUNCTION_NOARGS (); - if (!m_closeCompleted.IsNull ()) - { - m_closeCompleted (this); - } + return Recv (std::numeric_limits::max(), 0); } +int +Socket::Recv (uint8_t* buf, uint32_t size, uint32_t flags) +{ + NS_LOG_FUNCTION_NOARGS (); + Ptr p = Recv (size, flags); // read up to "size" bytes + if (p == 0) + { + return 0; + } + memcpy (buf, p->PeekData (), p->GetSize()); + return p->GetSize (); +} + +Ptr +Socket::RecvFrom (Address &fromAddress) +{ + NS_LOG_FUNCTION_NOARGS (); + return RecvFrom (std::numeric_limits::max(), 0, fromAddress); +} + +int +Socket::RecvFrom (uint8_t* buf, uint32_t size, uint32_t flags, + Address &fromAddress) +{ + NS_LOG_FUNCTION_NOARGS (); + Ptr p = RecvFrom (size, flags, fromAddress); + if (p == 0) + { + return 0; + } + memcpy (buf, p->PeekData (), p->GetSize()); + return p->GetSize (); +} + + void Socket::NotifyConnectionSucceeded (void) { @@ -199,16 +194,6 @@ Socket::NotifyConnectionFailed (void) } } -void -Socket::NotifyHalfClose (void) -{ - NS_LOG_FUNCTION_NOARGS (); - if (!m_halfClose.IsNull ()) - { - m_halfClose (this); - } -} - bool Socket::NotifyConnectionRequest (const Address &from) { @@ -237,16 +222,6 @@ Socket::NotifyNewConnectionCreated (Ptr socket, const Address &from) } } -void -Socket::NotifyCloseRequested (void) -{ - NS_LOG_FUNCTION_NOARGS (); - if (!m_closeRequested.IsNull ()) - { - m_closeRequested (this); - } -} - void Socket::NotifyDataSent (uint32_t size) { @@ -281,54 +256,54 @@ Socket::NotifyDataRecv (void) * Socket Tags ***************************************************************/ -SocketRxAddressTag::SocketRxAddressTag () +SocketAddressTag::SocketAddressTag () { } void -SocketRxAddressTag::SetAddress (Address addr) +SocketAddressTag::SetAddress (Address addr) { m_address = addr; } Address -SocketRxAddressTag::GetAddress (void) const +SocketAddressTag::GetAddress (void) const { return m_address; } TypeId -SocketRxAddressTag::GetTypeId (void) +SocketAddressTag::GetTypeId (void) { - static TypeId tid = TypeId ("ns3::SocketRxAddressTag") + static TypeId tid = TypeId ("ns3::SocketAddressTag") .SetParent () - .AddConstructor () + .AddConstructor () ; return tid; } TypeId -SocketRxAddressTag::GetInstanceTypeId (void) const +SocketAddressTag::GetInstanceTypeId (void) const { return GetTypeId (); } uint32_t -SocketRxAddressTag::GetSerializedSize (void) const +SocketAddressTag::GetSerializedSize (void) const { return m_address.GetSerializedSize (); } void -SocketRxAddressTag::Serialize (TagBuffer i) const +SocketAddressTag::Serialize (TagBuffer i) const { m_address.Serialize (i); } void -SocketRxAddressTag::Deserialize (TagBuffer i) +SocketAddressTag::Deserialize (TagBuffer i) { m_address.Deserialize (i); } void -SocketRxAddressTag::Print (std::ostream &os) const +SocketAddressTag::Print (std::ostream &os) const { os << "address=" << m_address; } @@ -386,4 +361,5 @@ SocketIpTtlTag::Print (std::ostream &os) const os << "Ttl=" << (uint32_t) m_ttl; } + }//namespace ns3 diff --git a/src/node/socket.h b/src/node/socket.h index 34e018743..6287895a4 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -92,27 +92,16 @@ public: * \param tid The TypeId of the socket to create */ static Ptr CreateSocket (Ptr node, TypeId tid); - /** * \return the errno associated to the last call which failed in this * socket. Each socket's errno is initialized to zero * when the socket is created. */ virtual enum Socket::SocketErrno GetErrno (void) const = 0; - /** * \returns the node this socket is associated with. */ virtual Ptr GetNode (void) const = 0; - - void SetCloseUnblocksCallback (Callback > closeUnblocks); - - /** - * \param closeCompleted Callback invoked when the close operation is - * completed. - */ - void SetCloseCallback (Callback > closeCompleted); - /** * \param connectionSucceeded this callback is invoked when the * connection request initiated by the user is successfully @@ -122,13 +111,9 @@ public: * 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 > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose); + Callback > connectionFailed); /** * \brief Accept connection requests from remote hosts * \param connectionRequest Callback for connection request from peer. @@ -145,27 +130,20 @@ public: * 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, const Address &> connectionRequest, Callback, - const Address&> newConnectionCreated, - Callback > closeRequested); + const Address&> newConnectionCreated); /** * \brief Notify application when a packet has been sent from transport * protocol (non-standard socket call) * \param dataSent Callback for the event that data is sent from the * underlying transport protocol. This callback is passed a * pointer to the socket, and the number of bytes sent. - * \returns whether or not this socket supports this callback. Note - * that this is a non-standard socket call. Some socket - * implementations in ns-3 may not support this call, so the - * user should check this return value to confirm that the - * callback is supported. */ - virtual bool SetDataSentCallback (Callback, uint32_t> dataSent); + void SetDataSentCallback (Callback, + uint32_t> dataSent); /** * \brief Notify application when space in transmit buffer is added * @@ -239,15 +217,29 @@ public: * \param queueLimit maximum number of incoming request to queue * \returns 0 on success, -1 on error (in which case errno is set). */ - virtual int Listen (uint32_t queueLimit) = 0; + virtual int Listen (void) = 0; + /** + * \brief Returns the number of bytes which can be sent in a single call + * to Send. + * + * For datagram sockets, this returns the number of bytes that + * can be passed atomically through the underlying protocol. + * + * For stream sockets, this returns the available space in bytes + * left in the transmit buffer. + */ + virtual uint32_t GetTxAvailable (void) const = 0; + /** * \brief Send data (or dummy data) to the remote host * * This function matches closely in semantics to the send() function * call in the standard C library (libc): * ssize_t send (int s, const void *msg, size_t len, int flags); - * except that the function call is asynchronous. + * except that the send I/O is asynchronous. This is the + * primary Send method at this low-level API and must be implemented + * by subclasses. * * In a typical blocking sockets model, this call would block upon * lack of space to hold the message to be sent. In ns-3 at this @@ -272,116 +264,245 @@ public: * split the Packet (based on information obtained from * GetTxAvailable) and reattempt to send the data. * + * The flags argument is formed by or'ing one or more of the values: + * MSG_OOB process out-of-band data + * MSG_DONTROUTE bypass routing, use direct interface + * These flags are _unsupported_ as of ns-3.1. + * * \param p ns3::Packet to send + * \param flags Socket control flags * \returns the number of bytes accepted for transmission if no error * occurs, and -1 otherwise. - */ - virtual int Send (Ptr p) = 0; - - /** - * \brief Returns the number of bytes which can be sent in a single call - * to Send. - * - * For datagram sockets, this returns the number of bytes that - * can be passed atomically through the underlying protocol. * - * For stream sockets, this returns the available space in bytes - * left in the transmit buffer. + * \see SetSendCallback */ - virtual uint32_t GetTxAvailable (void) const = 0; + virtual int Send (Ptr p, uint32_t flags) = 0; - /** - * \brief Send data (or dummy data) to the remote host - * \param buf A pointer to a raw byte buffer of some data to send. If this - * is 0, we send dummy data whose size is specified by the second parameter - * \param size the number of bytes to copy from the buffer - * - * This is provided so as to have an API which is closer in appearance - * to that of real network or BSD sockets. - */ - int Send (const uint8_t* buf, uint32_t size); - /** * \brief Send data to a specified peer. + * + * This method has similar semantics to Send () but subclasses may + * want to provide checks on socket state, so the implementation is + * pushed to subclasses. + * * \param p packet to send - * \param address IP Address of remote host + * \param flags Socket control flags + * \param toAddress IP Address of remote host * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int SendTo (Ptr p, const Address &address) = 0; + virtual int SendTo (Ptr p, uint32_t flags, + const Address &toAddress) = 0; - /** - * \brief Send data to a specified peer. - * \param buf A pointer to a raw byte buffer of some data to send. If this - * is 0, we send dummy data whose size is specified by the third parameter - * \param size the number of bytes to copy from the buffer - * \param address IP Address of remote host - * \returns -1 in case of error or the number of bytes copied in the - * internal buffer and accepted for transmission. - * - * This is provided so as to have an API which is closer in appearance - * to that of real network or BSD sockets. - */ - int SendTo (const uint8_t* buf, uint32_t size, const Address &address); - - /** - * \brief Read a single packet from the socket - * \param maxSize reader will accept packet up to maxSize - * \param flags Socket recv flags - * \returns Ptr of the next in-sequence packet. Returns - * 0 if the socket cannot return a next in-sequence packet conforming - * to the maxSize and flags. - */ - virtual Ptr Recv (uint32_t maxSize, uint32_t flags) = 0; - /** - * \brief Read a single packet from the socket - * - * Overloaded version of Recv(maxSize, flags) with maxSize - * implicitly set to maximum sized integer, and flags set to zero. - * - * \returns Ptr of the next in-sequence packet. Returns - * 0 if the socket cannot return a next in-sequence packet. - */ - Ptr Recv (void); - /** - * \brief Recv data (or dummy data) from the remote host - * \param buf A pointer to a raw byte buffer to write the data to. - * If the underlying packet was carring null (fake) data, this buffer - * will be zeroed up to the length specified by the return value. - * \param size Number of bytes (at most) to copy to buf - * \param flags any flags to pass to the socket - * \returns number of bytes copied into buf - * - * This is provided so as to have an API which is closer in appearance - * to that of real network or BSD sockets. - */ - int Recv (uint8_t* buf, uint32_t size, uint32_t flags); /** * Return number of bytes which can be returned from one or * multiple calls to Recv. * Must be possible to call this method from the Recv callback. */ virtual uint32_t GetRxAvailable (void) const = 0; + + /** + * \brief Read data from the socket + * + * This function matches closely in semantics to the recv() function + * call in the standard C library (libc): + * ssize_t recv (int s, void *buf, size_t len, int flags); + * except that the receive I/O is asynchronous. This is the + * primary Recv method at this low-level API and must be implemented + * by subclasses. + * + * This method is normally used only on a connected socket. + * In a typical blocking sockets model, this call would block until + * at least one byte is returned or the connection closes. + * In ns-3 at this API, the call returns immediately in such a case + * and returns 0 if nothing is available to be read. + * However, an application can set a callback, ns3::SetRecvCallback, + * to be notified of data being available to be read + * (when it conceptually unblocks); this is an asynchronous + * I/O model for recv(). + * + * This variant of Recv() uses class ns3::Packet to encapsulate + * data, rather than providing a raw pointer and length field. + * This allows an ns-3 application to attach tags if desired (such + * as a flow ID) and may allow the simulator to avoid some data + * copies. Despite the appearance of receiving Packets on a stream + * socket, just think of it as a fancy byte buffer with streaming + * semantics. + * + * The semantics depend on the type of socket. For a datagram socket, + * each Recv() returns the data from at most one Send(), and order + * is not necessarily preserved. For a stream socket, the bytes + * are delivered in order, and on-the-wire packet boundaries are + * not preserved. + * + * The flags argument is formed by or'ing one or more of the values: + * MSG_OOB process out-of-band data + * MSG_PEEK peek at incoming message + * These flags are _unsupported_ as of ns-3.1. + * + * Some variants of Recv() are supported as additional API, + * including RecvFrom(), overloaded Recv() without arguments, + * and variants that use raw character buffers. + * + * \param maxSize reader will accept packet up to maxSize + * \param flags Socket control flags + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet conforming + * to the maxSize and flags. + * + * \see SetRecvCallback + */ + virtual Ptr Recv (uint32_t maxSize, uint32_t flags) = 0; + + /** + * \brief Read a single packet from the socket and retrieve the sender + * address. + * + * Calls Recv(maxSize, flags) with maxSize + * implicitly set to maximum sized integer, and flags set to zero. + * + * This method has similar semantics to Recv () but subclasses may + * want to provide checks on socket state, so the implementation is + * pushed to subclasses. + * + * \param maxSize reader will accept packet up to maxSize + * \param flags Socket control flags + * \param fromAddress output parameter that will return the + * address of the sender of the received packet, if any. Remains + * untouched if no packet is received. + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet. + */ + virtual Ptr RecvFrom (uint32_t maxSize, uint32_t flags, + Address &fromAddress) = 0; + + ///////////////////////////////////////////////////////////////////// + // The remainder of these public methods are overloaded methods // + // or variants of Send() and Recv(), and they are non-virtual // + ///////////////////////////////////////////////////////////////////// + + /** + * \brief Send data (or dummy data) to the remote host + * + * Overloaded version of Send(..., flags) with flags set to zero. + * + * \param p ns3::Packet to send + * \returns the number of bytes accepted for transmission if no error + * occurs, and -1 otherwise. + */ + int Send (Ptr p); + + /** + * \brief Send data (or dummy data) to the remote host + * + * This method is provided so as to have an API which is closer in + * appearance to that of real network or BSD sockets. + * + * \param buf A pointer to a raw byte buffer of some data to send. If + * this buffer is 0, we send dummy data whose size is specified by the + * second parameter + * \param size the number of bytes to copy from the buffer + * \param flags Socket control flags + */ + int Send (const uint8_t* buf, uint32_t size, uint32_t flags); + + + /** + * \brief Send data to a specified peer. + * + * This method is provided so as to have an API which is closer in + * appearance to that of real network or BSD sockets. + * + * \param buf A pointer to a raw byte buffer of some data to send. + * If this is 0, we send dummy data whose size is specified by the + * third parameter + * \param size the number of bytes to copy from the buffer + * \param flags Socket control flags + * \param address IP Address of remote host + * \returns -1 in case of error or the number of bytes copied in the + * internal buffer and accepted for transmission. + * + */ + int SendTo (const uint8_t* buf, uint32_t size, uint32_t flags, + const Address &address); + + /** + * \brief Read a single packet from the socket + * + * Overloaded version of Recv(maxSize, flags) with maxSize + * implicitly set to maximum sized integer, and flags set to zero. + * + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet. + */ + Ptr Recv (void); + + /** + * \brief Recv data (or dummy data) from the remote host + * + * This method is provided so as to have an API which is closer in + * appearance to that of real network or BSD sockets. + * + * If the underlying packet was carring null (fake) data, this buffer + * will be zeroed up to the length specified by the return value. + * + * \param buf A pointer to a raw byte buffer to write the data to. + * \param size Number of bytes (at most) to copy to buf + * \param flags any flags to pass to the socket + * \returns number of bytes copied into buf + */ + int Recv (uint8_t* buf, uint32_t size, uint32_t flags); + + /** + * \brief Read a single packet from the socket and retrieve the sender + * address. + * + * Calls RecvFrom (maxSize, flags, fromAddress) with maxSize + * implicitly set to maximum sized integer, and flags set to zero. + * + * \param fromAddress output parameter that will return the + * address of the sender of the received packet, if any. Remains + * untouched if no packet is received. + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet. + */ + Ptr RecvFrom (Address &fromAddress); + + /** + * \brief Read a single packet from the socket and retrieve the sender + * address. + * + * This method is provided so as to have an API which is closer in + * appearance to that of real network or BSD sockets. + * + * \param buf A pointer to a raw byte buffer to write the data to. + * If the underlying packet was carring null (fake) data, this buffer + * will be zeroed up to the length specified by the return value. + * \param size Number of bytes (at most) to copy to buf + * \param flags any flags to pass to the socket + * \param fromAddress output parameter that will return the + * address of the sender of the received packet, if any. Remains + * untouched if no packet is received. + * \returns number of bytes copied into buf + */ + int RecvFrom (uint8_t* buf, uint32_t size, uint32_t flags, + Address &fromAddress); + /** + * \returns the address name this socket is associated with. + */ + virtual int GetSockName (Address &address) const = 0; protected: - void NotifyCloseUnblocks (void); - void NotifyCloseCompleted (void); void NotifyConnectionSucceeded (void); void NotifyConnectionFailed (void); - void NotifyHalfClose (void); bool NotifyConnectionRequest (const Address &from); void NotifyNewConnectionCreated (Ptr socket, const Address &from); - void NotifyCloseRequested (void); void NotifyDataSent (uint32_t size); void NotifySend (uint32_t spaceAvailable); void NotifyDataRecv (void); - - Callback > m_closeUnblocks; - Callback > m_closeCompleted; +private: Callback > m_connectionSucceeded; Callback > m_connectionFailed; - Callback > m_halfClose; - Callback > m_closeRequested; Callback, const Address &> m_connectionRequest; Callback, const Address&> m_newConnectionCreated; Callback, uint32_t> m_dataSent; @@ -391,13 +512,13 @@ protected: }; /** - * \brief This class implements a tag that carries the source address - * of a packet across the receiving socket interface. + * \brief This class implements a tag that carries an address + * of a packet across the socket interface. */ -class SocketRxAddressTag : public Tag +class SocketAddressTag : public Tag { public: - SocketRxAddressTag (); + SocketAddressTag (); void SetAddress (Address addr); Address GetAddress (void) const; diff --git a/src/node/tcp-socket-factory.h b/src/node/tcp-socket-factory.h index 92cede256..418bafde6 100644 --- a/src/node/tcp-socket-factory.h +++ b/src/node/tcp-socket-factory.h @@ -48,8 +48,6 @@ class TcpSocketFactory : public SocketFactory public: static TypeId GetTypeId (void); - virtual Ptr CreateSocket (void) = 0; - }; } // namespace ns3 diff --git a/src/node/tcp-socket.cc b/src/node/tcp-socket.cc index 1dd3d4057..2ba8195ba 100644 --- a/src/node/tcp-socket.cc +++ b/src/node/tcp-socket.cc @@ -55,12 +55,6 @@ TcpSocket::GetTypeId (void) MakeUintegerAccessor (&TcpSocket::GetSegSize, &TcpSocket::SetSegSize), MakeUintegerChecker ()) - .AddAttribute ("AdvertisedWindowSize", - "TCP advertised window size (bytes)", - UintegerValue (0xffff), - MakeUintegerAccessor (&TcpSocket::GetAdvWin, - &TcpSocket::SetAdvWin), - MakeUintegerChecker ()) .AddAttribute ("SlowStartThreshold", "TCP slow start threshold (bytes)", UintegerValue (0xffff), diff --git a/src/node/tcp-socket.h b/src/node/tcp-socket.h index 14ef39c5d..5c443f442 100644 --- a/src/node/tcp-socket.h +++ b/src/node/tcp-socket.h @@ -51,19 +51,6 @@ public: TcpSocket (void); virtual ~TcpSocket (void); - virtual enum Socket::SocketErrno GetErrno (void) const = 0; - virtual Ptr GetNode (void) const = 0; - virtual int Bind () = 0; - virtual int Close (void) = 0; - virtual int ShutdownSend (void) = 0; - virtual int ShutdownRecv (void) = 0; - virtual int Connect (const Address &address) = 0; - virtual int Send (Ptr p) = 0; - virtual uint32_t GetTxAvailable (void) const = 0; - virtual int SendTo (Ptr p, const Address &address) = 0; - virtual Ptr Recv (uint32_t maxSize, uint32_t flags) = 0; - virtual uint32_t GetRxAvailable (void) const = 0; - private: // Indirect the attribute setting and getting through private virtual methods virtual void SetSndBufSize (uint32_t size) = 0; @@ -72,8 +59,6 @@ private: virtual uint32_t GetRcvBufSize (void) const = 0; virtual void SetSegSize (uint32_t size) = 0; virtual uint32_t GetSegSize (void) const = 0; - virtual void SetAdvWin (uint32_t window) = 0; - virtual uint32_t GetAdvWin (void) const = 0; virtual void SetSSThresh (uint32_t threshold) = 0; virtual uint32_t GetSSThresh (void) const = 0; virtual void SetInitialCwnd (uint32_t count) = 0; diff --git a/src/node/udp-socket-factory.h b/src/node/udp-socket-factory.h index 4e2b74354..ff8309b4e 100644 --- a/src/node/udp-socket-factory.h +++ b/src/node/udp-socket-factory.h @@ -42,14 +42,6 @@ class UdpSocketFactory : public SocketFactory public: static TypeId GetTypeId (void); - /** - * \return smart pointer to Socket - * - * API for creating socket instances; must be implemented by UDP - * implementations.. - */ - virtual Ptr CreateSocket (void) = 0; - }; } // namespace ns3 diff --git a/src/node/udp-socket.h b/src/node/udp-socket.h index 61d3d2685..afe17774e 100644 --- a/src/node/udp-socket.h +++ b/src/node/udp-socket.h @@ -50,19 +50,6 @@ public: UdpSocket (void); virtual ~UdpSocket (void); - virtual enum Socket::SocketErrno GetErrno (void) const = 0; - virtual Ptr GetNode (void) const = 0; - virtual int Bind () = 0; - virtual int Close (void) = 0; - virtual int ShutdownSend (void) = 0; - virtual int ShutdownRecv (void) = 0; - virtual int Connect (const Address &address) = 0; - virtual int Send (Ptr p) = 0; - virtual uint32_t GetTxAvailable (void) const = 0; - virtual int SendTo (Ptr p, const Address &address) = 0; - virtual Ptr Recv (uint32_t maxSize, uint32_t flags) = 0; - virtual uint32_t GetRxAvailable (void) const = 0; - private: // Indirect the attribute setting and getting through private virtual methods virtual void SetRcvBufSize (uint32_t size) = 0; diff --git a/src/routing/global-routing/candidate-queue.h b/src/routing/global-routing/candidate-queue.h index 35747ec9f..c8b900e44 100644 --- a/src/routing/global-routing/candidate-queue.h +++ b/src/routing/global-routing/candidate-queue.h @@ -162,10 +162,6 @@ public: */ void Reorder (void); -protected: - typedef std::list CandidateList_t; - CandidateList_t m_candidates; - private: /** * Candidate Queue copy construction is disallowed (not implemented) to @@ -180,6 +176,9 @@ private: * properly deal with deep copies. */ CandidateQueue& operator= (CandidateQueue& sr); + + typedef std::list CandidateList_t; + CandidateList_t m_candidates; }; } // namespace ns3 diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index bf40994b0..8230c2a7f 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -1425,6 +1425,7 @@ GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v) #include "ns3/test.h" #include "ns3/simulator.h" +#include // for rand () namespace ns3 { diff --git a/src/routing/global-routing/global-routing.h b/src/routing/global-routing/global-routing.h new file mode 100644 index 000000000..ad9851505 --- /dev/null +++ b/src/routing/global-routing/global-routing.h @@ -0,0 +1,79 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright 2008 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; + * + * 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 + * + */ + +/** + * \ingroup routing + * \defgroup globalrouting Global Routing + * + * \section model Model + * + * ns-3 global routing performs pre-simulation static route computation + * on a layer-3 Ipv4 topology. The user API from the script level is + * fairly minimal; once a topology has been constructed and addresses + * assigned, the user may call ns3::GlobalRouteManager::PopulateRoutingTables() + * and the simulator will initialize the routing database and set up + * static unicast forwarding tables for each node. + * + * The model assumes that all nodes on an ns-3 channel are reachable to + * one another, regardless of whether the nodes can use the channel + * successfully (in the case of wireless). Therefore, this model + * should typically be used only on wired topologies. API does not + * yet exist to control the subset of a topology to which this global + * static routing is applied. + * + * This model also does not yet deal with the possible presence of + * layer-2 relays such as switches, bridges, and hubs, although ns-3 does + * not have such devices yet. + * + * \section api API and Usage + * + * Users must include ns3/global-route-manager.h header file. After the + * IPv4 topology has been built and addresses assigned, users call + * ns3::GlobalRouteManager::PopulateRoutingTables (), prior to the + * ns3::Simulator::Run() call. There are no other attributes or + * public methods that are typically called, or ways to parameterize + * the behavior. + * + * \section impl Implementation + * + * A singleton object, ns3::GlobalRouteManager, builds a global routing + * database of information about the topology, and executes a Dijkstra + * Shortest Path First (SPF) algorithm on the topology for each node, and + * stores the computed routes in each node's IPv4 forwarding table by + * making use of the routing API in class ns3::Ipv4. + * + * The nodes that export data are those that have had an ns3::GlobalRouter + * object aggregated to them. The ns3::GlobalRouter can be thought of + * as a per-node agent that exports topology information to the + * ns3::GlobalRouteManager. When it comes time to build the global + * routing database, the list of nodes is iterated and each node with + * an ns3::GlobalRouter object is asked to export routing information + * concerning the links to which it is attached. + * + * The format of the data exported conforms to the OSPFv2 standard + * (http://www.ietf.org/rfc/rfc2328.txt). In particular, the + * information is exported in the form of ns3::GlobalLSA objects that + * semantically match the Link State Advertisements of OSPF. + * + * By using a standard data format for reporting topology, existing + * OSPF route computation code can be reused, and that is what is done + * by the ns3::GlobalRouteManager. The main computation functions are + * ported from the quagga routing suite (http://www.quagga.net). + * + */ diff --git a/src/routing/global-routing/wscript b/src/routing/global-routing/wscript index b2758cc54..17816ade1 100644 --- a/src/routing/global-routing/wscript +++ b/src/routing/global-routing/wscript @@ -13,6 +13,5 @@ def build(bld): headers.source = [ 'global-router-interface.h', 'global-route-manager.h', - 'candidate-queue.h', ] diff --git a/src/routing/olsr/olsr-agent-impl.cc b/src/routing/olsr/olsr-agent-impl.cc index b9a9ea7e4..942ae8181 100644 --- a/src/routing/olsr/olsr-agent-impl.cc +++ b/src/routing/olsr/olsr-agent-impl.cc @@ -303,13 +303,8 @@ void AgentImpl::RecvOlsr (Ptr socket) { Ptr receivedPacket; - receivedPacket = socket->Recv (); - - SocketRxAddressTag tag; - bool found; - found = receivedPacket->FindFirstMatchingTag (tag); - NS_ASSERT (found); - Address sourceAddress = tag.GetAddress (); + Address sourceAddress; + receivedPacket = socket->RecvFrom (sourceAddress); InetSocketAddress inetSourceAddr = InetSocketAddress::ConvertFrom (sourceAddress); Ipv4Address senderIfaceAddr = inetSourceAddr.GetIpv4 (); @@ -1393,7 +1388,7 @@ AgentImpl::SendHello () msg.SetMessageSequenceNumber (GetMessageSequenceNumber ()); olsr::MessageHeader::Hello &hello = msg.GetHello (); - hello.SetHTime (m_helloInterval); + hello.SetHTime (Scalar (3) * m_helloInterval); hello.willingness = m_willingness; std::vector diff --git a/src/routing/olsr/olsr.h b/src/routing/olsr/olsr.h index 1ba19c02d..f2dbb7830 100644 --- a/src/routing/olsr/olsr.h +++ b/src/routing/olsr/olsr.h @@ -21,46 +21,39 @@ #ifndef OLSR_H #define OLSR_H -#include "ns3/node-list.h" - -namespace ns3 -{ - /** - * \namespace ns3::olsr - * \brief Includes a set of utility functions to enable OLSR on - * certain nodes with default parameters. For finer grained control - * of OLSR parameters, see OlsrAgent. - */ - namespace olsr - { - /// \brief Start the OLSR routing agent on all nodes - void EnableAllNodes (void); - - /// \brief Start the OLSR routing agent on a given list of nodes - template - void EnableNodes (InputIterator begin, InputIterator end); - - /// \brief Start the OLSR routing agent on the given node - void EnableNode (Ptr node); - } -} - - -// implementation -namespace ns3 -{ - namespace olsr - { - template - void EnableNodes (InputIterator begin, InputIterator end) - { - for (InputIterator i = begin; i != end; i++) - { - EnableNode (*i); - } - } - } -} +/** + * \ingroup routing + * \defgroup olsr OLSR + * + * \section model Model + * + * This model implements the base specification of the Optimized + * Link State Routing (OLSR) protocol, which is a dynamic mobile ad hoc + * unicast routing protocol. It has been developed at the + * University of Murcia (Spain) by Francisco J. Ros for NS-2, and was + * ported to NS-3 by Gustavo Carneiro at INESC Porto (Portugal). + * + * Here is a summary of software's main features: + * - Mostly compliant with OLSR as documented in RFC 3626 (http://www.ietf.org/rfc/rfc3626.txt), with the following differences: + * - The use of multiple interfaces was not supported by the NS-2 version, but is supported in NS-3; + * - Unlike the NS-2 version, does not yet support MAC layer feedback as described in RFC 3626; + * - HNA (Host/Network Association) messages are almost-but-not-quite supported in this version. + * + * \section api API and Usage + * + * A helper class for OLSR has been written. After an IPv4 topology + * has been created and unique IP addresses assigned to each node, the + * simulation script writer can call one of three overloaded functions + * with different scope to enable OLSR: ns3::OlsrHelper::Install + * (NodeContainer container); ns3::OlsrHelper::Install (Ptr + * node); or ns3::OlsrHelper::InstallAll (void); + * + * In addition, the behavior of OLSR can be modified by changing certain + * attributes. The method ns3::OlsrHelper::SetAgent () can be used + * to set OLSR attributes. These include HelloInterval, TcInterval, + * MidInterval, Willingness. Other parameters are defined as macros + * in olsr-agent-impl.cc. + */ #endif /* OLSR_H */ diff --git a/src/simulator/default-simulator-impl.cc b/src/simulator/default-simulator-impl.cc new file mode 100644 index 000000000..d5afd743a --- /dev/null +++ b/src/simulator/default-simulator-impl.cc @@ -0,0 +1,321 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 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 + */ + +#include "simulator.h" +#include "default-simulator-impl.h" +#include "scheduler.h" +#include "event-impl.h" + +#include "ns3/ptr.h" +#include "ns3/pointer.h" +#include "ns3/assert.h" +#include "ns3/log.h" + +#include + +NS_LOG_COMPONENT_DEFINE ("DefaultSimulatorImpl"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (DefaultSimulatorImpl); + +TypeId +DefaultSimulatorImpl::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl") + .SetParent () + .AddConstructor () + ; + return tid; +} + +DefaultSimulatorImpl::DefaultSimulatorImpl () +{ + m_stop = false; + m_stopAt = 0; + // uids are allocated from 4. + // uid 0 is "invalid" events + // uid 1 is "now" events + // uid 2 is "destroy" events + m_uid = 4; + // before ::Run is entered, the m_currentUid will be zero + m_currentUid = 0; + m_currentTs = 0; + m_unscheduledEvents = 0; +} + +DefaultSimulatorImpl::~DefaultSimulatorImpl () +{ + while (!m_events->IsEmpty ()) + { + Scheduler::Event next = m_events->RemoveNext (); + next.impl->Unref (); + } + m_events = 0; +} + +void +DefaultSimulatorImpl::Destroy () +{ + while (!m_destroyEvents.empty ()) + { + Ptr ev = m_destroyEvents.front ().PeekEventImpl (); + m_destroyEvents.pop_front (); + NS_LOG_LOGIC ("handle destroy " << ev); + if (!ev->IsCancelled ()) + { + ev->Invoke (); + } + } +} + +void +DefaultSimulatorImpl::SetScheduler (Ptr scheduler) +{ + if (m_events != 0) + { + while (!m_events->IsEmpty ()) + { + Scheduler::Event next = m_events->RemoveNext (); + scheduler->Insert (next); + } + } + m_events = scheduler; +} + +Ptr +DefaultSimulatorImpl::GetScheduler (void) const +{ + return m_events; +} + + +void +DefaultSimulatorImpl::ProcessOneEvent (void) +{ + Scheduler::Event next = m_events->RemoveNext (); + + NS_ASSERT (next.key.m_ts >= m_currentTs); + --m_unscheduledEvents; + + NS_LOG_LOGIC ("handle " << next.key.m_ts); + m_currentTs = next.key.m_ts; + m_currentUid = next.key.m_uid; + next.impl->Invoke (); + next.impl->Unref (); +} + +bool +DefaultSimulatorImpl::IsFinished (void) const +{ + return m_events->IsEmpty (); +} + +uint64_t +DefaultSimulatorImpl::NextTs (void) const +{ + NS_ASSERT (!m_events->IsEmpty ()); + Scheduler::Event ev = m_events->PeekNext (); + return ev.key.m_ts; +} + +Time +DefaultSimulatorImpl::Next (void) const +{ + return TimeStep (NextTs ()); +} + +void +DefaultSimulatorImpl::Run (void) +{ + + while (!m_events->IsEmpty () && !m_stop && + (m_stopAt == 0 || m_stopAt > NextTs ())) + { + ProcessOneEvent (); + } + + // If the simulator stopped naturally by lack of events, make a + // consistency test to check that we didn't lose any events along the way. + NS_ASSERT(!m_events->IsEmpty () || m_unscheduledEvents == 0); +} + +void +DefaultSimulatorImpl::RunOneEvent (void) +{ + ProcessOneEvent (); +} + +void +DefaultSimulatorImpl::Stop (void) +{ + m_stop = true; +} + +void +DefaultSimulatorImpl::Stop (Time const &time) +{ + NS_ASSERT (time.IsPositive ()); + Time absolute = Simulator::Now () + time; + m_stopAt = absolute.GetTimeStep (); +} + +// +// Schedule an event for a _relative_ time in the future. +// +EventId +DefaultSimulatorImpl::Schedule (Time const &time, EventImpl *event) +{ + Time tAbsolute = time + Now(); + + NS_ASSERT (tAbsolute.IsPositive ()); + NS_ASSERT (tAbsolute >= TimeStep (m_currentTs)); + Scheduler::Event ev; + ev.impl = event; + ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep (); + ev.key.m_uid = m_uid; + m_uid++; + ++m_unscheduledEvents; + m_events->Insert (ev); + return EventId (event, ev.key.m_ts, ev.key.m_uid); +} + +EventId +DefaultSimulatorImpl::ScheduleNow (EventImpl *event) +{ + Scheduler::Event ev; + ev.impl = event; + ev.key.m_ts = m_currentTs; + ev.key.m_uid = m_uid; + m_uid++; + ++m_unscheduledEvents; + m_events->Insert (ev); + return EventId (event, ev.key.m_ts, ev.key.m_uid); +} + +EventId +DefaultSimulatorImpl::ScheduleDestroy (EventImpl *event) +{ + EventId id (Ptr (event, false), m_currentTs, 2); + m_destroyEvents.push_back (id); + m_uid++; + return id; +} + +Time +DefaultSimulatorImpl::Now (void) const +{ + return TimeStep (m_currentTs); +} + +Time +DefaultSimulatorImpl::GetDelayLeft (const EventId &id) const +{ + if (IsExpired (id)) + { + return TimeStep (0); + } + else + { + return TimeStep (id.GetTs () - m_currentTs); + } +} + +void +DefaultSimulatorImpl::Remove (const EventId &id) +{ + if (id.GetUid () == 2) + { + // destroy events. + for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) + { + if (*i == id) + { + m_destroyEvents.erase (i); + break; + } + } + return; + } + if (IsExpired (id)) + { + return; + } + Scheduler::Event event; + event.impl = id.PeekEventImpl (); + event.key.m_ts = id.GetTs (); + event.key.m_uid = id.GetUid (); + m_events->Remove (event); + event.impl->Cancel (); + // whenever we remove an event from the event list, we have to unref it. + event.impl->Unref (); + + --m_unscheduledEvents; +} + +void +DefaultSimulatorImpl::Cancel (const EventId &id) +{ + if (!IsExpired (id)) + { + id.PeekEventImpl ()->Cancel (); + } +} + +bool +DefaultSimulatorImpl::IsExpired (const EventId &ev) const +{ + if (ev.GetUid () == 2) + { + // destroy events. + for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) + { + if (*i == ev) + { + return false; + } + } + return true; + } + if (ev.PeekEventImpl () == 0 || + ev.GetTs () < m_currentTs || + (ev.GetTs () == m_currentTs && + ev.GetUid () <= m_currentUid) || + ev.PeekEventImpl ()->IsCancelled ()) + { + return true; + } + else + { + return false; + } +} + +Time +DefaultSimulatorImpl::GetMaximumSimulationTime (void) const +{ + // XXX: I am fairly certain other compilers use other non-standard + // post-fixes to indicate 64 bit constants. + return TimeStep (0x7fffffffffffffffLL); +} + +} // namespace ns3 + + diff --git a/src/simulator/default-simulator-impl.h b/src/simulator/default-simulator-impl.h new file mode 100644 index 000000000..896977adb --- /dev/null +++ b/src/simulator/default-simulator-impl.h @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 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 + */ + +#ifndef DEFAULT_SIMULATOR_IMPL_H +#define DEFAULT_SIMULATOR_IMPL_H + +#include "simulator-impl.h" +#include "scheduler.h" +#include "event-impl.h" + +#include "ns3/ptr.h" +#include "ns3/assert.h" +#include "ns3/log.h" + +#include + +namespace ns3 { + + class DefaultSimulatorImpl : public SimulatorImpl +{ +public: + static TypeId GetTypeId (void); + + DefaultSimulatorImpl (); + ~DefaultSimulatorImpl (); + + virtual void Destroy (); + virtual bool IsFinished (void) const; + virtual Time Next (void) const; + virtual void Stop (void); + virtual void Stop (Time const &time); + virtual EventId Schedule (Time const &time, EventImpl *event); + virtual EventId ScheduleNow (EventImpl *event); + virtual EventId ScheduleDestroy (EventImpl *event); + virtual void Remove (const EventId &ev); + virtual void Cancel (const EventId &ev); + virtual bool IsExpired (const EventId &ev) const; + virtual void Run (void); + virtual void RunOneEvent (void); + virtual Time Now (void) const; + virtual Time GetDelayLeft (const EventId &id) const; + virtual Time GetMaximumSimulationTime (void) const; + virtual void SetScheduler (Ptr scheduler); + virtual Ptr GetScheduler (void) const; + +private: + void ProcessOneEvent (void); + uint64_t NextTs (void) const; + + typedef std::list DestroyEvents; + DestroyEvents m_destroyEvents; + uint64_t m_stopAt; + bool m_stop; + Ptr m_events; + uint32_t m_uid; + uint32_t m_currentUid; + uint64_t m_currentTs; + // number of events that have been inserted but not yet scheduled, + // not counting the "destroy" events; this is used for validation + int m_unscheduledEvents; +}; + +} // namespace ns3 + +#endif /* DEFAULT_SIMULATOR_IMPL_H */ diff --git a/src/simulator/event-impl.cc b/src/simulator/event-impl.cc index 9f9c39346..03db87d6c 100644 --- a/src/simulator/event-impl.cc +++ b/src/simulator/event-impl.cc @@ -23,7 +23,6 @@ namespace ns3 { - EventImpl::~EventImpl () {} @@ -31,6 +30,7 @@ EventImpl::EventImpl () : m_cancel (false), m_count (1) {} + void EventImpl::Invoke (void) { @@ -39,6 +39,7 @@ EventImpl::Invoke (void) Notify (); } } + void EventImpl::Cancel (void) { @@ -51,4 +52,4 @@ EventImpl::IsCancelled (void) return m_cancel; } -}; // namespace ns3 +} // namespace ns3 diff --git a/src/simulator/event-impl.h b/src/simulator/event-impl.h index 6d2835d17..479eefc12 100644 --- a/src/simulator/event-impl.h +++ b/src/simulator/event-impl.h @@ -58,10 +58,11 @@ public: * Invoked by the simulation engine before calling Invoke. */ bool IsCancelled (void); + protected: virtual void Notify (void) = 0; + private: - friend class Event; bool m_cancel; mutable uint32_t m_count; }; @@ -75,11 +76,13 @@ EventImpl::Ref (void) const { m_count++; } + void EventImpl::Unref (void) const { - m_count--; - if (m_count == 0) + uint32_t c; + c = --m_count; + if (c == 0) { delete this; } diff --git a/src/simulator/heap-scheduler.cc b/src/simulator/heap-scheduler.cc index 391ba5a8b..6795f64fd 100644 --- a/src/simulator/heap-scheduler.cc +++ b/src/simulator/heap-scheduler.cc @@ -23,20 +23,9 @@ #include "heap-scheduler.h" #include "event-impl.h" #include "ns3/assert.h" +#include "ns3/log.h" -#include -#define noTRACE_HEAP 1 - -#ifdef TRACE_HEAP -#include -# define TRACE(x) \ -std::cout << "HEAP TRACE " << x << std::endl; -#else /* TRACE_HEAP */ -# define TRACE(format,...) -#endif /* TRACE_HEAP */ - - - +NS_LOG_COMPONENT_DEFINE ("HeapScheduler"); namespace ns3 { @@ -46,8 +35,8 @@ HeapScheduler::HeapScheduler () // we purposedly waste an item at the start of // the array to make sure the indexes in the // array start at one. - Scheduler::EventKey emptyKey = {0,0}; - m_heap.push_back (std::make_pair (static_cast(0), emptyKey)); + Scheduler::Event empty = {0,{0,0}}; + m_heap.push_back (empty); } HeapScheduler::~HeapScheduler () @@ -103,37 +92,16 @@ void HeapScheduler::Exch (uint32_t a, uint32_t b) { NS_ASSERT (b < m_heap.size () && a < m_heap.size ()); - TRACE ("Exch " << a << ", " << b); - std::pair tmp (m_heap[a]); + NS_LOG_DEBUG ("Exch " << a << ", " << b); + Event tmp (m_heap[a]); m_heap[a] = m_heap[b]; m_heap[b] = tmp; } -bool -HeapScheduler::IsLowerStrictly (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const -{ - if (a->m_ts < b->m_ts) - { - return true; - } - else if (a->m_ts > b->m_ts) - { - return false; - } - else if (a->m_uid < b->m_uid) - { - return true; - } - else - { - return false; - } -} - bool HeapScheduler::IsLessStrictly (uint32_t a, uint32_t b) const { - return IsLowerStrictly (&m_heap[a].second, &m_heap[b].second); + return m_heap[a] < m_heap[b]; } uint32_t @@ -196,57 +164,45 @@ HeapScheduler::TopDown (uint32_t start) void -HeapScheduler::Insert (const EventId &id) +HeapScheduler::Insert (const Event &ev) { - // acquire single ref - EventImpl *event = id.PeekEventImpl (); - event->Ref (); - Scheduler::EventKey key; - key.m_ts = id.GetTs (); - key.m_uid = id.GetUid (); - m_heap.push_back (std::make_pair (event, key)); + m_heap.push_back (ev); BottomUp (); } -EventId +Scheduler::Event HeapScheduler::PeekNext (void) const { - std::pair next = m_heap[Root ()]; - return EventId (next.first, next.second.m_ts, next.second.m_uid); + return m_heap[Root ()]; } -EventId +Scheduler::Event HeapScheduler::RemoveNext (void) { - std::pair next = m_heap[Root ()]; + Event next = m_heap[Root ()]; Exch (Root (), Last ()); m_heap.pop_back (); TopDown (Root ()); - return EventId (Ptr (next.first, false), next.second.m_ts, next.second.m_uid); + return next; } -bool -HeapScheduler::Remove (const EventId &id) +void +HeapScheduler::Remove (const Event &ev) { - uint32_t uid = id.GetUid (); + uint32_t uid = ev.key.m_uid; for (uint32_t i = 1; i < m_heap.size (); i++) { - if (uid == m_heap[i].second.m_uid) + if (uid == m_heap[i].key.m_uid) { - NS_ASSERT (m_heap[i].first == id.PeekEventImpl ()); - std::pair next = m_heap[i]; - // release single ref - next.first->Unref (); + NS_ASSERT (m_heap[i].impl == ev.impl); Exch (i, Last ()); m_heap.pop_back (); TopDown (i); - return true; + return; } } NS_ASSERT (false); - // quiet compiler - return false; } -}; // namespace ns3 +} // namespace ns3 diff --git a/src/simulator/heap-scheduler.h b/src/simulator/heap-scheduler.h index 3f2f37c94..ca4a38be5 100644 --- a/src/simulator/heap-scheduler.h +++ b/src/simulator/heap-scheduler.h @@ -18,8 +18,8 @@ * Author: Mathieu Lacage */ -#ifndef SCHEDULER_HEAP_H -#define SCHEDULER_HEAP_H +#ifndef HEAP_SCHEDULER_H +#define HEAP_SCHEDULER_H #include "scheduler.h" #include @@ -27,8 +27,6 @@ namespace ns3 { -class EventHolder; - /** * \ingroup scheduler * \brief a binary heap event scheduler @@ -46,19 +44,20 @@ class EventHolder; * - It uses a slightly non-standard while loop for top-down heapify * to move one if statement out of the loop. */ -class HeapScheduler : public Scheduler { +class HeapScheduler : public Scheduler +{ public: HeapScheduler (); virtual ~HeapScheduler (); - virtual void Insert (const EventId &id); + virtual void Insert (const Event &ev); virtual bool IsEmpty (void) const; - virtual EventId PeekNext (void) const; - virtual EventId RemoveNext (void); - virtual bool Remove (const EventId &ev); + virtual Event PeekNext (void) const; + virtual Event RemoveNext (void); + virtual void Remove (const Event &ev); private: - typedef std::vector > BinaryHeap; + typedef std::vector BinaryHeap; inline uint32_t Parent (uint32_t id) const; uint32_t Sibling (uint32_t id) const; @@ -69,7 +68,6 @@ private: uint32_t Last (void) const; inline bool IsRoot (uint32_t id) const; inline bool IsBottom (uint32_t id) const; - inline bool IsLowerStrictly (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const; inline bool IsLessStrictly (uint32_t a, uint32_t b) const; inline uint32_t Smallest (uint32_t a, uint32_t b) const; @@ -80,7 +78,6 @@ private: BinaryHeap m_heap; }; -}; // namespace ns3 +} // namespace ns3 - -#endif /* SCHEDULER_HEAP_H */ +#endif /* HEAP_SCHEDULER_H */ diff --git a/src/simulator/list-scheduler.cc b/src/simulator/list-scheduler.cc index 78459434a..822cfe4a8 100644 --- a/src/simulator/list-scheduler.cc +++ b/src/simulator/list-scheduler.cc @@ -32,79 +32,51 @@ ListScheduler::ListScheduler () ListScheduler::~ListScheduler () {} -bool -ListScheduler::IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const -{ - if (a->m_ts < b->m_ts) - { - return true; - } - else if (a->m_ts == b->m_ts && - a->m_uid < b->m_uid) - { - return true; - } - else - { - return false; - } -} - void -ListScheduler::Insert (const EventId &id) +ListScheduler::Insert (const Event &ev) { - Scheduler::EventKey key; - // 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++) { - if (IsLower (&key, &i->second)) + if (ev.key < i->key) { - m_events.insert (i, std::make_pair (event, key)); + m_events.insert (i, ev); return; } } - m_events.push_back (std::make_pair (event, key)); + m_events.push_back (ev); } bool ListScheduler::IsEmpty (void) const { return m_events.empty (); } -EventId +Scheduler::Event ListScheduler::PeekNext (void) const { - std::pair next = m_events.front (); - return EventId (next.first, next.second.m_ts, next.second.m_uid); + return m_events.front (); } -EventId +Scheduler::Event ListScheduler::RemoveNext (void) { - std::pair next = m_events.front (); + Event next = m_events.front (); m_events.pop_front (); - return EventId (Ptr (next.first,false), next.second.m_ts, next.second.m_uid); + return next; } -bool -ListScheduler::Remove (const EventId &id) +void +ListScheduler::Remove (const Event &ev) { for (EventsI i = m_events.begin (); i != m_events.end (); i++) { - if (i->second.m_uid == id.GetUid ()) + if (i->key.m_uid == ev.key.m_uid) { - NS_ASSERT (id.PeekEventImpl () == i->first); - // release single acquire ref. - i->first->Unref (); + NS_ASSERT (ev.impl == i->impl); m_events.erase (i); - return true; + return; } } NS_ASSERT (false); - return false; } -}; // namespace ns3 +} // namespace ns3 diff --git a/src/simulator/list-scheduler.h b/src/simulator/list-scheduler.h index c2a70ea31..064ae1d17 100644 --- a/src/simulator/list-scheduler.h +++ b/src/simulator/list-scheduler.h @@ -18,11 +18,10 @@ * Author: Mathieu Lacage */ -#ifndef SCHEDULER_LIST_H -#define SCHEDULER_LIST_H +#ifndef LIST_SCHEDULER_H +#define LIST_SCHEDULER_H #include "scheduler.h" -#include "event-id.h" #include #include #include @@ -35,29 +34,28 @@ class EventImpl; * \ingroup scheduler * \brief a std::list event scheduler * - * This class implements the an event scheduler using an std::list + * This class implements an event scheduler using an std::list * data structure, that is, a double linked-list. */ -class ListScheduler : public Scheduler { +class ListScheduler : public Scheduler +{ public: ListScheduler (); virtual ~ListScheduler (); - virtual void Insert (const EventId &id); + virtual void Insert (const Event &ev); virtual bool IsEmpty (void) const; - virtual EventId PeekNext (void) const; - virtual EventId RemoveNext (void); - virtual bool Remove (const EventId &ev); + virtual Event PeekNext (void) const; + virtual Event RemoveNext (void); + virtual void Remove (const Event &ev); private: - inline bool IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const; - typedef std::list > Events; - typedef std::list >::iterator EventsI; + typedef std::list Events; + typedef std::list::iterator EventsI; Events m_events; }; -}; // namespace ns3 +} // namespace ns3 - -#endif /* SCHEDULER_LIST_H */ +#endif /* LIST_SCHEDULER_H */ diff --git a/src/simulator/make-event.cc b/src/simulator/make-event.cc new file mode 100644 index 000000000..d791632ba --- /dev/null +++ b/src/simulator/make-event.cc @@ -0,0 +1,27 @@ +#include "make-event.h" + +namespace ns3 { + +EventImpl *MakeEvent (void (*f) (void)) +{ + // zero arg version + class EventFunctionImpl0 : public EventImpl + { + public: + typedef void (*F)(void); + + EventFunctionImpl0 (F function) + : m_function (function) + {} + virtual ~EventFunctionImpl0 () {} + protected: + virtual void Notify (void) { + (*m_function) (); + } + private: + F m_function; + } *ev = new EventFunctionImpl0 (f); + return ev; +} + +} // namespace ns3 diff --git a/src/simulator/make-event.h b/src/simulator/make-event.h new file mode 100644 index 000000000..d24a0e28e --- /dev/null +++ b/src/simulator/make-event.h @@ -0,0 +1,388 @@ +#ifndef MAKE_EVENT_H +#define MAKE_EVENT_H + +namespace ns3 { + +class EventImpl; + +template +EventImpl *MakeEvent (MEM mem_ptr, OBJ obj); + +template +EventImpl *MakeEvent (MEM mem_ptr, OBJ obj, T1 a1); + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2); + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3); + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); + +EventImpl * MakeEvent (void (*f) (void)); +template +EventImpl * MakeEvent (void (*f) (U1), T1 a1); + +template +EventImpl * MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2); + +template +EventImpl * MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3); + +template +EventImpl * MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4); + +template +EventImpl * MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); + +} // namespace ns3 + +/******************************************************************** + Implementation of templates defined above + ********************************************************************/ + +#include "event-impl.h" +#include "ns3/type-traits.h" + +namespace ns3 { + +template +struct EventMemberImplObjTraits; + +template +struct EventMemberImplObjTraits +{ + static T &GetReference (T *p) { + return *p; + } +}; + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj) +{ + // zero argument version + class EventMemberImpl0 : public EventImpl { + public: + EventMemberImpl0 (OBJ obj, MEM function) + : m_obj (obj), + m_function (function) + {} + virtual ~EventMemberImpl0 () {} + private: + virtual void Notify (void) { + (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (); + } + OBJ m_obj; + MEM m_function; + } * ev = new EventMemberImpl0 (obj, mem_ptr); + return ev; +} + + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, T1 a1) +{ + // one argument version + class EventMemberImpl1 : public EventImpl { + public: + EventMemberImpl1 (OBJ obj, MEM function, T1 a1) + : m_obj (obj), + m_function (function), + m_a1 (a1) + {} + protected: + virtual ~EventMemberImpl1 () {} + private: + virtual void Notify (void) { + (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1); + } + OBJ m_obj; + MEM m_function; + typename TypeTraits::ReferencedType m_a1; + } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); + return ev; +} + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) +{ + // two argument version + class EventMemberImpl2 : public EventImpl { + public: + EventMemberImpl2 (OBJ obj, MEM function, T1 a1, T2 a2) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2) + { } + protected: + virtual ~EventMemberImpl2 () {} + private: + virtual void Notify (void) { + (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2); + } + OBJ m_obj; + MEM m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + } *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2); + return ev; +} + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) +{ + // three argument version + class EventMemberImpl3 : public EventImpl { + public: + EventMemberImpl3 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3) + { } + protected: + virtual ~EventMemberImpl3 () {} + private: + virtual void Notify (void) { + (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3); + } + OBJ m_obj; + MEM m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + typename TypeTraits::ReferencedType m_a3; + } *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3); + return ev; +} + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) +{ + // four argument version + class EventMemberImpl4 : public EventImpl { + public: + EventMemberImpl4 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4) + { } + protected: + virtual ~EventMemberImpl4 () {} + private: + virtual void Notify (void) { + (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4); + } + OBJ m_obj; + MEM m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + typename TypeTraits::ReferencedType m_a3; + typename TypeTraits::ReferencedType m_a4; + } *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4); + return ev; +} + +template +EventImpl * MakeEvent (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) +{ + // five argument version + class EventMemberImpl5 : public EventImpl { + public: + EventMemberImpl5 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4), + m_a5 (a5) + { } + protected: + virtual ~EventMemberImpl5 () {} + private: + virtual void Notify (void) { + (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5); + } + OBJ m_obj; + MEM m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + typename TypeTraits::ReferencedType m_a3; + typename TypeTraits::ReferencedType m_a4; + typename TypeTraits::ReferencedType m_a5; + } *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5); + return ev; +} + +template +EventImpl * MakeEvent (void (*f) (U1), T1 a1) +{ + // one arg version + class EventFunctionImpl1 : public EventImpl { + public: + typedef void (*F)(U1); + + EventFunctionImpl1 (F function, T1 a1) + : m_function (function), + m_a1 (a1) + { } + protected: + virtual ~EventFunctionImpl1 () {} + private: + virtual void Notify (void) { + (*m_function) (m_a1); + } + F m_function; + typename TypeTraits::ReferencedType m_a1; + } *ev = new EventFunctionImpl1 (f, a1); + return ev; +} + +template +EventImpl * MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) +{ + // two arg version + class EventFunctionImpl2 : public EventImpl { + public: + typedef void (*F)(U1, U2); + + EventFunctionImpl2 (F function, T1 a1, T2 a2) + : m_function (function), + m_a1 (a1), + m_a2 (a2) + {} + protected: + virtual ~EventFunctionImpl2 () {} + private: + virtual void Notify (void) { + (*m_function) (m_a1, m_a2); + } + F m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + } *ev = new EventFunctionImpl2 (f, a1, a2); + return ev; +} + +template +EventImpl * MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3) +{ + // three arg version + class EventFunctionImpl3 : public EventImpl { + public: + typedef void (*F)(U1, U2, U3); + + EventFunctionImpl3 (F function, T1 a1, T2 a2, T3 a3) + : m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3) + { } + protected: + virtual ~EventFunctionImpl3 () {} + private: + virtual void Notify (void) { + (*m_function) (m_a1, m_a2, m_a3); + } + F m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + typename TypeTraits::ReferencedType m_a3; + } *ev = new EventFunctionImpl3 (f, a1, a2, a3); + return ev; +} + +template +EventImpl * MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) +{ + // four arg version + class EventFunctionImpl4 : public EventImpl { + public: + typedef void (*F)(U1, U2, U3, U4); + + EventFunctionImpl4 (F function, T1 a1, T2 a2, T3 a3, T4 a4) + : m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4) + { } + protected: + virtual ~EventFunctionImpl4 () {} + private: + virtual void Notify (void) { + (*m_function) (m_a1, m_a2, m_a3, m_a4); + } + F m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + typename TypeTraits::ReferencedType m_a3; + typename TypeTraits::ReferencedType m_a4; + } *ev = new EventFunctionImpl4 (f, a1, a2, a3, a4); + return ev; +} + +template +EventImpl * 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 { + public: + typedef void (*F)(U1,U2,U3,U4,U5); + + EventFunctionImpl5 (F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) + : m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4), + m_a5 (a5) + {} + protected: + virtual ~EventFunctionImpl5 () {} + private: + virtual void Notify (void) { + (*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5); + } + F m_function; + typename TypeTraits::ReferencedType m_a1; + typename TypeTraits::ReferencedType m_a2; + typename TypeTraits::ReferencedType m_a3; + typename TypeTraits::ReferencedType m_a4; + typename TypeTraits::ReferencedType m_a5; + } *ev = new EventFunctionImpl5 (f, a1, a2, a3, a4, a5); + return ev; +} + +} // namespace ns3 + +#endif /* MAKE_EVENT_H */ diff --git a/src/simulator/map-scheduler.cc b/src/simulator/map-scheduler.cc index 9726c4b66..ce861b8d0 100644 --- a/src/simulator/map-scheduler.cc +++ b/src/simulator/map-scheduler.cc @@ -22,18 +22,10 @@ #include "map-scheduler.h" #include "event-impl.h" #include "ns3/assert.h" +#include "ns3/log.h" #include -#define noTRACE_MAP 1 - -#ifdef TRACE_MAP -#include -# define TRACE(x) \ -std::cout << "MAP TRACE " << x << std::endl; -#else /* TRACE_MAP */ -# define TRACE(format,...) -#endif /* TRACE_MAP */ - +NS_LOG_COMPONENT_DEFINE ("MapScheduler"); namespace ns3 { @@ -42,45 +34,12 @@ MapScheduler::MapScheduler () MapScheduler::~MapScheduler () {} -/* Note the invariants which this function must provide: - * - irreflexibility: f (x,x) is false) - * - antisymmetry: f(x,y) = !f(y,x) - * - transitivity: f(x,y) and f(y,z) => f(x,z) - */ -bool -MapScheduler::EventKeyCompare::operator () (struct EventKey const&a, struct EventKey const&b) -{ - if (a.m_ts < b.m_ts) - { - return true; - } - else if (a.m_ts > b.m_ts) - { - return false; - } - else if (a.m_uid < b.m_uid) - { - return true; - } - else - { - return false; - } -} - - - void -MapScheduler::Insert (const EventId &id) +MapScheduler::Insert (const Event &ev) { - // acquire a single ref - EventImpl *event = id.PeekEventImpl (); - event->Ref (); - Scheduler::EventKey key; - key.m_ts = id.GetTs (); - key.m_uid = id.GetUid (); + NS_LOG_FUNCTION (this << ev.impl << ev.key.m_ts << ev.key.m_uid); std::pair result; - result = m_list.insert (std::make_pair (key, event)); + result = m_list.insert (std::make_pair (ev.key, ev.impl)); NS_ASSERT (result.second); } @@ -90,35 +49,41 @@ MapScheduler::IsEmpty (void) const return m_list.empty (); } -EventId +Scheduler::Event MapScheduler::PeekNext (void) const { + NS_LOG_FUNCTION (this); EventMapCI i = m_list.begin (); NS_ASSERT (i != m_list.end ()); - return EventId (i->second, i->first.m_ts, i->first.m_uid); + Event ev; + ev.impl = i->second; + ev.key = i->first; + NS_LOG_DEBUG (this << ev.impl << ev.key.m_ts << ev.key.m_uid); + return ev; } -EventId +Scheduler::Event MapScheduler::RemoveNext (void) { + NS_LOG_FUNCTION (this); EventMapI i = m_list.begin (); + NS_ASSERT (i != m_list.end ()); std::pair next = *i; + Event ev; + ev.impl = i->second; + ev.key = i->first; m_list.erase (i); - return EventId (Ptr (next.second, false), next.first.m_ts, next.first.m_uid); + NS_LOG_DEBUG (this << ev.impl << ev.key.m_ts << ev.key.m_uid); + return ev; } -bool -MapScheduler::Remove (const EventId &id) +void +MapScheduler::Remove (const Event &ev) { - Scheduler::EventKey key; - key.m_ts = id.GetTs (); - key.m_uid = id.GetUid (); - EventMapI i = m_list.find (key); - NS_ASSERT (i->second == id.PeekEventImpl ()); - // release single ref. - i->second->Unref (); + NS_LOG_FUNCTION (this << ev.impl << ev.key.m_ts << ev.key.m_uid); + EventMapI i = m_list.find (ev.key); + NS_ASSERT (i->second == ev.impl); m_list.erase (i); - return true; } -}; // namespace ns3 +} // namespace ns3 diff --git a/src/simulator/map-scheduler.h b/src/simulator/map-scheduler.h index c2bf55341..d82eb7fec 100644 --- a/src/simulator/map-scheduler.h +++ b/src/simulator/map-scheduler.h @@ -18,8 +18,8 @@ * Author: Mathieu Lacage */ -#ifndef SCHEDULER_MAP_H -#define SCHEDULER_MAP_H +#ifndef MAP_SCHEDULER_H +#define MAP_SCHEDULER_H #include "scheduler.h" #include @@ -28,8 +28,6 @@ namespace ns3 { -class EventImpl; - /** * \ingroup scheduler * \brief a std::map event scheduler @@ -37,32 +35,27 @@ class EventImpl; * This class implements the an event scheduler using an std::map * data structure. */ -class MapScheduler : public Scheduler { +class MapScheduler : public Scheduler +{ public: MapScheduler (); virtual ~MapScheduler (); - virtual void Insert (const EventId &id); + virtual void Insert (const Event &ev); virtual bool IsEmpty (void) const; - virtual EventId PeekNext (void) const; - virtual EventId RemoveNext (void); - virtual bool Remove (const EventId &ev); + virtual Event PeekNext (void) const; + virtual Event RemoveNext (void); + virtual void Remove (const Event &ev); private: - class EventKeyCompare { - public: - bool operator () (struct EventKey const&a, struct EventKey const&b); - }; - - typedef std::map EventMap; - typedef std::map::iterator EventMapI; - typedef std::map::const_iterator EventMapCI; + typedef std::map EventMap; + typedef std::map::iterator EventMapI; + typedef std::map::const_iterator EventMapCI; EventMap m_list; }; -}; // namespace ns3 +} // namespace ns3 - -#endif /* SCHEDULER_MAP_H */ +#endif /* MAP_SCHEDULER_H */ diff --git a/src/simulator/realtime-simulator-impl.cc b/src/simulator/realtime-simulator-impl.cc new file mode 100644 index 000000000..1acec20b3 --- /dev/null +++ b/src/simulator/realtime-simulator-impl.cc @@ -0,0 +1,845 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 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; + * + * 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 "simulator.h" +#include "realtime-simulator-impl.h" +#include "wall-clock-synchronizer.h" +#include "scheduler.h" +#include "event-impl.h" +#include "synchronizer.h" + +#include "ns3/ptr.h" +#include "ns3/pointer.h" +#include "ns3/assert.h" +#include "ns3/fatal-error.h" +#include "ns3/log.h" +#include "ns3/system-mutex.h" +#include "ns3/boolean.h" +#include "ns3/enum.h" + + +#include + +NS_LOG_COMPONENT_DEFINE ("RealtimeSimulatorImpl"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (RealtimeSimulatorImpl); + +TypeId +RealtimeSimulatorImpl::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl") + .SetParent () + .AddConstructor () + .AddAttribute ("SynchronizationMode", + "What to do if the simulation cannot keep up with real time.", + EnumValue (SYNC_BEST_EFFORT), + MakeEnumAccessor (&RealtimeSimulatorImpl::SetSynchronizationMode), + MakeEnumChecker (SYNC_BEST_EFFORT, "BestEffort", + SYNC_HARD_LIMIT, "HardLimit")) + .AddAttribute ("HardLimit", + "Maximum acceptable real-time jitter (used in conjunction with SynchronizationMode=HardLimit)", + TimeValue (Seconds (0.1)), + MakeTimeAccessor (&RealtimeSimulatorImpl::m_hardLimit), + MakeTimeChecker ()) + ; + return tid; +} + + +RealtimeSimulatorImpl::RealtimeSimulatorImpl () +{ + NS_LOG_FUNCTION_NOARGS (); + + m_stop = false; + m_stopAt = 0; + m_running = false; + // uids are allocated from 4. + // uid 0 is "invalid" events + // uid 1 is "now" events + // uid 2 is "destroy" events + m_uid = 4; + // before ::Run is entered, the m_currentUid will be zero + m_currentUid = 0; + m_currentTs = 0; + m_unscheduledEvents = 0; + + // Be very careful not to do anything that would cause a change or assignment + // of the underlying reference counts of m_synchronizer or you will be sorry. + m_synchronizer = CreateObject (); +} + +RealtimeSimulatorImpl::~RealtimeSimulatorImpl () +{ + NS_LOG_FUNCTION_NOARGS (); + while (m_events->IsEmpty () == false) + { + Scheduler::Event next = m_events->RemoveNext (); + next.impl->Unref (); + } + m_events = 0; + m_synchronizer = 0; +} + +void +RealtimeSimulatorImpl::Destroy () +{ + NS_LOG_FUNCTION_NOARGS (); + + // + // This function is only called with the private version "disconnected" from + // the main simulator functions. We rely on the user not calling + // Simulator::Destroy while there is a chance that a worker thread could be + // accessing the current instance of the private object. In practice this + // means shutting down the workers and doing a Join() before calling the + // Simulator::Destroy(). + // + while (m_destroyEvents.empty () == false) + { + Ptr ev = m_destroyEvents.front ().PeekEventImpl (); + m_destroyEvents.pop_front (); + NS_LOG_LOGIC ("handle destroy " << ev); + if (ev->IsCancelled () == false) + { + ev->Invoke (); + } + } +} + +void +RealtimeSimulatorImpl::SetScheduler (Ptr scheduler) +{ + NS_LOG_FUNCTION_NOARGS (); + + { + CriticalSection cs (m_mutex); + + if (m_events != 0) + { + while (m_events->IsEmpty () == false) + { + Scheduler::Event next = m_events->RemoveNext (); + scheduler->Insert (next); + } + } + m_events = scheduler; + } +} + +Ptr +RealtimeSimulatorImpl::GetScheduler (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_events; +} + +void +RealtimeSimulatorImpl::ProcessOneEvent (void) +{ + NS_LOG_FUNCTION_NOARGS (); + // + // The idea here is to wait until the next event comes due. In the case of + // a realtime simulation, we want real time to be consumed between events. + // It is the realtime synchronizer that causes real time to be consumed by + // doing some kind of a wait. + // + // We need to be able to have external events (such as a packet reception event) + // cause us to re-evaluate our state. The way this works is that the synchronizer + // gets interrupted and returs. So, there is a possibility that things may change + // out from under us dynamically. In this case, we need to re-evaluate how long to + // wait in a for-loop until we have waited sucessfully (until a timeout) for the + // event at the head of the event list. + // + // m_synchronizer->Synchronize will return true if the wait was completed without + // interruption, otherwise it will return false indicating that something has changed + // out from under us. If we sit in the for-loop trying to synchronize until + // Synchronize() returns true, we will have successfully synchronized the execution + // time of the next event with the wall clock time of the synchronizer. + // + + for (;;) + { + uint64_t tsDelay = 0; + uint64_t tsNext = 0; + + // + // It is important to understand that m_currentTs is interpreted only as the + // timestamp of the last event we executed. Current time can a bit of a + // slippery concept in realtime mode. What we have here is a discrete event + // simulator, so the last event is, by defintion, executed entirely at a single + // discrete time. This is the definition of m_currentTs. It really has + // nothing to do with the current real time, except that we are trying to arrange + // that at the instant of the beginning of event execution, the current real time + // and m_currentTs coincide. + // + // We use tsNow as the indication of the current real time. + // + uint64_t tsNow; + + { + CriticalSection cs (m_mutex); + // + // Since we are in realtime mode, the time to delay has got to be the + // difference between the current realtime and the timestamp of the next + // event. Since m_currentTs is actually the timestamp of the last event we + // executed, it's not particularly meaningful for us here since real time has + // certainly elapsed since it was last updated. + // + // It is possible that the current realtime has drifted past the next event + // time so we need to be careful about that and not delay in that case. + // + NS_ASSERT_MSG (m_synchronizer->Realtime (), + "RealtimeSimulatorImpl::ProcessOneEvent (): Synchronizer reports not Realtime ()"); + + // + // tsNow is set to the normalized current real time. When the simulation was + // started, the current real time was effectively set to zero; so tsNow is + // the current "real" simulation time. + // + // tsNext is the simulation time of the next event we want to execute. + // + tsNow = m_synchronizer->GetCurrentRealtime (); + tsNext = NextTs (); + + // + // tsDelay is therefore the real time we need to delay in order to bring the + // real time in sync with the simulation time. If we wait for this amount of + // real time, we will accomplish moving the simulation time at the same rate + // as the real time. This is typically called "pacing" the simulation time. + // + // We do have to be careful if we are falling behind. If so, tsDelay must be + // zero. If we're late, don't dawdle. + // + if (tsNext <= tsNow) + { + tsDelay = 0; + } + else + { + tsDelay = tsNext - tsNow; + } + + // + // We've figured out how long we need to delay in order to pace the + // simulation time with the real time. We're going to sleep, but need + // to work with the synchronizer to make sure we're awakened if something + // external happens (like a packet is received). This next line resets + // the synchronizer so that any future event will cause it to interrupt. + // + m_synchronizer->SetCondition (false); + } + + // + // We have a time to delay. This time may actually not be valid anymore + // since we released the critical section immediately above, and a real-time + // ScheduleReal or ScheduleRealNow may have snuck in, well, between the + // closing brace above and this comment so to speak. If this is the case, + // that schedule operation will have done a synchronizer Signal() that + // will set the condition variable to true and cause the Synchronize call + // below to return immediately. + // + // It's easiest to understand if you just consider a short tsDelay that only + // requires a SpinWait down in the synchronizer. What will happen is that + // whan Synchronize calls SpinWait, SpinWait will look directly at its + // condition variable. Note that we set this condition variable to false + // inside the critical section above. + // + // SpinWait will go into a forever loop until either the time has expired or + // until the condition variable becomes true. A true condition indicates that + // the wait should stop. The condition is set to true by one of the Schedule + // methods of the simulator; so if we are in a wait down in Synchronize, and + // a Simulator::ScheduleReal is done, the wait down in Synchronize will exit and + // Synchronize will return false. This means we have not actually synchronized + // to the event expiration time. If no real-time schedule operation is done + // while down in Synchronize, the wait will time out and Synchronize will return + // true. This indicates that we have synchronized to the event time. + // + // So we need to stay in this for loop, looking for the next event timestamp and + // attempting to sleep until its due. If we've slept until the timestamp is due, + // Synchronize returns true and we break out of the sync loop. If an external + // event happens that requires a re-schedule, Synchronize returns false and + // we re-evaluate our timing by continuing in the loop. + // + // It is expected that tsDelay become shorter as external events interrupt our + // waits. + // + if (m_synchronizer->Synchronize (tsNow, tsDelay)) + { + NS_LOG_LOGIC ("Interrupted ..."); + break; + } + + // + // If we get to this point, we have been interrupted during a wait by a real-time + // schedule operation. This means all bets are off regarding tsDelay and we need + // to re-evaluate what it is we want to do. We'll loop back around in the + // for-loop and start again from scratch. + // + } + + // + // If we break out of the for-loop above, we have waited until the time specified + // by the event that was at the head of the event list when we started the process. + // Since there is a bunch of code that was executed outside a critical section (the + // Synchronize call) we cannot be sure that the event at the head of the event list + // is the one we think it is. What we can be sure of is that it is time to execute + // whatever event is at the head of this list if the list is in time order. + // + Scheduler::Event next; + + { + CriticalSection cs (m_mutex); + + // + // We do know we're waiting for an event, so there had better be an event on the + // event queue. Let's pull it off. When we release the critical section, the + // event we're working on won't be on the list and so subsequent operations won't + // mess with us. + // + NS_ASSERT_MSG (m_events->IsEmpty () == false, + "RealtimeSimulatorImpl::ProcessOneEvent(): event queue is empty"); + next = m_events->RemoveNext (); + --m_unscheduledEvents; + + // + // We cannot make any assumption that "next" is the same event we originally waited + // for. We can only assume that only that it must be due and cannot cause time + // to move backward. + // + NS_ASSERT_MSG (next.key.m_ts >= m_currentTs, + "RealtimeSimulatorImpl::ProcessOneEvent(): " + "next.GetTs() earlier than m_currentTs (list order error)"); + NS_LOG_LOGIC ("handle " << next.key.m_ts); + + // + // Update the current simulation time to be the timestamp of the event we're + // executing. From the rest of the simulation's point of view, simulation time + // is frozen until the next event is executed. + // + m_currentTs = next.key.m_ts; + m_currentUid = next.key.m_uid; + + // + // We're about to run the event and we've done our best to synchronize this + // event execution time to real time. Now, if we're in SYNC_HARD_LIMIT mode + // we have to decide if we've done a good enough job and if we haven't, we've + // been asked to commit ritual suicide. + // + // We check the simulation time against the current real time to make this + // judgement. + // + if (m_synchronizationMode == SYNC_HARD_LIMIT) + { + uint64_t tsFinal = m_synchronizer->GetCurrentRealtime (); + uint64_t tsJitter; + + if (tsFinal >= m_currentTs) + { + tsJitter = tsFinal - m_currentTs; + } + else + { + tsJitter = m_currentTs - tsFinal; + } + + if (tsJitter > static_cast(m_hardLimit.GetTimeStep ())) + { + NS_FATAL_ERROR ("RealtimeSimulatorImpl::ProcessOneEvent (): " + "Hard real-time limit exceeded (jitter = " << tsJitter << ")"); + } + } + } + + // + // We have got the event we're about to execute completely disentangled from the + // event list so we can execute it outside a critical section without fear of someone + // changing things out from under us. + + EventImpl *event = next.impl; + m_synchronizer->EventStart (); + event->Invoke (); + m_synchronizer->EventEnd (); + event->Unref (); +} + +bool +RealtimeSimulatorImpl::IsFinished (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + bool rc; + { + CriticalSection cs (m_mutex); + rc = m_events->IsEmpty (); + } + + return rc; +} + +// +// Peeks into event list. Should be called with critical section locked. +// +uint64_t +RealtimeSimulatorImpl::NextTs (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + NS_ASSERT_MSG (m_events->IsEmpty () == false, + "RealtimeSimulatorImpl::NextTs(): event queue is empty"); + Scheduler::Event ev = m_events->PeekNext (); + return ev.key.m_ts; +} + +// +// Calls NextTs(). Should be called with critical section locked. +// +Time +RealtimeSimulatorImpl::Next (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return TimeStep (NextTs ()); +} + +void +RealtimeSimulatorImpl::Run (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + NS_ASSERT_MSG (m_running == false, + "RealtimeSimulatorImpl::Run(): Simulator already running"); + + m_running = true; + m_synchronizer->SetOrigin (m_currentTs); + + for (;;) + { + bool done = false; + + { + CriticalSection cs (m_mutex); + // + // In all cases we stop when the event list is empty. If you are doing a + // realtime simulation and you want it to extend out for some time, you must + // call StopAt. In the realtime case, this will stick a placeholder event out + // at the end of time. + // + if (m_stop || m_events->IsEmpty ()) + { + done = true; + } + // + // We also want to stop the simulator at some time even if there are events + // that have been scheduled out in the future. If we're in realtime mode, we + // actually have time passing, so we must look at the realtime clock to see if + // we're past the end time. + // + if (m_stopAt && m_stopAt <= m_synchronizer->GetCurrentRealtime ()) + { + done = true; + } + } + + if (done) + { + break; + } + + ProcessOneEvent (); + } + + // + // If the simulator stopped naturally by lack of events, make a + // consistency test to check that we didn't lose any events along the way. + // + { + CriticalSection cs (m_mutex); + + NS_ASSERT_MSG (m_events->IsEmpty () == false || m_unscheduledEvents == 0, + "RealtimeSimulatorImpl::Run(): Empty queue and unprocessed events"); + } + + m_running = false; +} + +bool +RealtimeSimulatorImpl::Running (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_running; +} + +bool +RealtimeSimulatorImpl::Realtime (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_synchronizer->Realtime (); +} + +// +// This will run the first event on the queue without considering any realtime +// synchronization. It's mainly implemented to allow simulations requiring +// the multithreaded ScheduleRealtimeNow() functions the possibility of driving +// the simulation from their own event loop. +// +// It is expected that if there are any realtime requirements, the responsibility +// for synchronizing with real time in an external event loop will be picked up +// by that loop. For example, they may call Simulator::Next() to find the +// execution time of the next event and wait for that time somehow -- then call +// RunOneEvent to fire the event. +// +void +RealtimeSimulatorImpl::RunOneEvent (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + NS_ASSERT_MSG (m_running == false, + "RealtimeSimulatorImpl::RunOneEvent(): An internal simulator event loop is running"); + + EventImpl *event = 0; + + // + // Run this in a critical section in case there's another thread around that + // may be inserting things onto the event list. + // + { + CriticalSection cs (m_mutex); + + Scheduler::Event next = m_events->RemoveNext (); + + NS_ASSERT (next.key.m_ts >= m_currentTs); + --m_unscheduledEvents; + + NS_LOG_LOGIC ("handle " << next.key.m_ts); + m_currentTs = next.key.m_ts; + m_currentUid = next.key.m_ts; + event = next.impl; + } + event->Invoke (); + event->Unref (); +} + +void +RealtimeSimulatorImpl::Stop (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_stop = true; +} + +static void Placeholder (void) {} + +// +// Schedule a stop for a _relative_ time in the future. If the simulation +// hasn't started yet, this will effectively be an absolute time. +// +void +RealtimeSimulatorImpl::Stop (Time const &time) +{ + NS_LOG_FUNCTION (time); + + Time tAbsolute = Simulator::Now () + time; + NS_ASSERT (tAbsolute.IsPositive ()); + NS_ASSERT (tAbsolute >= TimeStep (m_currentTs)); + m_stopAt = tAbsolute.GetTimeStep (); + + // + // For the realtime case, we need a real event sitting out at the end of time + // to keep the simulator running (sleeping) while there are no other events + // present. If an "external" device in another thread decides to schedule an + // event, the sleeping synchronizer will be awakened and the new event will + // be run. + // + // The easiest thing to do is to call back up into the simulator to take + // advantage of all of the nice event wrappers. This will call back down into + // RealtimeSimulatorImpl::Schedule to do the work. This path interprets the + // time as relative, so pass the relative time. + // + Simulator::Schedule (time, &Placeholder); +} + +// +// Schedule an event for a _relative_ time in the future. +// +EventId +RealtimeSimulatorImpl::Schedule (Time const &time, EventImpl *impl) +{ + NS_LOG_FUNCTION (time << impl); + + Scheduler::Event ev; + { + CriticalSection cs (m_mutex); + // + // This is the reason we had to bring the absolute time calcualtion in from the + // simulator.h into the implementation. Since the implementations may be + // multi-threaded, we need this calculation to be atomic. You can see it is + // here since we are running in a CriticalSection. + // + Time tAbsolute = Simulator::Now () + time; + NS_ASSERT_MSG (tAbsolute.IsPositive (), "RealtimeSimulatorImpl::Schedule(): Negative time"); + NS_ASSERT_MSG (tAbsolute >= TimeStep (m_currentTs), "RealtimeSimulatorImpl::Schedule(): time < m_currentTs"); + ev.impl = impl; + ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep (); + ev.key.m_uid = m_uid; + m_uid++; + ++m_unscheduledEvents; + m_events->Insert (ev); + m_synchronizer->Signal (); + } + + return EventId (impl, ev.key.m_ts, ev.key.m_uid); +} + +EventId +RealtimeSimulatorImpl::ScheduleNow (EventImpl *impl) +{ + NS_LOG_FUNCTION_NOARGS (); + Scheduler::Event ev; + { + CriticalSection cs (m_mutex); + + ev.impl = impl; + ev.key.m_ts = m_currentTs; + ev.key.m_uid = m_uid; + m_uid++; + ++m_unscheduledEvents; + m_events->Insert (ev); + m_synchronizer->Signal (); + } + + return EventId (impl, ev.key.m_ts, ev.key.m_uid); +} + +Time +RealtimeSimulatorImpl::Now (void) const +{ + return TimeStep (m_currentTs); +} + +// +// Schedule an event for a _relative_ time in the future. +// +void +RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, EventImpl *impl) +{ + NS_LOG_FUNCTION (time << impl); + + + { + CriticalSection cs (m_mutex); + + uint64_t ts = m_synchronizer->GetCurrentRealtime () + time.GetTimeStep (); + NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtime(): schedule for time < m_currentTs"); + Scheduler::Event ev; + ev.impl = impl; + ev.key.m_ts = ts; + ev.key.m_uid = m_uid; + m_uid++; + ++m_unscheduledEvents; + m_events->Insert (ev); + m_synchronizer->Signal (); + } + +} + +void +RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl) +{ + NS_LOG_FUNCTION_NOARGS (); + { + CriticalSection cs (m_mutex); + + // + // If the simulator is running, we're pacing and have a meaningful + // realtime clock. If we're not, then m_currentTs is were we stopped. + // + uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs; + NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtimeNow(): schedule for time < m_currentTs"); + Scheduler::Event ev; + ev.impl = impl; + ev.key.m_ts = ts; + ev.key.m_uid = m_uid; + m_uid++; + ++m_unscheduledEvents; + m_events->Insert (ev); + m_synchronizer->Signal (); + } +} + +Time +RealtimeSimulatorImpl::RealtimeNow (void) const +{ + return TimeStep (m_synchronizer->GetCurrentRealtime ()); +} + +EventId +RealtimeSimulatorImpl::ScheduleDestroy (EventImpl *impl) +{ + NS_LOG_FUNCTION_NOARGS (); + + EventId id; + { + CriticalSection cs (m_mutex); + + // + // Time doesn't really matter here (especially in realtime mode). It is + // overridden by the uid of 2 which identifies this as an event to be + // executed at Simulator::Destroy time. + // + id = EventId (Ptr (impl, false), m_currentTs, 2); + m_destroyEvents.push_back (id); + m_uid++; + } + + return id; +} + +Time +RealtimeSimulatorImpl::GetDelayLeft (const EventId &id) const +{ + // + // If the event has expired, there is no delay until it runs. It is not the + // case that there is a negative time until it runs. + // + if (IsExpired (id)) + { + return TimeStep (0); + } + + return TimeStep (id.GetTs () - m_currentTs); +} + +void +RealtimeSimulatorImpl::Remove (const EventId &id) +{ + if (id.GetUid () == 2) + { + // destroy events. + for (DestroyEvents::iterator i = m_destroyEvents.begin (); + i != m_destroyEvents.end (); + i++) + { + if (*i == id) + { + m_destroyEvents.erase (i); + break; + } + } + return; + } + if (IsExpired (id)) + { + return; + } + + { + CriticalSection cs (m_mutex); + + Scheduler::Event event; + event.impl = id.PeekEventImpl (); + event.key.m_ts = id.GetTs (); + event.key.m_uid = id.GetUid (); + + m_events->Remove (event); + --m_unscheduledEvents; + event.impl->Cancel (); + event.impl->Unref (); + } +} + +void +RealtimeSimulatorImpl::Cancel (const EventId &id) +{ + if (IsExpired (id) == false) + { + id.PeekEventImpl ()->Cancel (); + } +} + +bool +RealtimeSimulatorImpl::IsExpired (const EventId &ev) const +{ + if (ev.GetUid () == 2) + { + // destroy events. + for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); + i != m_destroyEvents.end (); i++) + { + if (*i == ev) + { + return false; + } + } + return true; + } + + // + // If the time of the event is less than the current timestamp of the + // simulator, the simulator has gone past the invocation time of the + // event, so the statement ev.GetTs () < m_currentTs does mean that + // the event has been fired even in realtime mode. + // + // The same is true for the next line involving the m_currentUid. + // + if (ev.PeekEventImpl () == 0 || + ev.GetTs () < m_currentTs || + (ev.GetTs () == m_currentTs && ev.GetUid () <= m_currentUid) || + ev.PeekEventImpl ()->IsCancelled ()) + { + return true; + } + else + { + return false; + } +} + +Time +RealtimeSimulatorImpl::GetMaximumSimulationTime (void) const +{ + // XXX: I am fairly certain other compilers use other non-standard + // post-fixes to indicate 64 bit constants. + return TimeStep (0x7fffffffffffffffLL); +} + +void +RealtimeSimulatorImpl::SetSynchronizationMode (enum SynchronizationMode mode) +{ + NS_LOG_FUNCTION (mode); + m_synchronizationMode = mode; +} + +RealtimeSimulatorImpl::SynchronizationMode +RealtimeSimulatorImpl::GetSynchronizationMode (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_synchronizationMode; +} + +void +RealtimeSimulatorImpl::SetHardLimit (Time limit) +{ + NS_LOG_FUNCTION (limit); + m_hardLimit = limit; +} + +Time +RealtimeSimulatorImpl::GetHardLimit (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_hardLimit; +} + +}; // namespace ns3 diff --git a/src/simulator/realtime-simulator-impl.h b/src/simulator/realtime-simulator-impl.h new file mode 100644 index 000000000..48484c8a6 --- /dev/null +++ b/src/simulator/realtime-simulator-impl.h @@ -0,0 +1,120 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 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; + * + * 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 REALTIME_SIMULATOR_IMPL_H +#define REALTIME_SIMULATOR_IMPL_H + +#include "simulator-impl.h" + +#include "scheduler.h" +#include "synchronizer.h" +#include "event-impl.h" + +#include "ns3/ptr.h" +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/system-mutex.h" + +#include + +namespace ns3 { + +class RealtimeSimulatorImpl : public SimulatorImpl +{ +public: + static TypeId GetTypeId (void); + + /** + * Enumeration of the types of packets supported in the class. + * + */ + enum SynchronizationMode { + SYNC_BEST_EFFORT, /** Make a best effort to keep synced to real-time */ + SYNC_HARD_LIMIT, /** Keep to real-time within a tolerance or die trying */ + }; + + RealtimeSimulatorImpl (); + ~RealtimeSimulatorImpl (); + + virtual void Destroy (); + virtual bool IsFinished (void) const; + virtual Time Next (void) const; + virtual void Stop (void); + virtual void Stop (Time const &time); + virtual EventId Schedule (Time const &time, EventImpl *event); + virtual EventId ScheduleNow (EventImpl *event); + virtual EventId ScheduleDestroy (EventImpl *event); + virtual void Remove (const EventId &ev); + virtual void Cancel (const EventId &ev); + virtual bool IsExpired (const EventId &ev) const; + virtual void Run (void); + virtual void RunOneEvent (void); + virtual Time Now (void) const; + virtual Time GetDelayLeft (const EventId &id) const; + virtual Time GetMaximumSimulationTime (void) const; + virtual void SetScheduler (Ptr scheduler); + virtual Ptr GetScheduler (void) const; + + void ScheduleRealtime (Time const &time, EventImpl *event); + void ScheduleRealtimeNow (EventImpl *event); + Time RealtimeNow (void) const; + + void SetSynchronizationMode (RealtimeSimulatorImpl::SynchronizationMode mode); + RealtimeSimulatorImpl::SynchronizationMode GetSynchronizationMode (void) const; + + void SetHardLimit (Time limit); + Time GetHardLimit (void) const; + +private: + bool Running (void) const; + bool Realtime (void) const; + + void ProcessOneEvent (void); + uint64_t NextTs (void) const; + + typedef std::list DestroyEvents; + DestroyEvents m_destroyEvents; + uint64_t m_stopAt; + bool m_stop; + bool m_running; + + // The following variables are protected using the m_mutex + Ptr m_events; + int m_unscheduledEvents; + uint32_t m_uid; + uint32_t m_currentUid; + uint64_t m_currentTs; + + mutable SystemMutex m_mutex; + + Ptr m_synchronizer; + + /** + * The policy to use if the simulation cannot keep synchronized to real-time. + */ + SynchronizationMode m_synchronizationMode; + + /** + * The maximum allowable drift from real-time in SYNC_HARD_LIMIT mode. + */ + Time m_hardLimit; +}; + +} // namespace ns3 + +#endif /* REALTIME_SIMULATOR_IMPL_H */ diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h index 17e1ed021..5b26392ad 100644 --- a/src/simulator/scheduler.h +++ b/src/simulator/scheduler.h @@ -22,11 +22,12 @@ #define SCHEDULER_H #include -#include "event-id.h" #include "ns3/object.h" namespace ns3 { +class EventImpl; + /** * \ingroup simulator * \defgroup scheduler Scheduler @@ -38,13 +39,16 @@ namespace ns3 { * 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 pure virtual methods defined here. Namely: - * - ns3::Scheduler::Insert - * - ns3::Scheduler::IsEmpty - * - ns3::Scheduler::PeekNext - * - ns3::Scheduler::RemoveNext - * - ns3::Scheduler::Remove + * all the pure virtual methods defined here. * + * The only tricky aspect of this API is the memory management of + * the EventImpl pointer which is a member of the Event data structure. + * The lifetime of this pointer is assumed to always be longer than + * the lifetime of the Scheduler class which means that the caller + * is responsible for ensuring that this invariant holds through + * calling EventImpl::Ref and EventImpl::Unref at the right time. + * Typically, ::Ref is called before Insert and ::Unref is called + * after a call to one of the Remove methods. */ class Scheduler : public Object { @@ -55,15 +59,17 @@ class Scheduler : public Object uint64_t m_ts; uint32_t m_uid; }; + struct Event { + EventImpl *impl; + EventKey key; + }; virtual ~Scheduler () = 0; /** - * \param id event to store in the event list - * - * This method takes ownership of the event pointer. + * \param ev event to store in the event list */ - virtual void Insert (const EventId &id) = 0; + virtual void Insert (const Event &ev) = 0; /** * \returns true if the event list is empty and false otherwise. */ @@ -74,23 +80,49 @@ class Scheduler : public Object * * This method cannot be invoked if the list is empty. */ - virtual EventId PeekNext (void) const = 0; + virtual Event PeekNext (void) const = 0; /** * This method cannot be invoked if the list is empty. * Remove the next earliest event from the event list. */ - virtual EventId RemoveNext (void) = 0; + virtual Event RemoveNext (void) = 0; /** * \param id the id of the event to remove - * \returns true if the id was found and removed - * successfully, false otherwise. * * This methods cannot be invoked if the list is empty. */ - virtual bool Remove (const EventId &id) = 0; + virtual void Remove (const Event &ev) = 0; }; -}; // namespace ns3 +/* Note the invariants which this function must provide: + * - irreflexibility: f (x,x) is false) + * - antisymmetry: f(x,y) = !f(y,x) + * - transitivity: f(x,y) and f(y,z) => f(x,z) + */ +inline bool operator < (const Scheduler::EventKey &a, const Scheduler::EventKey &b) +{ + if (a.m_ts < b.m_ts) + { + return true; + } + else if (a.m_ts == b.m_ts && + a.m_uid < b.m_uid) + { + return true; + } + else + { + return false; + } +} + +inline bool operator < (const Scheduler::Event &a, const Scheduler::Event &b) +{ + return a.key < b.key; +} + + +} // namespace ns3 #endif /* SCHEDULER_H */ diff --git a/src/simulator/simulator-impl.h b/src/simulator/simulator-impl.h new file mode 100644 index 000000000..c84d82f83 --- /dev/null +++ b/src/simulator/simulator-impl.h @@ -0,0 +1,59 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 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 + */ + +#ifndef SIMULATOR_IMPL_H +#define SIMULATOR_IMPL_H + +#include "event-impl.h" +#include "event-id.h" +#include "nstime.h" +#include "ns3/object.h" +#include "ns3/ptr.h" + +namespace ns3 { + +class Scheduler; + +class SimulatorImpl : public Object +{ +public: + virtual void Destroy () = 0; + virtual bool IsFinished (void) const = 0; + virtual Time Next (void) const = 0; + virtual void Stop (void) = 0; + virtual void Stop (Time const &time) = 0; + virtual EventId Schedule (Time const &time, EventImpl *event) = 0; + virtual EventId ScheduleNow (EventImpl *event) = 0; + virtual EventId ScheduleDestroy (EventImpl *event) = 0; + virtual void Remove (const EventId &ev) = 0; + virtual void Cancel (const EventId &ev) = 0; + virtual bool IsExpired (const EventId &ev) const = 0; + virtual void Run (void) = 0; + virtual void RunOneEvent (void) = 0; + virtual Time Now (void) const = 0; + virtual Time GetDelayLeft (const EventId &id) const = 0; + virtual Time GetMaximumSimulationTime (void) const = 0; + virtual void SetScheduler (Ptr scheduler) = 0; + virtual Ptr GetScheduler (void) const = 0; +}; + +} // namespace ns3 + +#endif /* SIMULATOR_IMPL_H */ diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 00af60a65..36d3f8854 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -19,569 +19,280 @@ */ #include "simulator.h" +#include "simulator-impl.h" +#include "default-simulator-impl.h" +#include "realtime-simulator-impl.h" #include "scheduler.h" +#include "map-scheduler.h" #include "event-impl.h" #include "ns3/ptr.h" -#include "ns3/pointer.h" +#include "ns3/string.h" +#include "ns3/object-factory.h" +#include "ns3/global-value.h" #include "ns3/assert.h" #include "ns3/log.h" - #include #include #include #include #include -#define noTRACE_SIMU 1 - -#ifdef TRACE_SIMU -#include -# define TRACE(x) \ -std::cout << "SIMU TRACE " << Simulator::Now () << " " << x << std::endl; -# define TRACE_S(x) \ -std::cout << "SIMU TRACE " << x << std::endl; -#else /* TRACE_SIMU */ -# define TRACE(format,...) -# define TRACE_S(format,...) -#endif /* TRACE_SIMU */ - +NS_LOG_COMPONENT_DEFINE ("Simulator"); namespace ns3 { -/** - * \brief private implementation detail of the Simulator API. - */ -class SimulatorPrivate : public Object -{ -public: - static TypeId GetTypeId (void); - - SimulatorPrivate (); - ~SimulatorPrivate (); - - void Destroy (); - - void EnableLogTo (char const *filename); - - bool IsFinished (void) const; - Time Next (void) const; - void Stop (void); - void Stop (Time const &time); - EventId Schedule (Time const &time, const Ptr &event); - EventId ScheduleNow (const Ptr &event); - EventId ScheduleDestroy (const Ptr &event); - void Remove (const EventId &ev); - void Cancel (const EventId &ev); - bool IsExpired (const EventId &ev) const; - void Run (void); - Time Now (void) const; - Time GetDelayLeft (const EventId &id) const; - Time GetMaximumSimulationTime (void) const; - - void SetScheduler (Ptr scheduler); - Ptr GetScheduler (void) const; - -private: - void ProcessOneEvent (void); - uint64_t NextTs (void) const; - - typedef std::list DestroyEvents; - DestroyEvents m_destroyEvents; - uint64_t m_stopAt; - bool m_stop; - Ptr m_events; - uint32_t m_uid; - uint32_t m_currentUid; - uint64_t m_currentTs; - std::ofstream m_log; - std::ifstream m_inputLog; - bool m_logEnable; - // number of events that have been inserted but not yet scheduled, - // not counting the "destroy" events; this is used for validation - int m_unscheduledEvents; -}; - -NS_OBJECT_ENSURE_REGISTERED (SimulatorPrivate); - - -TypeId -SimulatorPrivate::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::SimulatorPrivate") - .SetParent () - .AddConstructor () - .AddAttribute ("Scheduler", - "The Scheduler used to handle all simulation events.", - PointerValue (), - MakePointerAccessor (&SimulatorPrivate::SetScheduler, - &SimulatorPrivate::GetScheduler), - MakePointerChecker ()) - ; - return tid; -} - -SimulatorPrivate::SimulatorPrivate () -{ - m_stop = false; - m_stopAt = 0; - // uids are allocated from 4. - // uid 0 is "invalid" events - // uid 1 is "now" events - // uid 2 is "destroy" events - m_uid = 4; - // before ::Run is entered, the m_currentUid will be zero - m_currentUid = 0; - m_logEnable = false; - m_currentTs = 0; - m_unscheduledEvents = 0; -} - -SimulatorPrivate::~SimulatorPrivate () -{ - while (!m_events->IsEmpty ()) - { - EventId next = m_events->RemoveNext (); - } - m_events = 0; -} -void -SimulatorPrivate::Destroy () -{ - while (!m_destroyEvents.empty ()) - { - Ptr ev = m_destroyEvents.front ().PeekEventImpl (); - m_destroyEvents.pop_front (); - TRACE ("handle destroy " << ev); - if (!ev->IsCancelled ()) - { - ev->Invoke (); - } - } -} - -void -SimulatorPrivate::SetScheduler (Ptr scheduler) -{ - if (m_events != 0) - { - while (!m_events->IsEmpty ()) - { - EventId next = m_events->RemoveNext (); - scheduler->Insert (next); - } - } - m_events = scheduler; -} - -Ptr -SimulatorPrivate::GetScheduler (void) const -{ - return m_events; -} - -void -SimulatorPrivate::EnableLogTo (char const *filename) -{ - m_log.open (filename); - m_logEnable = true; -} - -void -SimulatorPrivate::ProcessOneEvent (void) -{ - EventId next = m_events->RemoveNext (); - - NS_ASSERT (next.GetTs () >= m_currentTs); - --m_unscheduledEvents; - - TRACE ("handle " << nextEv); - m_currentTs = next.GetTs (); - m_currentUid = next.GetUid (); - if (m_logEnable) - { - m_log << "e "<Invoke (); -} - -bool -SimulatorPrivate::IsFinished (void) const -{ - return m_events->IsEmpty (); -} -uint64_t -SimulatorPrivate::NextTs (void) const -{ - NS_ASSERT (!m_events->IsEmpty ()); - EventId id = m_events->PeekNext (); - return id.GetTs (); -} -Time -SimulatorPrivate::Next (void) const -{ - return TimeStep (NextTs ()); -} - -void -SimulatorPrivate::Run (void) -{ - - while (!m_events->IsEmpty () && !m_stop && - (m_stopAt == 0 || m_stopAt > NextTs ())) - { - ProcessOneEvent (); - } - - // If the simulator stopped naturally by lack of events, make a - // consistency test to check that we didn't lose any events along the way. - NS_ASSERT(!m_events->IsEmpty () || m_unscheduledEvents == 0); - - m_log.close (); -} - - -void -SimulatorPrivate::Stop (void) -{ - m_stop = true; -} -void -SimulatorPrivate::Stop (Time const &time) -{ - NS_ASSERT (time.IsPositive ()); - Time absolute = Simulator::Now () + time; - m_stopAt = absolute.GetTimeStep (); -} -EventId -SimulatorPrivate::Schedule (Time const &time, const Ptr &event) -{ - NS_ASSERT (time.IsPositive ()); - NS_ASSERT (time >= TimeStep (m_currentTs)); - uint64_t ts = (uint64_t) time.GetTimeStep (); - EventId id (event, ts, m_uid); - if (m_logEnable) - { - m_log << "i "<Insert (id); - return id; -} -EventId -SimulatorPrivate::ScheduleNow (const Ptr &event) -{ - EventId id (event, m_currentTs, m_uid); - if (m_logEnable) - { - m_log << "i "<Insert (id); - return id; -} -EventId -SimulatorPrivate::ScheduleDestroy (const Ptr &event) -{ - EventId id (event, m_currentTs, 2); - m_destroyEvents.push_back (id); - if (m_logEnable) - { - m_log << "id " << m_currentUid << " " << Now ().GetTimeStep () << " " - << m_uid << std::endl; - } - m_uid++; - return id; -} - -Time -SimulatorPrivate::Now (void) const -{ - return TimeStep (m_currentTs); -} -Time -SimulatorPrivate::GetDelayLeft (const EventId &id) const -{ - if (IsExpired (id)) - { - return TimeStep (0); - } - else - { - return TimeStep (id.GetTs () - m_currentTs); - } -} - -void -SimulatorPrivate::Remove (const EventId &ev) -{ - if (ev.GetUid () == 2) - { - // destroy events. - for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) - { - if (*i == ev) - { - m_destroyEvents.erase (i); - break; - } - } - return; - } - if (IsExpired (ev)) - { - return; - } - m_events->Remove (ev); - Cancel (ev); - - if (m_logEnable) - { - m_log << "r " << m_currentUid << " " << m_currentTs << " " - << ev.GetUid () << " " << ev.GetTs () << std::endl; - } - --m_unscheduledEvents; -} - -void -SimulatorPrivate::Cancel (const EventId &id) -{ - if (!IsExpired (id)) - { - id.PeekEventImpl ()->Cancel (); - } -} - -bool -SimulatorPrivate::IsExpired (const EventId &ev) const -{ - if (ev.GetUid () == 2) - { - // destroy events. - for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) - { - if (*i == ev) - { - return false; - } - } - return true; - } - if (ev.PeekEventImpl () == 0 || - ev.GetTs () < m_currentTs || - (ev.GetTs () == m_currentTs && - ev.GetUid () <= m_currentUid) || - ev.PeekEventImpl ()->IsCancelled ()) - { - return true; - } - else - { - return false; - } -} - -Time -SimulatorPrivate::GetMaximumSimulationTime (void) const -{ - // XXX: I am fairly certain other compilers use other non-standard - // post-fixes to indicate 64 bit constants. - return TimeStep (0x7fffffffffffffffLL); -} - - - -}; // namespace ns3 - - -#include "map-scheduler.h" - - -namespace ns3 { - -Ptr Simulator::m_priv = 0; - -void Simulator::SetScheduler (Ptr scheduler) -{ - GetPriv ()->SetScheduler (scheduler); -} -void Simulator::EnableLogTo (char const *filename) -{ - GetPriv ()->EnableLogTo (filename); -} +GlobalValue g_simTypeImpl = GlobalValue ("SimulatorImplementationType", + "The object class to use as the simulator implementation", + StringValue ("ns3::DefaultSimulatorImpl"), + MakeStringChecker ()); #ifdef NS3_LOG_ENABLE + +// +// Note: Calls that take TimePrinter as a parameter are defined as nothing +// in the logging module if NS3_LOG_ENABLE is not defined. +// + static void TimePrinter (std::ostream &os) { os << Simulator::Now (); } + #endif /* NS3_LOG_ENABLE */ -Ptr -Simulator::GetPriv (void) +static Ptr *PeekImpl (void) { - if (m_priv == 0) + static Ptr impl = 0; + return &impl; +} + +static SimulatorImpl * GetImpl (void) +{ + Ptr &impl = *PeekImpl (); + /* Please, don't include any calls to logging macros in this function + * or pay the price, that is, stack explosions. + */ + if (impl == 0) { - /* Note: we call LogSetTimePrinter below _after_ calling CreateObject because - * CreateObject can trigger calls to the logging framework which would call - * the TimePrinter function above which would call Simulator::Now which would - * call Simulator::GetPriv, and, thus, get us in an infinite recursion until the - * stack explodes. - */ - m_priv = CreateObject (); + ObjectFactory factory; + StringValue s; + + g_simTypeImpl.GetValue (s); + factory.SetTypeId (s.Get ()); + impl = factory.Create (); + Ptr scheduler = CreateObject (); - m_priv->SetScheduler (scheduler); + impl->SetScheduler (scheduler); + +// +// Note: we call LogSetTimePrinter _after_ creating the implementation +// object because the act of creation can trigger calls to the logging +// framework which would call the TimePrinter function which would call +// Simulator::Now which would call Simulator::GetImpl, and, thus, get us +// in an infinite recursion until the stack explodes. +// LogSetTimePrinter (&TimePrinter); } - TRACE_S ("priv " << m_priv); - return m_priv; + return PeekPointer (impl); } void Simulator::Destroy (void) { - if (m_priv == 0) + NS_LOG_FUNCTION_NOARGS (); + + Ptr &impl = *PeekImpl (); + if (impl == 0) { return; } - /* Note: we have to call LogSetTimePrinter (0) below because if we do not do this, - * and restart a simulation after this call to Destroy, (which is legal), - * Simulator::GetPriv will trigger again an infinite recursion until the stack - * explodes. + /* Note: we have to call LogSetTimePrinter (0) below because if we do not do + * this, and restart a simulation after this call to Destroy, (which is + * legal), Simulator::GetImpl will trigger again an infinite recursion until + * the stack explodes. */ LogSetTimePrinter (0); - m_priv->Destroy (); - m_priv = 0; + impl->Destroy (); + impl = 0; } +void +Simulator::SetScheduler (Ptr scheduler) +{ + NS_LOG_FUNCTION (scheduler); + GetImpl ()->SetScheduler (scheduler); +} + +void +Simulator::EnableLogTo (char const *filename) +{} bool Simulator::IsFinished (void) { - return GetPriv ()->IsFinished (); + NS_LOG_FUNCTION_NOARGS (); + return GetImpl ()->IsFinished (); } + Time Simulator::Next (void) { - return GetPriv ()->Next (); + NS_LOG_FUNCTION_NOARGS (); + return GetImpl ()->Next (); } - void Simulator::Run (void) { - GetPriv ()->Run (); + NS_LOG_FUNCTION_NOARGS (); + GetImpl ()->Run (); } + +void +Simulator::RunOneEvent (void) +{ + NS_LOG_FUNCTION_NOARGS (); + GetImpl ()->RunOneEvent (); +} + void Simulator::Stop (void) { - TRACE ("stop"); - GetPriv ()->Stop (); + NS_LOG_LOGIC ("stop"); + GetImpl ()->Stop (); } + void Simulator::Stop (Time const &time) { - GetPriv ()->Stop (time); + NS_LOG_FUNCTION (time); + GetImpl ()->Stop (time); } + Time Simulator::Now (void) { - return GetPriv ()->Now (); + /* Please, don't include any calls to logging macros in this function + * or pay the price, that is, stack explosions. + */ + return GetImpl ()->Now (); } + Time Simulator::GetDelayLeft (const EventId &id) { - return GetPriv ()->GetDelayLeft (id); + NS_LOG_FUNCTION (&id); + return GetImpl ()->GetDelayLeft (id); } -Ptr -Simulator::MakeEvent (void (*f) (void)) -{ - // zero arg version - class EventFunctionImpl0 : public EventImpl { - public: - typedef void (*F)(void); - - EventFunctionImpl0 (F function) - : m_function (function) - {} - virtual ~EventFunctionImpl0 () {} - protected: - virtual void Notify (void) { - (*m_function) (); - } - private: - F m_function; - } *ev = new EventFunctionImpl0 (f); - return Ptr (ev, false); -} EventId Simulator::Schedule (Time const &time, const Ptr &ev) { - return GetPriv ()->Schedule (Now () + time, ev); + NS_LOG_FUNCTION (time << ev); + return DoSchedule (time, GetPointer (ev)); } + EventId Simulator::ScheduleNow (const Ptr &ev) { - return GetPriv ()->ScheduleNow (ev); + NS_LOG_FUNCTION (ev); + return DoScheduleNow (GetPointer (ev)); } + EventId Simulator::ScheduleDestroy (const Ptr &ev) { - return GetPriv ()->ScheduleDestroy (ev); -} + NS_LOG_FUNCTION (ev); + return DoScheduleDestroy (GetPointer (ev)); +} +EventId +Simulator::DoSchedule (Time const &time, EventImpl *impl) +{ + return GetImpl ()->Schedule (time, impl); +} +EventId +Simulator::DoScheduleNow (EventImpl *impl) +{ + return GetImpl ()->ScheduleNow (impl); +} +EventId +Simulator::DoScheduleDestroy (EventImpl *impl) +{ + return GetImpl ()->ScheduleDestroy (impl); +} + + EventId Simulator::Schedule (Time const &time, void (*f) (void)) { - return Schedule (time, MakeEvent (f)); + NS_LOG_FUNCTION (time << f); + return DoSchedule (time, MakeEvent (f)); } + EventId Simulator::ScheduleNow (void (*f) (void)) { - return ScheduleNow (MakeEvent (f)); + NS_LOG_FUNCTION (f); + return DoScheduleNow (MakeEvent (f)); } + EventId Simulator::ScheduleDestroy (void (*f) (void)) { - return ScheduleDestroy (MakeEvent (f)); + NS_LOG_FUNCTION (f); + return DoScheduleDestroy (MakeEvent (f)); } - void Simulator::Remove (const EventId &ev) { - return GetPriv ()->Remove (ev); + NS_LOG_FUNCTION (&ev); + return GetImpl ()->Remove (ev); } void Simulator::Cancel (const EventId &ev) { - return GetPriv ()->Cancel (ev); + NS_LOG_FUNCTION (&ev); + return GetImpl ()->Cancel (ev); } + bool Simulator::IsExpired (const EventId &id) { - return GetPriv ()->IsExpired (id); + NS_LOG_FUNCTION (&id); + return GetImpl ()->IsExpired (id); } Time Now (void) { + NS_LOG_FUNCTION_NOARGS (); return Time (Simulator::Now ()); } Time Simulator::GetMaximumSimulationTime (void) { - return GetPriv ()->GetMaximumSimulationTime (); + NS_LOG_FUNCTION_NOARGS (); + return GetImpl ()->GetMaximumSimulationTime (); } +void +Simulator::SetImplementation (Ptr impl) +{ + NS_FATAL_ERROR ("TODO"); +} +Ptr +Simulator::GetImplementation (void) +{ + return GetImpl (); +} + + + } // namespace ns3 @@ -697,25 +408,31 @@ private: SimulatorTests::SimulatorTests () : Test ("Simulator") {} + SimulatorTests::~SimulatorTests () {} + void SimulatorTests::Ref (void) const {} + void SimulatorTests::Unref (void) const {} + uint64_t SimulatorTests::NowUs (void) { uint64_t ns = Now ().GetNanoSeconds (); return ns / 1000; } + void SimulatorTests::A (int a) { m_a = false; } + void SimulatorTests::B (int b) { @@ -730,11 +447,13 @@ SimulatorTests::B (int b) Simulator::Remove (m_idC); Simulator::Schedule (MicroSeconds (10), &SimulatorTests::D, this, 4); } + void SimulatorTests::C (int c) { m_c = false; } + void SimulatorTests::D (int d) { @@ -747,6 +466,7 @@ SimulatorTests::D (int d) m_d = true; } } + void SimulatorTests::destroy (void) { @@ -755,21 +475,27 @@ SimulatorTests::destroy (void) m_destroy = true; } } + void SimulatorTests::bar0 (void) {} + void SimulatorTests::bar1 (int) {} + void SimulatorTests::bar2 (int, int) {} + void SimulatorTests::bar3 (int, int, int) {} + void SimulatorTests::bar4 (int, int, int, int) {} + void SimulatorTests::bar5 (int, int, int, int, int) {} @@ -777,15 +503,19 @@ SimulatorTests::bar5 (int, int, int, int, int) void SimulatorTests::baz1 (int &) {} + void SimulatorTests::baz2 (int &, int &) {} + void SimulatorTests::baz3 (int &, int &, int &) {} + void SimulatorTests::baz4 (int &, int &, int &, int &) {} + void SimulatorTests::baz5 (int &, int &, int &, int &, int &) {} @@ -793,15 +523,19 @@ SimulatorTests::baz5 (int &, int &, int &, int &, int &) void SimulatorTests::cbaz1 (const int &) {} + void SimulatorTests::cbaz2 (const int &, const int &) {} + void SimulatorTests::cbaz3 (const int &, const int &, const int &) {} + void SimulatorTests::cbaz4 (const int &, const int &, const int &, const int &) {} + void SimulatorTests::cbaz5 (const int &, const int &, const int &, const int &, const int &) {} @@ -809,18 +543,23 @@ SimulatorTests::cbaz5 (const int &, const int &, const int &, const int &, const 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 {} @@ -828,15 +567,19 @@ 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 {} @@ -844,15 +587,19 @@ 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 {} @@ -881,6 +628,7 @@ SimulatorTests::RunOneTest (void) NS_TEST_ASSERT (m_d); return result; } + void SimulatorTests::RunTestsConst (void) const { @@ -980,7 +728,6 @@ SimulatorTests::RunTests (void) } Simulator::Destroy (); - Simulator::Schedule (Seconds (0.0), &foo0); Simulator::Schedule (Seconds (0.0), &foo1, 0); Simulator::Schedule (Seconds (0.0), &foo2, 0, 0); diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index 892f9eb2f..11a4a1a9d 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -21,18 +21,20 @@ #ifndef SIMULATOR_H #define SIMULATOR_H -#include #include "event-id.h" #include "event-impl.h" +#include "make-event.h" #include "nstime.h" -#include "scheduler.h" -#include "ns3/type-traits.h" + +#include "ns3/deprecated.h" + +#include +#include namespace ns3 { - -class SimulatorPrivate; -class SchedulerFactory; +class SimulatorImpl; +class Scheduler; /** * \ingroup simulator @@ -52,14 +54,25 @@ class SchedulerFactory; * is shown below: * \include samples/main-simulator.cc */ -class Simulator { +class Simulator +{ public: /** - * Enable ParallelSimulation. - * This method must be invoked before every other method exported - * by the Simulator class. + * \param impl a new simulator implementation + * + * The simulator provides a mechanism to swap out different implementations. + * For example, the default implementation is a single-threaded simulator + * that performs no realtime synchronization. By calling this method, you + * can substitute in a new simulator implementation that might be multi- + * threaded and synchronize events to a realtime clock. + * + * The simulator implementation can be set when the simulator is not + * running. */ - static void EnableParallelSimulation (void); + static void SetImplementation (Ptr impl); + + static Ptr GetImplementation (void); + /** * \param scheduler a new event scheduler * @@ -69,27 +82,7 @@ public: */ static void SetScheduler (Ptr scheduler); - /** - * Force the use of a user-provided event scheduler. - * This method must be invoked before any other method exported - * by the Simulator class. - */ - static void SetExternal (const std::string &name); - - /** - * Enable logging to the file identified by filename. If the file - * does not exist, it is created. If it exists, it is destroyed and - * re-created. Every scheduling event is logged to this file in a - * simple text format which can be read back by the event replay - * utility. This allows you to record the scheduling behavior of - * a simulation, and measure the exact overhead related to - * event scheduling with the event replay utility. It is also possible - * to compare the performance of every scheduling algorithms on this - * specific scheduling load. - * This method must be invoked before any call to Simulator::run - * @param filename the name of the file to log to - */ - static void EnableLogTo (char const *filename); + static void EnableLogTo (char const *filename) NS_DEPRECATED; /** * Every event scheduled by the Simulator::insertAtDestroy method is @@ -103,7 +96,6 @@ public: */ static void Destroy (void); - /** * If there any any events lefts to be scheduled, return * true. Return false otherwise. @@ -125,12 +117,19 @@ public: * is greater than or equal to the stop time. */ static void Run (void); + + /** + * Process only the next simulation event, then return immediately. + */ + static void RunOneEvent (void); + /** * If an event invokes this method, it will be the last * event scheduled by the Simulator::run method before * returning to the caller. */ static void Stop (void); + /** * Force the Simulator::run method to return to the caller when the * expiration time of the next event to be processed is greater than @@ -141,9 +140,13 @@ public: static void Stop (Time const &time); /** - * Schedule an event to expire when the time "now + time" - * is reached. When the event expires, the input method - * will be invoked on the input object. + * Schedule an event to expire at the relative time "time" + * is reached. This can be thought of as scheduling an event + * for the current simulation time plus the Time passed as a + * parameter + * + * When the event expires (when it becomes due to be run), the + * input method will be invoked on the input object. * * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -152,6 +155,7 @@ public: */ template 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 @@ -161,6 +165,7 @@ public: */ template 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 @@ -171,6 +176,7 @@ public: */ template 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 @@ -183,6 +189,7 @@ public: template 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 @@ -196,6 +203,7 @@ public: template 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 @@ -217,6 +225,7 @@ public: * @returns an id for the scheduled event. */ static EventId Schedule (Time const &time, void (*f) (void)); + /** * @param time the relative expiration time of the event. * @param f the function to invoke @@ -225,6 +234,7 @@ public: */ template static EventId Schedule (Time const &time, void (*f) (U1), T1 a1); + /** * @param time the relative expiration time of the event. * @param f the function to invoke @@ -234,6 +244,7 @@ public: */ template static EventId Schedule (Time const &time, void (*f) (U1,U2), T1 a1, T2 a2); + /** * @param time the relative expiration time of the event. * @param f the function to invoke @@ -244,6 +255,7 @@ public: */ template static EventId Schedule (Time const &time, void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3); + /** * @param time the relative expiration time of the event. * @param f the function to invoke @@ -256,6 +268,7 @@ public: template static EventId Schedule (Time const &time, void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4); + /** * @param time the relative expiration time of the event. * @param f the function to invoke @@ -270,7 +283,6 @@ public: typename T1, typename T2, typename T3, typename T4, typename T5> static EventId Schedule (Time const &time, void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); - /** * Schedule an event to expire Now. All events scheduled to * to expire "Now" are scheduled FIFO, after all normal events @@ -281,6 +293,7 @@ public: */ template 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 @@ -289,6 +302,7 @@ public: template 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 @@ -298,6 +312,7 @@ public: template 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 @@ -308,6 +323,7 @@ public: template 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 @@ -337,6 +353,7 @@ public: * @param f the function to invoke */ static EventId ScheduleNow (void (*f) (void)); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -344,6 +361,7 @@ public: template static EventId ScheduleNow (void (*f) (U1), T1 a1); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -352,6 +370,7 @@ public: template static EventId ScheduleNow (void (*f) (U1,U2), T1 a1, T2 a2); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -361,6 +380,7 @@ public: template static EventId ScheduleNow (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -371,6 +391,7 @@ public: template static EventId ScheduleNow (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -383,7 +404,6 @@ public: typename T1, typename T2, typename T3, typename T4, typename T5> static EventId ScheduleNow (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); - /** * Schedule an event to expire at Destroy time. All events * scheduled to expire at "Destroy" time are scheduled FIFO, @@ -395,6 +415,7 @@ public: */ template 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 @@ -403,6 +424,7 @@ public: template 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 @@ -412,6 +434,7 @@ public: template 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 @@ -422,6 +445,7 @@ public: template 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 @@ -451,6 +475,7 @@ public: * @param f the function to invoke */ static EventId ScheduleDestroy (void (*f) (void)); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -458,6 +483,7 @@ public: template static EventId ScheduleDestroy (void (*f) (U1), T1 a1); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -466,6 +492,7 @@ public: template static EventId ScheduleDestroy (void (*f) (U1,U2), T1 a1, T2 a2); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -475,6 +502,7 @@ public: template static EventId ScheduleDestroy (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -485,6 +513,7 @@ public: template static EventId ScheduleDestroy (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4); + /** * @param f the function to invoke * @param a1 the first argument to pass to the function to invoke @@ -509,6 +538,7 @@ public: * @param id the event to remove from the list of scheduled events. */ 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. @@ -522,6 +552,7 @@ public: * @param id the event to cancel */ static void Cancel (const EventId &id); + /** * This method has O(1) complexity. * Note that it is not possible to test for the expiration of @@ -535,10 +566,12 @@ public: * @returns true if the event has expired, false otherwise. */ static bool IsExpired (const EventId &id); + /** * Return the "current simulation time". */ static Time Now (void); + /** * \param id the event id to analyse * \returns the delay left until the input event id expires. @@ -554,50 +587,41 @@ public: * The returned value will always be bigger than or equal to Simulator::Now. */ static Time GetMaximumSimulationTime (void); + + /** + * \param time delay until the event expires + * \param event the event to schedule + * \returns a unique identifier for the newly-scheduled event. + * + * This method will be typically used by language bindings + * to delegate events to their own subclass of the EventImpl base class. + */ + static EventId Schedule (Time const &time, const Ptr &event); + + /** + * \param event the event to schedule + * \returns a unique identifier for the newly-scheduled event. + * + * This method will be typically used by language bindings + * to delegate events to their own subclass of the EventImpl base class. + */ + static EventId ScheduleDestroy (const Ptr &event); + + /** + * \param event the event to schedule + * \returns a unique identifier for the newly-scheduled event. + * + * This method will be typically used by language bindings + * to delegate events to their own subclass of the EventImpl base class. + */ + static EventId ScheduleNow (const Ptr &event); private: Simulator (); ~Simulator (); - template - static Ptr MakeEvent (MEM mem_ptr, OBJ obj); - template - static Ptr MakeEvent (MEM mem_ptr, OBJ obj, T1 a1); - template - static Ptr MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2); - template - static Ptr MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3); - template - static Ptr MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); - template - static Ptr MakeEvent (MEM mem_ptr, OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); - static Ptr MakeEvent (void (*f) (void)); - template - static Ptr MakeEvent (void (*f) (U1), T1 a1); - template - static Ptr MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2); - template - static Ptr MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3); - template - static Ptr MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4); - template - static Ptr MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); - - static Ptr GetPriv (void); - static EventId Schedule (Time const &time, const Ptr &event); - static EventId ScheduleDestroy (const Ptr &event); - static EventId ScheduleNow (const Ptr &event); - static Ptr m_priv; + static EventId DoSchedule (Time const &time, EventImpl *event); + static EventId DoScheduleNow (EventImpl *event); + static EventId DoScheduleDestroy (EventImpl *event); }; /** @@ -613,341 +637,14 @@ private: */ Time Now (void); -}; // namespace ns3 - - -/******************************************************************** - Implementation of templates defined above - ********************************************************************/ +} // namespace ns3 namespace ns3 { -template -struct EventMemberImplObjTraits; - -template -struct EventMemberImplObjTraits -{ - static T &GetReference (T *p) { - return *p; - } -}; - -template -Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj) -{ - // zero argument version - class EventMemberImpl0 : public EventImpl { - public: - EventMemberImpl0 (OBJ obj, MEM function) - : m_obj (obj), - m_function (function) - {} - virtual ~EventMemberImpl0 () {} - private: - virtual void Notify (void) { - (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (); - } - OBJ m_obj; - MEM m_function; - } * ev = new EventMemberImpl0 (obj, mem_ptr); - return Ptr (ev, false); -} - - -template -Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1) -{ - // one argument version - class EventMemberImpl1 : public EventImpl { - public: - EventMemberImpl1 (OBJ obj, MEM function, T1 a1) - : m_obj (obj), - m_function (function), - m_a1 (a1) - {} - protected: - virtual ~EventMemberImpl1 () {} - private: - virtual void Notify (void) { - (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1); - } - OBJ m_obj; - MEM m_function; - typename TypeTraits::ReferencedType m_a1; - } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); - return Ptr (ev, false); -} - -template -Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) -{ - // two argument version - class EventMemberImpl2 : public EventImpl { - public: - EventMemberImpl2 (OBJ obj, MEM function, T1 a1, T2 a2) - : m_obj (obj), - m_function (function), - m_a1 (a1), - m_a2 (a2) - { } - protected: - virtual ~EventMemberImpl2 () {} - private: - virtual void Notify (void) { - (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2); - } - OBJ m_obj; - MEM m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - } *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2); - return Ptr (ev, false); -} - -template -Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) -{ - // three argument version - class EventMemberImpl3 : public EventImpl { - public: - EventMemberImpl3 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3) - : m_obj (obj), - m_function (function), - m_a1 (a1), - m_a2 (a2), - m_a3 (a3) - { } - protected: - virtual ~EventMemberImpl3 () {} - private: - virtual void Notify (void) { - (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3); - } - OBJ m_obj; - MEM m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - typename TypeTraits::ReferencedType m_a3; - } *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3); - return Ptr (ev, false); -} - -template -Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) -{ - // four argument version - class EventMemberImpl4 : public EventImpl { - public: - EventMemberImpl4 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4) - : m_obj (obj), - m_function (function), - m_a1 (a1), - m_a2 (a2), - m_a3 (a3), - m_a4 (a4) - { } - protected: - virtual ~EventMemberImpl4 () {} - private: - virtual void Notify (void) { - (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4); - } - OBJ m_obj; - MEM m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - typename TypeTraits::ReferencedType m_a3; - typename TypeTraits::ReferencedType m_a4; - } *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4); - return Ptr (ev, false); -} - -template -Ptr 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: - EventMemberImpl5 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) - : m_obj (obj), - m_function (function), - m_a1 (a1), - m_a2 (a2), - m_a3 (a3), - m_a4 (a4), - m_a5 (a5) - { } - protected: - virtual ~EventMemberImpl5 () {} - private: - virtual void Notify (void) { - (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5); - } - OBJ m_obj; - MEM m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - typename TypeTraits::ReferencedType m_a3; - typename TypeTraits::ReferencedType m_a4; - typename TypeTraits::ReferencedType m_a5; - } *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5); - return Ptr (ev, false); -} - -template -Ptr Simulator::MakeEvent (void (*f) (U1), T1 a1) -{ - // one arg version - class EventFunctionImpl1 : public EventImpl { - public: - typedef void (*F)(U1); - - EventFunctionImpl1 (F function, T1 a1) - : m_function (function), - m_a1 (a1) - { } - protected: - virtual ~EventFunctionImpl1 () {} - private: - virtual void Notify (void) { - (*m_function) (m_a1); - } - F m_function; - typename TypeTraits::ReferencedType m_a1; - } *ev = new EventFunctionImpl1 (f, a1); - return Ptr (ev, false); -} - -template -Ptr Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) -{ - // two arg version - class EventFunctionImpl2 : public EventImpl { - public: - typedef void (*F)(U1, U2); - - EventFunctionImpl2 (F function, T1 a1, T2 a2) - : m_function (function), - m_a1 (a1), - m_a2 (a2) - {} - protected: - virtual ~EventFunctionImpl2 () {} - private: - virtual void Notify (void) { - (*m_function) (m_a1, m_a2); - } - F m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - } *ev = new EventFunctionImpl2 (f, a1, a2); - return Ptr (ev, false); -} - -template -Ptr Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3) -{ - // three arg version - class EventFunctionImpl3 : public EventImpl { - public: - typedef void (*F)(U1, U2, U3); - - EventFunctionImpl3 (F function, T1 a1, T2 a2, T3 a3) - : m_function (function), - m_a1 (a1), - m_a2 (a2), - m_a3 (a3) - { } - protected: - virtual ~EventFunctionImpl3 () {} - private: - virtual void Notify (void) { - (*m_function) (m_a1, m_a2, m_a3); - } - F m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - typename TypeTraits::ReferencedType m_a3; - } *ev = new EventFunctionImpl3 (f, a1, a2, a3); - return Ptr (ev, false); -} - -template -Ptr Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) -{ - // four arg version - class EventFunctionImpl4 : public EventImpl { - public: - typedef void (*F)(U1, U2, U3, U4); - - EventFunctionImpl4 (F function, T1 a1, T2 a2, T3 a3, T4 a4) - : m_function (function), - m_a1 (a1), - m_a2 (a2), - m_a3 (a3), - m_a4 (a4) - { } - protected: - virtual ~EventFunctionImpl4 () {} - private: - virtual void Notify (void) { - (*m_function) (m_a1, m_a2, m_a3, m_a4); - } - F m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - typename TypeTraits::ReferencedType m_a3; - typename TypeTraits::ReferencedType m_a4; - } *ev = new EventFunctionImpl4 (f, a1, a2, a3, a4); - return Ptr (ev, false); -} - -template -Ptr 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 { - public: - typedef void (*F)(U1,U2,U3,U4,U5); - - EventFunctionImpl5 (F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) - : m_function (function), - m_a1 (a1), - m_a2 (a2), - m_a3 (a3), - m_a4 (a4), - m_a5 (a5) - {} - protected: - virtual ~EventFunctionImpl5 () {} - private: - virtual void Notify (void) { - (*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5); - } - F m_function; - typename TypeTraits::ReferencedType m_a1; - typename TypeTraits::ReferencedType m_a2; - typename TypeTraits::ReferencedType m_a3; - typename TypeTraits::ReferencedType m_a4; - typename TypeTraits::ReferencedType m_a5; - } *ev = new EventFunctionImpl5 (f, a1, a2, a3, a4, a5); - return Ptr (ev, false); -} - template EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj) { - return Schedule (time, MakeEvent (mem_ptr, obj)); + return DoSchedule (time, MakeEvent (mem_ptr, obj)); } @@ -955,28 +652,28 @@ template EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1) { - return Schedule (time, MakeEvent (mem_ptr, obj, a1)); + return DoSchedule (time, MakeEvent (mem_ptr, obj, a1)); } template EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2) { - return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2)); + return DoSchedule (time, MakeEvent (mem_ptr, obj, a1, a2)); } template 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)); + return DoSchedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3)); } template 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)); + return DoSchedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4)); } template EventId Simulator::Schedule (Time const &time, void (*f) (U1), T1 a1) { - return Schedule (time, MakeEvent (f, a1)); + return DoSchedule (time, MakeEvent (f, a1)); } template EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2), T1 a1, T2 a2) { - return Schedule (time, MakeEvent (f, a1, a2)); + return DoSchedule (time, MakeEvent (f, a1, a2)); } template EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3) { - return Schedule (time, MakeEvent (f, a1, a2, a3)); + return DoSchedule (time, MakeEvent (f, a1, a2, a3)); } template EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) { - return Schedule (time, MakeEvent (f, a1, a2, a3, a4)); + return DoSchedule (time, MakeEvent (f, a1, a2, a3, a4)); } template EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { - return Schedule (time, MakeEvent (f, a1, a2, a3, a4, a5)); + return DoSchedule (time, MakeEvent (f, a1, a2, a3, a4, a5)); } @@ -1028,7 +725,7 @@ template EventId Simulator::ScheduleNow (MEM mem_ptr, OBJ obj) { - return ScheduleNow (MakeEvent (mem_ptr, obj)); + return DoScheduleNow (MakeEvent (mem_ptr, obj)); } @@ -1037,7 +734,7 @@ template EventId Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj) { - return ScheduleDestroy (MakeEvent (mem_ptr, obj)); + return DoScheduleDestroy (MakeEvent (mem_ptr, obj)); } @@ -1128,7 +825,7 @@ template () + ; + return tid; +} + +Synchronizer::Synchronizer () + : m_realtimeOriginNano (0), m_simOriginNano (0) +{ +} + +Synchronizer::~Synchronizer () +{ +} + + bool +Synchronizer::Realtime (void) +{ + return DoRealtime (); +} + + uint64_t +Synchronizer::GetCurrentRealtime (void) +{ + return NanosecondToTimeStep (DoGetCurrentRealtime ()); +} + + void +Synchronizer::SetOrigin (uint64_t ts) +{ + m_simOriginNano = TimeStepToNanosecond (ts); + DoSetOrigin (m_simOriginNano); +} + + uint64_t +Synchronizer::GetOrigin (void) +{ + return NanosecondToTimeStep (m_simOriginNano); +} + + int64_t +Synchronizer::GetDrift (uint64_t ts) +{ + int64_t tDrift = DoGetDrift (TimeStepToNanosecond (ts)); + + if (tDrift < 0) + { + return -NanosecondToTimeStep (-tDrift); + } else { + return NanosecondToTimeStep (tDrift); + } +} + + bool +Synchronizer::Synchronize (uint64_t tsCurrent, uint64_t tsDelay) +{ + return DoSynchronize (TimeStepToNanosecond (tsCurrent), + TimeStepToNanosecond (tsDelay)); +} + + void +Synchronizer::Signal (void) +{ + DoSignal (); +} + + void +Synchronizer::SetCondition (bool cond) +{ + DoSetCondition (cond); +} + + void +Synchronizer::EventStart (void) +{ + DoEventStart (); +} + + uint64_t +Synchronizer::EventEnd (void) +{ + return NanosecondToTimeStep (DoEventEnd ()); +} + + uint64_t +Synchronizer::TimeStepToNanosecond (uint64_t ts) +{ + switch (TimeStepPrecision::Get ()) { + case TimeStepPrecision::S: + return ts * 1000000000; + case TimeStepPrecision::MS: + return ts * 1000000; + case TimeStepPrecision::US: + return ts * 1000; + case TimeStepPrecision::NS: + return ts; + case TimeStepPrecision::PS: + return ts / 1000; + case TimeStepPrecision::FS: + return ts / 1000000; + default: + NS_ASSERT_MSG (false, "Synchronizer::TimeStepToNanosecond: " + "Unexpected precision not implemented"); + return 0; + } +} + + uint64_t +Synchronizer::NanosecondToTimeStep (uint64_t ns) +{ + switch (TimeStepPrecision::Get ()) { + case TimeStepPrecision::S: + return ns / 1000000000; + case TimeStepPrecision::MS: + return ns / 1000000; + case TimeStepPrecision::US: + return ns / 1000; + case TimeStepPrecision::NS: + return ns; + case TimeStepPrecision::PS: + return ns * 1000; + case TimeStepPrecision::FS: + return ns * 1000000; + default: + NS_ASSERT_MSG (false, "Synchronizer::NanosecondToTimeStep: " + "Unexpected precision not implemented"); + return 0; + } +} + +}; // namespace ns3 + + diff --git a/src/simulator/synchronizer.h b/src/simulator/synchronizer.h new file mode 100644 index 000000000..b15c6dd0f --- /dev/null +++ b/src/simulator/synchronizer.h @@ -0,0 +1,334 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 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; + * + * 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 SYNCHRONIZER_H +#define SYNCHRONIZER_H + +#include +#include "nstime.h" +#include "ns3/object.h" + +namespace ns3 { + +/** + * @brief Base class used for synchronizing the simulation events to some + * real time "wall clock." + * + * The simulation clock is maintained as a 64-bit integer in a unit specified + * by the user through the TimeStepPrecision::Set function. This means that + * it is not possible to specify event expiration times with anything better + * than this user-specified accuracy. We use this clock for the simulation + * time. + * + * The real-time clock is maintained as a 64-bit integer count of nanoseconds. + * + * The synchronization between the simulation clock and the real-time clock + * is maintained using a combination of sleep-waiting, busy-waiting and a + * feedback loop. + */ +class Synchronizer : public Object +{ +public: + static TypeId GetTypeId (void); + + Synchronizer (); + virtual ~Synchronizer (); + +/** + * @brief Return true if this synchronizer is actually synchronizing to a + * realtime clock. The simulator sometimes needs to know this. + * @returns True if locked with realtime, false if not. + */ + bool Realtime (void); + +/** + * @brief Retrieve the value of the origin of the underlying normalized wall + * clock time in simulator timestep units. + * + * @returns The normalized wall clock time (in simulator timestep units). + * @see TimeStepPrecision::Get + * @see Synchronizer::SetOrigin + */ + uint64_t GetCurrentRealtime (void); + +/** + * @brief Establish a correspondence between a simulation time and the + * synchronizer real time. + * + * This method is expected to be called at the "instant" before simulation + * begins. At this point, simulation time = 0, and a + * set = 0 in this method. We then associate this time with the current + * value of the real time clock that will be used to actually perform the + * synchronization. + * + * Subclasses are expected to implement the corresponding DoSetOrigin pure + * virtual method to do the actual real-time-clock-specific work of making the + * correspondence mentioned above. + * + * @param ts The simulation time we should use as the origin (in simulator + * timestep units). + * @see TimeStepPrecision::Get + * @see TimeStepPrecision::DoSetOrigin + */ + void SetOrigin (uint64_t ts); + +/** + * @brief Retrieve the value of the origin of the simulation time in + * simulator timestep units. + * + * @returns The simulation time used as the origin (in simulator timestep + * units). + * @see TimeStepPrecision::Get + * @see Synchronizer::SetOrigin + */ + uint64_t GetOrigin (void); + +/** + * @brief Retrieve the difference between the real time clock used to + * synchronize the simulation and the simulation time (in simulator timestep + * units). + * + * @param ts Simulation timestep from the simulator interpreted as current time + * in the simulator. + * @returns Simulation timestep (in simulator timestep units) minus origin + * time (stored internally in nanosecond units). + * @see TimeStepPrecision::Get + * @see Synchronizer::SetOrigin + * @see Synchronizer::DoGetDrift + */ + int64_t GetDrift (uint64_t ts); + +/** + * @brief Wait until the real time is in sync with the specified simulation + * time or until the synchronizer is Sigalled. + * + * This is where the real work of synchronization is done. The Time passed + * in as a parameter is the simulation time. The job of Synchronize is to + * translate from simulation time to synchronizer time (in a perfect world + * this is the same time) and then figure out how long in real-time it needs + * to wait until that synchronizer / simulation time comes around. + * + * Subclasses are expected to implement the corresponding DoSynchronize pure + * virtual method to do the actual real-time-clock-specific work of waiting + * (either busy-waiting or sleeping, or some combination thereof) until the + * requested simulation time. + * + * @param tsCurrent The current simulation time (in simulator timestep units). + * @param tsDelay The simulation time we need to wait for (in simulator + * timestep units). + * @returns True if the function ran to completion, false if it was interrupted + * by a Signal. + * @see TimeStepPrecision::Get + * @see Synchronizer::DoSynchronize + * @see Synchronizer::Signal + */ + bool Synchronize (uint64_t tsCurrent, uint64_t tsDelay); + +/** + * @brief Tell a posible simulator thread waiting in the Synchronize method + * that an event has happened which demands a reevaluation of the wait time. + * This will cause the thread to wake and return to the simulator proper + * where it can get its bearings. + * + * @see Synchronizer::Synchronize + * @see Synchronizer::DoSignal + */ + void Signal (void); + +/** + * @brief Set the condition variable that tells a posible simulator thread + * waiting in the Synchronize method that an event has happened which demands + * a reevaluation of the wait time. + * + * @see Synchronizer::Signal + */ + void SetCondition (bool); + +/** + * @brief Ask the synchronizer to remember what time it is. Typically used + * with EventEnd to determine the real execution time of a simulation event. + * + * @see Synchronizer::EventEnd + * @see TimeStepPrecision::Get + */ + void EventStart (void); + +/** + * @brief Ask the synchronizer to return the time step between the instant + * remembered during EventStart and now. Used in conjunction with EventStart + * to determine the real execution time of a simulation event. + * + * @see Synchronizer::EventStart + * @see TimeStepPrecision::Get + */ + uint64_t EventEnd (void); + +protected: +/** + * @brief Establish a correspondence between a simulation time and a + * wall-clock (real) time. + * + * @internal + * + * There are three timelines involved here: the simulation time, the + * (absolute) wall-clock time and the (relative) synchronizer real time. + * Calling this method makes a correspondence between the origin of the + * synchronizer time and the current wall-clock time. + * + * This method is expected to be called at the "instant" before simulation + * begins. At this point, simulation time = 0, and synchronizer time is + * set = 0 in this method. We then associate this time with the current + * value of the real time clock that will be used to actually perform the + * synchronization. + * + * Subclasses are expected to implement this method to do the actual + * real-time-clock-specific work of making the correspondence mentioned above. + * for example, this is where the differences between Time parameters and + * parameters to clock_nanosleep would be dealt with. + * + * @param ns The simulation time we need to use as the origin (normalized to + * nanosecond units). + * @see Synchronizer::SetOrigin + * @see TimeStepPrecision::Get + */ + virtual void DoSetOrigin (uint64_t ns) = 0; + +/** + * @brief Return true if this synchronizer is actually synchronizing to a + * realtime clock. The simulator sometimes needs to know this. + * + * @internal + * + * Subclasses are expected to implement this method to tell the outside world + * whether or not they are synchronizing to a realtime clock. + * + * @returns True if locked with realtime, false if not. + */ + virtual bool DoRealtime (void) = 0; + +/** + * @brief Retrieve the value of the origin of the underlying normalized wall + * clock time in simulator timestep units. + * + * @internal + * + * Subclasses are expected to implement this method to do the actual + * real-time-clock-specific work of getting the current time. + * + * @returns The normalized wall clock time (in nanosecond units). + * @see TimeStepPrecision::Get + * @see Synchronizer::SetOrigin + */ + virtual uint64_t DoGetCurrentRealtime (void) = 0; + +/** + * @brief Wait until the real time is in sync with the specified simulation + * time. + * + * @internal + * + * This is where the real work of synchronization is done. The Time passed + * in as a parameter is the simulation time. The job of Synchronize is to + * translate from simulation time to synchronizer time (in a perfect world + * this is the same time) and then figure out how long in real-time it needs + * to wait until that synchronizer / simulation time comes around. + * + * Subclasses are expected to implement this method to do the actual + * real-time-clock-specific work of waiting (either busy-waiting or sleeping, + * or some combination) until the requested simulation time. + * + * @param nsCurrent The current simulation time (normalized to nanosecond + * units). + * @param nsDelay The simulation time we need to wait for (normalized to + * nanosecond units). + * @returns True if the function ran to completion, false if it was interrupted + * by a Signal. + * @see Synchronizer::Synchronize + * @see TimeStepPrecision::Get + * @see Synchronizer::Signal + */ + virtual bool DoSynchronize (uint64_t nsCurrent, uint64_t nsDelay) = 0; + +/** + * @brief Declaration of the method used to tell a posible simulator thread + * waiting in the DoSynchronize method that an event has happened which + * demands a reevaluation of the wait time. + * + * @see Synchronizer::Signal + */ + virtual void DoSignal (void) = 0; + +/** + * @brief Declaration of the method used to set the condition variable that + * tells a posible simulator thread waiting in the Synchronize method that an + * event has happened which demands a reevaluation of the wait time. + * + * @see Synchronizer::SetCondition + */ + virtual void DoSetCondition (bool) = 0; + +/** + * @brief Declaration of method used to retrieve drift between the real time + * clock used to synchronize the simulation and the current simulation time. + * + * @internal + * + * @param ns Simulation timestep from the simulator normalized to nanosecond + * steps. + * @returns Drift in nanosecond units. + * @see TimeStepPrecision::Get + * @see Synchronizer::SetOrigin + * @see Synchronizer::GetDrift + */ + virtual int64_t DoGetDrift (uint64_t ns) = 0; + + virtual void DoEventStart (void) = 0; + virtual uint64_t DoEventEnd (void) = 0; + + uint64_t m_realtimeOriginNano; + uint64_t m_simOriginNano; + +private: +/** + * @brief Convert a simulator time step (which can be steps of time in a + * user-specified unit) to a normalized time step in nanosecond units. + * + * @internal + * + * @param ts The simulation time step to be normalized. + * @returns The simulation time step normalized to nanosecond units. + * @see TimeStepPrecision::Get + */ + uint64_t TimeStepToNanosecond (uint64_t ts); + +/** + * @brief Convert a normalized nanosecond count into a simulator time step + * (which can be steps of time in a user-specified unit). + * + * @internal + * + * @param ns The nanosecond count step to be converted + * @returns The simulation time step to be interpreted in appropriate units. + * @see TimeStepPrecision::Get + */ + uint64_t NanosecondToTimeStep (uint64_t ns); +}; + +}; // namespace ns3 + +#endif /* SYNCHRONIZER_H */ diff --git a/src/simulator/time.cc b/src/simulator/time.cc index a25770277..ba36543e6 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -72,7 +72,10 @@ TimeUnit<1>::TimeUnit(const std::string& s) std::string::size_type n = s.find_first_not_of("0123456789."); if (n != std::string::npos) { // Found non-numeric - double r = atof(s.substr(0, n).c_str()); + std::istringstream iss; + iss.str (s.substr(0, n)); + double r; + iss >> r; std::string trailer = s.substr(n, std::string::npos); if (trailer == std::string("s")) { @@ -113,7 +116,11 @@ TimeUnit<1>::TimeUnit(const std::string& s) } //else //they didn't provide units, assume seconds - m_data = HighPrecision (atof(s.c_str()) * TimeStepPrecision::g_tsPrecFactor); + std::istringstream iss; + iss. str (s); + double v; + iss >> v; + m_data = HighPrecision (v * TimeStepPrecision::g_tsPrecFactor); } double diff --git a/src/simulator/wall-clock-synchronizer.cc b/src/simulator/wall-clock-synchronizer.cc new file mode 100644 index 000000000..301a68652 --- /dev/null +++ b/src/simulator/wall-clock-synchronizer.cc @@ -0,0 +1,423 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 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; + * + * 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 +#include + +#include "ns3/log.h" +#include "ns3/system-condition.h" + +#include "wall-clock-synchronizer.h" + +NS_LOG_COMPONENT_DEFINE ("WallClockSynchronizer"); + +namespace ns3 { + +WallClockSynchronizer::WallClockSynchronizer () +{ + NS_LOG_FUNCTION_NOARGS (); +// +// In Linux, the basic timekeeping unit is derived from a variable called HZ +// HZ is the frequency in hertz of the system timer. The system timer fires +// every 1/HZ seconds and a counter, called the jiffies counter is incremented +// at each tick. The time between ticks is called a jiffy (American slang for +// a short period of time). The ticking of the jiffies counter is how the +// the kernel tells time. +// +// Now, the shortest time the kernel can sleep is one jiffy since a timer +// has to be set to expire and trigger the process to be made ready. The +// Posix clock CLOCK_REALTIME is defined as a 1/HZ clock, so by doing a +// clock_getres () on the realtime clock we can infer the scheduler quantum +// and the minimimum sleep time for the system. This is most certainly NOT +// going to be one nanosecond even though clock_nanosleep () pretends it is. +// +// The reason this number is important is that we are going to schedule lots +// of waits for less time than a jiffy. The clock_nanosleep function is +// going to guarantee that it will sleep for AT LEAST the time specified. +// The least time that it will sleep is a jiffy. +// +// In order to deal with this, we are going to do a spin-wait if the simulator +// requires a delay less than a jiffy. This is on the order of one millisecond +// (999848 ns) on the ns-regression machine. +// +// If the underlying OS does not support posix clocks, we'll just assume a +// one millisecond quantum and deal with this as best we can + +#ifdef CLOCK_REALTIME + struct timespec ts; + clock_getres (CLOCK_REALTIME, &ts); + m_jiffy = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; + NS_LOG_INFO ("Jiffy is " << m_jiffy << " ns"); +#else + m_jiffy = 1000000; +#endif +} + +WallClockSynchronizer::~WallClockSynchronizer () +{ + NS_LOG_FUNCTION_NOARGS (); +} + + bool +WallClockSynchronizer::DoRealtime (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return true; +} + + uint64_t +WallClockSynchronizer::DoGetCurrentRealtime (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return GetNormalizedRealtime (); +} + + void +WallClockSynchronizer::DoSetOrigin (uint64_t ns) +{ + NS_LOG_FUNCTION_NOARGS (); +// +// In order to make sure we're really locking the simulation time to some +// wall-clock time, we need to be able to compare that simulation time to +// that wall-clock time. The wall clock will have been running for some +// long time and will probably have a huge count of nanoseconds in it. We +// save the real time away so we can subtract it from "now" later and get +// a count of nanoseconds in real time since the simulation started. +// + m_realtimeOriginNano = GetRealtime (); + NS_LOG_INFO ("origin = " << m_realtimeOriginNano); +} + + int64_t +WallClockSynchronizer::DoGetDrift (uint64_t ns) +{ + NS_LOG_FUNCTION_NOARGS (); +// +// In order to make sure we're really locking the simulation time to some +// wall-clock time, we need to be able to compare that simulation time to +// that wall-clock time. In DoSetOrigin we saved the real time at the start +// of the simulation away. This is the place where we subtract it from "now" +// to a count of nanoseconds in real time since the simulation started. We +// then subtract the current real time in normalized nanoseconds we just got +// from the normalized simulation time in nanoseconds that is passed in as +// the parameter ns. We return an integer difference, but in reality all of +// the mechanisms that cause wall-clock to simuator time drift cause events +// to be late. That means that the wall-clock will be higher than the +// simulation time and drift will be positive. I would be astonished to +// see a negative drift, but the possibility is admitted for other +// implementations; and we'll use the ability to report an early result in +// DoSynchronize below. +// + uint64_t nsNow = GetNormalizedRealtime (); + + if (nsNow > ns) + { +// +// Real time (nsNow) is larger/later than the simulator time (ns). We are +// behind real time and the difference (drift) is positive. +// + return (int64_t)(nsNow - ns); + } + else + { +// +// Real time (nsNow) is smaller/earlier than the simulator time (ns). We are +// ahead of real time and the difference (drift) is negative. +// + return -(int64_t)(ns - nsNow); + } +} + + bool +WallClockSynchronizer::DoSynchronize (uint64_t nsCurrent, uint64_t nsDelay) +{ + NS_LOG_FUNCTION_NOARGS (); +// +// This is the belly of the beast. We have received two parameters from the +// simulator proper -- a current simulation time (nsCurrent) and a simulation +// time to delay which identifies the time the next event is supposed to fire. +// +// The first thing we need to do is to (try and) correct for any realtime +// drift that has happened in the system. In this implementation, we realize +// that all mechanisms for drift will cause the drift to be such that the +// realtime is greater than the simulation time. This typically happens when +// our process is put to sleep for a given time, but actually sleeps for +// longer. So, what we want to do is to "catch up" to realtime and delay for +// less time than we are actually asked to delay. DriftCorrect will return a +// number from 0 to nsDelay corresponding to the amount of catching-up we +// need to do. If we are more than nsDelay behind, we do not wait at all. +// +// Note that it will be impossible to catch up if the amount of drift is +// cumulatively greater than the amount of delay between events. The method +// GetDrift () is available to clients of the syncrhonizer to keep track of +// the cumulative drift. The client can assert if the drift gets out of +// hand, print warning messages, or just ignore the situation and hope it will +// go away. +// + uint64_t ns = DriftCorrect (nsCurrent, nsDelay); + NS_LOG_INFO ("Synchronize ns = " << ns); +// +// Once we've decided on how long we need to delay, we need to split this +// time into sleep waits and busy waits. The reason for this is described +// in the comments for the constructor where jiffies and jiffy resolution is +// explained. +// +// Here, I'll just say that we need that the jiffy is the minimum resolution +// of the system clock. It can only sleep in blocks of time equal to a jiffy. +// If we want to be more accurate than a jiffy (we do) then we need to sleep +// for some number of jiffies and then busy wait for any leftover time. +// + uint64_t numberJiffies = ns / m_jiffy; + NS_LOG_INFO ("Synchronize numberJiffies = " << numberJiffies); +// +// This is where the real world interjects its very ugly head. The code +// immediately below reflects the fact that a sleep is actually quite probably +// going to end up sleeping for some number of jiffies longer than you wanted. +// This is because your system is going to be off doing other unimportant +// stuff during that extra time like running file systems and networks. What +// we want to do is to ask the system to sleep enough less than the requested +// delay so that it comes back early most of the time (coming back early is +// fine, coming back late is bad). If we can convince the system to come back +// early (most of the time), then we can busy-wait until the requested +// completion time actually comes around (most of the time). +// +// The tradeoff here is, of course, that the less time we spend sleeping, the +// more accurately we will sync up; but the more CPU time we will spend busy +// waiting (doing nothing). +// +// I'm not really sure about this number -- a boss of mine once said, "pick +// a number and it'll be wrong." But this works for now. +// +// XXX BUGBUG Hardcoded tunable parameter below. +// + if (numberJiffies > 3) + { + NS_LOG_INFO ("SleepWait for " << numberJiffies * m_jiffy << " ns"); + NS_LOG_INFO ("SleepWait until " << nsCurrent + numberJiffies * m_jiffy + << " ns"); +// +// SleepWait is interruptible. If it returns true it meant that the sleep +// went until the end. If it returns false, it means that the sleep was +// interrupted by a Signal. In this case, we need to return and let the +// simulator re-evaluate what to do. +// + if (SleepWait ((numberJiffies - 3) * m_jiffy) == false) + { + NS_LOG_INFO ("SleepWait interrupted"); + return false; + } + } + NS_LOG_INFO ("Done with SleepWait"); +// +// We asked the system to sleep for some number of jiffies, but that doesn't +// mean we actually did. Let's re-evaluate what we need to do here. Maybe +// we're already late. Probably the "real" delay time left has little to do +// with what we would calculate it to be naively. +// +// We are now at some Realtime. The important question now is not, "what +// would we calculate in a mathematicians paradise," it is, "how many +// nanoseconds do we need to busy-wait until we get to the Realtime that +// corresponds to nsCurrent + nsDelay (in simulation time). We have a handy +// function to do just that -- we ask for the time the realtime clock has +// drifted away from the simulation clock. That's our answer. If the drift +// is negative, we're early and we need to busy wait for that number of +// nanoseconds. The place were we want to be is described by the parameters +// we were passed by the simulator. +// + int64_t nsDrift = DoGetDrift (nsCurrent + nsDelay); +// +// If the drift is positive, we are already late and we need to just bail out +// of here as fast as we can. Return true to indicate that the requested time +// has, in fact, passed. +// + if (nsDrift >= 0) + { + NS_LOG_INFO ("Back from SleepWait: IML8 " << nsDrift); + return true; + } +// +// There are some number of nanoseconds left over and we need to wait until +// the time defined by nsDrift. We'll do a SpinWait since the usual case +// will be that we are doing this Spinwait after we've gotten a rough delay +// using the SleepWait above. If SpinWait completes to the end, it will +// return true; if it is interrupted by a signal it will return false. +// + NS_LOG_INFO ("SpinWait until " << nsCurrent + nsDelay); + return SpinWait (nsCurrent + nsDelay); +} + + void +WallClockSynchronizer::DoSignal (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + m_condition.SetCondition (true); + m_condition.Signal (); +} + + void +WallClockSynchronizer::DoSetCondition (bool cond) +{ + NS_LOG_FUNCTION_NOARGS (); + m_condition.SetCondition (cond); +} + + void +WallClockSynchronizer::DoEventStart (void) +{ + NS_LOG_FUNCTION_NOARGS (); + m_nsEventStart = GetNormalizedRealtime (); +} + + uint64_t +WallClockSynchronizer::DoEventEnd (void) +{ + NS_LOG_FUNCTION_NOARGS (); + return GetNormalizedRealtime () - m_nsEventStart; +} + + bool +WallClockSynchronizer::SpinWait (uint64_t ns) +{ + NS_LOG_FUNCTION_NOARGS (); +// +// Do a busy-wait until the normalized realtime equals the value passed in +// or the condition variable becomes true. The condition becomes true if +// an outside entity (a network device receives a packet, sets the condition +// and signals the scheduler it needs to re-evaluate). +// +// We just sit here and spin, wasting CPU cycles until we get to the right +// time or are told to leave. +// + for (;;) + { + if (GetNormalizedRealtime () >= ns) + { + return true; + } + if (m_condition.GetCondition ()) + { + return false; + } + } +// Quiet compiler + return true; +} + + bool +WallClockSynchronizer::SleepWait (uint64_t ns) +{ + NS_LOG_FUNCTION_NOARGS (); +// +// Put our process to sleep for some number of nanoseconds. Typically this +// will be some time equal to an integral number of jiffies. We will usually +// follow a call to SleepWait with a call to SpinWait to get the kind of +// accuracy we want. +// +// We have to have some mechanism to wake up this sleep in case an external +// event happens that causes a schedule event in the simulator. This newly +// scheduled event might be before the time we are waiting until, so we have +// to break out of both the SleepWait and the following SpinWait to go back +// and reschedule/resynchronize taking the new event into account. The +// SystemCondition we have saved in m_condition takes care of this for us. +// +// This call will return if the timeout expires OR if the condition is +// set true by a call to WallClockSynchronizer::SetCondition (true) followed +// by a call to WallClockSynchronizer::Signal(). In either case, we are done +// waiting. If the timeout happened, we TimedWait returns true; if a Signal +// happened, false. +// + return m_condition.TimedWait (ns); +} + + uint64_t +WallClockSynchronizer::DriftCorrect (uint64_t nsNow, uint64_t nsDelay) +{ + int64_t drift = DoGetDrift (nsNow); +// +// If we're running late, drift will be positive and we need to correct by +// delaying for less time. If we're early for some bizarre reason, we don't +// do anything since we'll almost instantly self-correct. +// + if (drift < 0) + { + return nsDelay; + } +// +// If we've drifted out of sync by less than the requested delay, then just +// subtract the drift from the delay and fix up the drift in one go. If we +// have more drift than delay, then we just play catch up as fast as possible +// by not delaying at all. +// + uint64_t correction = (uint64_t)drift; + if (correction <= nsDelay) + { + return nsDelay - correction; + } + else + { + return 0; + } +} + + uint64_t +WallClockSynchronizer::GetRealtime (void) +{ + struct timeval tvNow; + gettimeofday (&tvNow, NULL); + return TimevalToNs (&tvNow); +} + + uint64_t +WallClockSynchronizer::GetNormalizedRealtime (void) +{ + return GetRealtime () - m_realtimeOriginNano; +} + + void +WallClockSynchronizer::NsToTimeval (int64_t ns, struct timeval *tv) +{ + NS_ASSERT ((ns % US_PER_NS) == 0); + tv->tv_sec = ns / NS_PER_SEC; + tv->tv_usec = (ns % NS_PER_SEC) / US_PER_NS; +} + + uint64_t +WallClockSynchronizer::TimevalToNs (struct timeval *tv) +{ + uint64_t nsResult = tv->tv_sec * NS_PER_SEC + tv->tv_usec * US_PER_NS; + NS_ASSERT ((nsResult % US_PER_NS) == 0); + return nsResult; +} + + void +WallClockSynchronizer::TimevalAdd ( + struct timeval *tv1, + struct timeval *tv2, + struct timeval *result) +{ + result->tv_sec = tv1->tv_sec + tv2->tv_sec; + result->tv_usec = tv1->tv_usec + tv2->tv_usec; + if (result->tv_usec > (int64_t)US_PER_SEC) + { + ++result->tv_sec; + result->tv_usec %= US_PER_SEC; + } +} + +}; // namespace ns3 diff --git a/src/simulator/wall-clock-synchronizer.h b/src/simulator/wall-clock-synchronizer.h new file mode 100644 index 000000000..63a16a2d0 --- /dev/null +++ b/src/simulator/wall-clock-synchronizer.h @@ -0,0 +1,196 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 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; + * + * 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 WALL_CLOCK_CLOCK_SYNCHRONIZER_H +#define WALL_CLOCK_CLOCK_SYNCHRONIZER_H + +#include "ns3/system-condition.h" +#include "synchronizer.h" + +namespace ns3 { + +/** + * @brief Class used for synchronizing the simulation events to a real-time + * "wall clock" using Posix Clock functions. + * + * Enable this synchronizer using: + * + * DefaultValue::Bind ("Synchronizer", "WallClockSynchronizer"); + * + * before calling any simulator functions. + * + * The simulation clock is maintained as a 64-bit integer in a unit specified + * by the user through the TimeStepPrecision::Set function. This means that + * it is not possible to specify event expiration times with anything better + * than this user-specified accuracy. + * + * There are a couple of more issues at this level. Posix clocks provide + * access to several clocks we could use as a wall clock. We don't care about + * time in the sense of 0430 CEST, we care about some piece of hardware that + * ticks at some regular period. The most accurate posix clock in this + * respect is the CLOCK_PROCESS_CPUTIME_ID clock. This is a high-resolution + * register in the CPU. For example, on Intel machines this corresponds to + * the timestamp counter (TSC) register. The resolution of this counter will + * be on the order of nanoseconds. + * + * Now, just because we can measure time in nanoseconds doesn't mean we can + * put our process to sleep to nanosecond resolution. We are eventualy going + * to use the function clock_nanosleep () to sleep until a simulation Time + * specified by the caller. + * + * MORE ON JIFFIES, SLEEP, PROCESSES, etc., as required + * + * Nanosleep takes a struct timespec as an input so we have to deal with + * conversion between Time and struct timespec here. They are both + * interpreted as elapsed times. + */ +class WallClockSynchronizer : public Synchronizer +{ +public: + WallClockSynchronizer (); + virtual ~WallClockSynchronizer (); + + static const uint64_t US_PER_NS = (uint64_t)1000; + static const uint64_t US_PER_SEC = (uint64_t)1000000; + static const uint64_t NS_PER_SEC = (uint64_t)1000000000; + +protected: +/** + * @brief Return true if this synchronizer is actually synchronizing to a + * realtime clock. The simulator sometimes needs to know this. + * + * @internal + * + * Subclasses are expected to implement this method to tell the outside world + * whether or not they are synchronizing to a realtime clock. + * + * @returns True if locked with realtime, false if not. + */ + virtual bool DoRealtime (void); + +/** + * @brief Retrieve the value of the origin of the underlying normalized wall + * clock time in nanosecond units. + * + * @internal + * + * Subclasses are expected to implement this method to do the actual + * real-time-clock-specific work of getting the current time. + * + * @returns The normalized wall clock time (in nanosecond units). + * @see TimeStepPrecision::Get + * @see Synchronizer::SetOrigin + */ + virtual uint64_t DoGetCurrentRealtime (void); + +/** + * @brief Establish a correspondence between a simulation time and a + * wall-clock (real) time. + * + * @internal + * + * There are three timelines involved here: the simulation time, the + * (absolute) wall-clock time and the (relative) synchronizer real time. + * Calling this method makes a correspondence between the origin of the + * synchronizer time and the current wall-clock time. + * + * This method is expected to be called at the "instant" before simulation + * begins. At this point, simulation time = 0, and synchronizer time is + * set = 0 in this method. We then associate this time with the current + * value of the real time clock that will be used to actually perform the + * synchronization. + * + * Subclasses are expected to implement this method to do the actual + * real-time-clock-specific work of making the correspondence mentioned above. + * for example, this is where the differences between Time parameters and + * parameters to clock_nanosleep would be dealt with. + * + * @param ns The simulation time we need to use as the origin (normalized to + * nanosecond units). + */ + virtual void DoSetOrigin (uint64_t ns); + +/** + * @brief Declaration of method used to retrieve drift between the real time + * clock used to synchronize the simulation and the current simulation time. + * + * @internal + * + * @param ns Simulation timestep from the simulator normalized to nanosecond + * steps. + * @returns Drift in nanosecond units. + * @see TimeStepPrecision::Get + * @see Synchronizer::SetOrigin + * @see Synchronizer::GetDrift + */ + virtual int64_t DoGetDrift (uint64_t ns); + +/** + * @brief Wait until the real time is in sync with the specified simulation + * time. + * + * @internal + * + * This is where the real work of synchronization is done. The Time passed + * in as a parameter is the simulation time. The job of Synchronize is to + * translate from simulation time to synchronizer time (in a perfect world + * this is the same time) and then figure out how long in real-time it needs + * to wait until that synchronizer / simulation time comes around. + * + * Subclasses are expected to implement this method to do the actual + * real-time-clock-specific work of waiting (either busy-waiting or sleeping, + * or some combination) until the requested simulation time. + * + * @param ns The simulation time we need to wait for (normalized to nanosecond + * units). + * @see TimeStepPrecision::Get + */ + virtual bool DoSynchronize (uint64_t nsCurrent, uint64_t nsDelay); + virtual void DoSignal (void); + virtual void DoSetCondition (bool cond); + + virtual void DoEventStart (void); + virtual uint64_t DoEventEnd (void); + + bool SpinWait (uint64_t); + bool SleepWait (uint64_t); + + uint64_t DriftCorrect (uint64_t nsNow, uint64_t nsDelay); + + uint64_t GetRealtime (void); + uint64_t GetNormalizedRealtime (void); + + void NsToTimeval (int64_t ns, struct timeval *tv); + uint64_t TimevalToNs (struct timeval *tv); + + void TimevalAdd ( + struct timeval *tv1, + struct timeval *tv2, + struct timeval *result); + + uint64_t m_cpuTick; + uint64_t m_realtimeTick; + uint64_t m_jiffy; + uint64_t m_nsEventStart; + + SystemCondition m_condition; +}; + +}; // namespace ns3 + +#endif /* WALL_CLOCK_SYNCHRONIZER_H */ diff --git a/src/simulator/wscript b/src/simulator/wscript index d41c5a356..506119579 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -16,13 +16,13 @@ def set_options(opt): def configure(conf): if Params.g_options.high_precision_as_double: - conf.add_define('USE_HIGH_PRECISION_DOUBLE', 1) + conf.define('USE_HIGH_PRECISION_DOUBLE', 1) conf.env['USE_HIGH_PRECISION_DOUBLE'] = 1 highprec = 'long double' else: conf.env['USE_HIGH_PRECISION_DOUBLE'] = 0 highprec = '128-bit integer' - conf.check_message_custom('high precision time', 'implementation', highprec) + conf.check_message_custom('high precision time','implementation',highprec) e = conf.create_header_configurator() e.mandatory = False @@ -44,6 +44,9 @@ def configure(conf): conf.write_config_header('ns3/simulator-config.h') + conf.report_optional_feature("RealTime", "Real Time Simulator", + conf.env['ENABLE_THREADING'], + "threading not enabled") def build(bld): @@ -58,8 +61,11 @@ def build(bld): 'heap-scheduler.cc', 'event-impl.cc', 'simulator.cc', + 'default-simulator-impl.cc', 'timer.cc', 'watchdog.cc', + 'synchronizer.cc', + 'make-event.cc', ] headers = bld.create_obj('ns3header') @@ -70,6 +76,8 @@ def build(bld): 'event-id.h', 'event-impl.h', 'simulator.h', + 'simulator-impl.h', + 'default-simulator-impl.h', 'scheduler.h', 'list-scheduler.h', 'map-scheduler.h', @@ -78,6 +86,8 @@ def build(bld): 'timer.h', 'timer-impl.h', 'watchdog.h', + 'synchronizer.h', + 'make-event.h', ] env = bld.env_of_name('default') @@ -98,3 +108,13 @@ def build(bld): 'cairo-wideint-private.h', ]) + if env['ENABLE_THREADING']: + headers.source.extend([ + 'realtime-simulator-impl.h', + 'wall-clock-synchronizer.h', + ]) + sim.source.extend([ + 'realtime-simulator-impl.cc', + 'wall-clock-synchronizer.cc', + ]) + diff --git a/src/wscript b/src/wscript index 43dddb49b..bc8c87689 100644 --- a/src/wscript +++ b/src/wscript @@ -27,6 +27,8 @@ all_modules = ( 'mobility', 'devices/wifi', 'helper', + 'devices/bridge', + 'contrib/stats', ) def set_options(opt): @@ -48,9 +50,10 @@ def configure(conf): conf.sub_config('core') conf.sub_config('simulator') conf.sub_config('contrib') + conf.sub_config('internet-stack') blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) - conf.env['NS3_MODULE_PATH'] = [blddir] + conf.env.append_value('NS3_MODULE_PATH', blddir) if Params.g_options.enable_rpath: conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),)) diff --git a/tutorial/testipv4.cc b/tutorial/testipv4.cc deleted file mode 100644 index ef98b3a77..000000000 --- a/tutorial/testipv4.cc +++ /dev/null @@ -1,59 +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 - */ - -#include "ns3/log.h" -#include "ns3/ipv4-address-generator.h" - -NS_LOG_COMPONENT_DEFINE ("TestIpv4"); - -using namespace ns3; - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("TestIpv4", LOG_LEVEL_ALL); - - NS_LOG_INFO ("Test Ipv4"); - - Ipv4Mask mask1 ("255.0.0.0"); - - for (uint32_t i = 0; i < 10; ++i) - { - Ipv4Address network = Ipv4AddressGenerator::NextNetwork (mask1); - Ipv4Address address = Ipv4AddressGenerator::NextAddress (mask1); - NS_LOG_INFO ("address = " << address); - } - - Ipv4Mask mask2 ("255.255.0.0"); - Ipv4AddressGenerator::Init (Ipv4Address ("192.168.0.0"), mask2); - Ipv4AddressGenerator::InitAddress (Ipv4Address ("0.0.0.3"), mask2); - - Ipv4Address network1 = Ipv4AddressGenerator::NextNetwork (mask2); - for (uint32_t i = 0; i < 10; ++i) - { - Ipv4Address address = Ipv4AddressGenerator::NextAddress (mask2); - NS_LOG_INFO ("address = " << address); - } - - Ipv4Mask mask3 ("255.255.255.0"); - - for (uint32_t i = 0; i < 10; ++i) - { - Ipv4Address network = Ipv4AddressGenerator::NextNetwork (mask3); - Ipv4Address address = Ipv4AddressGenerator::NextAddress (mask3); - NS_LOG_INFO ("address = " << address); - } -} diff --git a/tutorial/tutorial-bus-network.cc b/tutorial/tutorial-bus-network.cc deleted file mode 100644 index a4016a4dc..000000000 --- a/tutorial/tutorial-bus-network.cc +++ /dev/null @@ -1,75 +0,0 @@ - -/* - * 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 - -#include "ns3/core-module.h" -#include "ns3/node-module.h" -#include "ns3/helper-module.h" -#include "ns3/simulator-module.h" -#include "ns3/global-route-manager.h" - -NS_LOG_COMPONENT_DEFINE ("BusNetworkSimulation"); - -using namespace ns3; - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("BusNetworkSimulation", LOG_LEVEL_ALL); - - NS_LOG_INFO ("Bus Network Simulation"); - - NodeContainer n; - n.Create (10); - - InternetStackHelper internet; - internet.Install (n); - - CsmaHelper csma; - csma.SetChannelParameter ("DataRate", StringValue ("10Mbps")); - csma.SetChannelParameter ("Delay", StringValue ("10ms")); - NetDeviceContainer nd = csma.Install (n); - - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.0.0", "255.255.0.0", "0.0.0.3"); - Ipv4InterfaceContainer i = ipv4.Assign (nd); - - uint32_t port = 7; - UdpEchoClientHelper client; - client.SetRemote (i.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (1)); - client.SetAppAttribute ("Interval", StringValue ("1s")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - ApplicationContainer apps = client.Install (n.Get (0)); - apps.Start (Seconds (2.0)); - apps.Stop (Seconds (10.0)); - - UdpEchoServerHelper server; - server.SetPort (port); - apps = server.Install (n.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - GlobalRouteManager::PopulateRoutingTables (); - - std::ofstream ascii; - ascii.open ("tutorial.tr"); - CsmaHelper::EnableAsciiAll (ascii); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/tutorial-csma-echo-ascii-trace.cc b/tutorial/tutorial-csma-echo-ascii-trace.cc deleted file mode 100644 index 8fef98c97..000000000 --- a/tutorial/tutorial-csma-echo-ascii-trace.cc +++ /dev/null @@ -1,72 +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 - */ - -#include - -#include "ns3/core-module.h" -#include "ns3/simulator-module.h" -#include "ns3/helper-module.h" - -NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); - -using namespace ns3; - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("UDP Echo Simulation"); - - NodeContainer n; - n.Create (4); - - InternetStackHelper internet; - internet.Install (n); - - CsmaHelper csma; - csma.SetChannelParameter ("DataRate", StringValue ("5Mpbs")); - csma.SetChannelParameter ("Delay", StringValue ("2ms")); - NetDeviceContainer nd = csma.Install (n); - - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer i = ipv4.Assign (nd); - - uint16_t port = 7; - - UdpEchoClientHelper client; - client.SetRemote (i.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (1)); - client.SetAppAttribute ("Interval", StringValue ("1s")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - ApplicationContainer apps = client.Install (n.Get (0)); - apps.Start (Seconds (2.0)); - apps.Stop (Seconds (10.0)); - - UdpEchoServerHelper server; - server.SetPort (port); - apps = server.Install (n.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - std::ofstream os; - os.open ("tutorial.tr"); - CsmaHelper::EnableAsciiAll (os); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/tutorial-csma-echo-pcap-trace.cc b/tutorial/tutorial-csma-echo-pcap-trace.cc deleted file mode 100644 index 090fb1b65..000000000 --- a/tutorial/tutorial-csma-echo-pcap-trace.cc +++ /dev/null @@ -1,68 +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 - */ - -#include "ns3/core-module.h" -#include "ns3/simulator-module.h" -#include "ns3/helper-module.h" - -NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); - -using namespace ns3; - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("UDP Echo Simulation"); - - NodeContainer n; - n.Create (4); - - InternetStackHelper internet; - internet.Install (n); - - CsmaHelper csma; - csma.SetChannelParameter ("DataRate", StringValue ("5Mbps")); - csma.SetChannelParameter ("Delay", StringValue ("2ms")); - NetDeviceContainer nd = csma.Install (n); - - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer i = ipv4.Assign (nd); - - uint16_t port = 7; - - UdpEchoClientHelper client; - client.SetRemote (i.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (1)); - client.SetAppAttribute ("Interval", StringValue ("2s")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - ApplicationContainer apps = client.Install (n.Get (0)); - apps.Start (Seconds (2.0)); - apps.Stop (Seconds (10.0)); - - UdpEchoServerHelper server; - server.SetPort (port); - apps = server.Install (n.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - CsmaHelper::EnablePcapAll ("tutorial"); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/tutorial-csma-echo.cc b/tutorial/tutorial-csma-echo.cc deleted file mode 100644 index e4472d4a9..000000000 --- a/tutorial/tutorial-csma-echo.cc +++ /dev/null @@ -1,66 +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 - */ - -#include "ns3/core-module.h" -#include "ns3/simulator-module.h" -#include "ns3/helper-module.h" - -NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); - -using namespace ns3; - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("UDP Echo Simulation"); - - NodeContainer n; - n.Create (4); - - InternetStackHelper internet; - internet.Install (n); - - CsmaHelper csma; - csma.SetChannelParameter ("DataRate", StringValue ("5Mbps")); - csma.SetChannelParameter ("Delay", StringValue ("2ms")); - NetDeviceContainer nd = csma.Install (n); - - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer i = ipv4.Assign (nd); - - uint16_t port = 7; - - UdpEchoClientHelper client; - client.SetRemote (i.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (1)); - client.SetAppAttribute ("Interval", StringValue ("1s")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - ApplicationContainer apps = client.Install (n.Get (0)); - apps.Start (Seconds (2.0)); - apps.Stop (Seconds (10.0)); - - UdpEchoServerHelper server; - server.SetPort (port); - apps = server.Install (n.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/tutorial-linear-dumbbell.cc b/tutorial/tutorial-linear-dumbbell.cc deleted file mode 100644 index 6b85a7b08..000000000 --- a/tutorial/tutorial-linear-dumbbell.cc +++ /dev/null @@ -1,148 +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 - */ - -#include - -#include "ns3/core-module.h" -#include "ns3/node-module.h" -#include "ns3/helper-module.h" -#include "ns3/simulator-module.h" -#include "ns3/global-route-manager.h" - - -NS_LOG_COMPONENT_DEFINE ("DumbbellSimulation"); - -using namespace ns3; - -// Network topology -// -// point to point -// +--------------+ -// | | -// n0 n1 n2 n3 n4 n5 n6 n7 -// | | | | | | | | -// ================ ================ -// lan1 lan2 -// -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("DumbbellSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Dumbbell Topology Simulation"); -// -// Create the lan on the left side of the dumbbell. -// - NodeContainer lan1; - lan1.Create (4); - - InternetStackHelper internet; - internet.Install (lan1); - - CsmaHelper csma; - csma.SetChannelParameter ("DataRate", StringValue ("10Mbps")); - csma.SetChannelParameter ("Delay", StringValue ("2ms")); - NetDeviceContainer dev1 = csma.Install (lan1); - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer i1 = ipv4.Assign (dev1); - - -// -// Create the lan on the right side of the dumbbell. -// - NodeContainer lan2; - lan2.Create (4); - internet.Install (lan2); - - NetDeviceContainer dev2 = csma.Install (lan2); - ipv4.SetBase ("10.1.2.0", "255.255.255.0"); - Ipv4InterfaceContainer i2 = ipv4.Assign (dev2); - - -// -// Create the point-to-point link to connect the two lans. -// - NodeContainer backbone = NodeContainer (lan1.Get (3), lan2.Get (0)); - PointToPointHelper p2p; - p2p.SetChannelParameter ("DataRate", StringValue ("38400bps")); - p2p.SetChannelParameter ("Delay", StringValue ("20ms")); - NetDeviceContainer dev3 = p2p.Install (backbone); - ipv4.SetBase ("10.1.3.0", "255.255.255.0"); - ipv4.Assign (dev3); - -// -// Create data flows across the link: -// n0 ==> n4 ==> n0 -// n1 ==> n5 ==> n1 -// n2 ==> n6 ==> n2 -// n3 ==> n7 ==> n3 -// - uint16_t port = 7; - - UdpEchoClientHelper client; - client.SetRemote (i2.GetAddress (0), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (100)); - client.SetAppAttribute ("Interval", StringValue ("10ms")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - ApplicationContainer apps = client.Install (lan1.Get (0)); - apps.Start (Seconds(2.)); - apps.Stop (Seconds (10.0)); - - client.SetRemote (i2.GetAddress (1), port); - apps = client.Install (lan1.Get (1)); - apps.Start (Seconds(2.1)); - apps.Stop (Seconds (10.0)); - - client.SetRemote (i2.GetAddress (2), port); - apps = client.Install (lan1.Get (2)); - apps.Start (Seconds(2.2)); - apps.Stop (Seconds (10.0)); - - client.SetRemote (i2.GetAddress (3), port); - apps = client.Install (lan1.Get (3)); - apps.Start (Seconds(2.3)); - apps.Stop (Seconds (10.0)); - - - UdpEchoServerHelper server; - server.SetPort (port); - apps = server.Install (lan2.Get (0)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - apps = server.Install (lan2.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - apps = server.Install (lan2.Get (2)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - apps = server.Install (lan2.Get (3)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - GlobalRouteManager::PopulateRoutingTables (); - - std::ofstream os; - os.open ("tutorial.tr"); - PointToPointHelper::EnableAsciiAll (os); - CsmaHelper::EnableAsciiAll (os); - - PointToPointHelper::EnablePcapAll ("tutorial"); - CsmaHelper::EnablePcapAll ("tutorial"); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/tutorial-point-to-point.cc b/tutorial/tutorial-point-to-point.cc deleted file mode 100644 index 030920007..000000000 --- a/tutorial/tutorial-point-to-point.cc +++ /dev/null @@ -1,78 +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 - */ - -#include - -#include "ns3/core-module.h" -#include "ns3/simulator-module.h" -#include "ns3/helper-module.h" - -NS_LOG_COMPONENT_DEFINE ("PointToPointSimulation"); - -using namespace ns3; - -// Network topology -// -// point to point -// +--------------+ -// | | -// n0 n1 -// -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("PointToPointSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Point to Point Topology Simulation"); - - NodeContainer n; - n.Create (2); - - InternetStackHelper internet; - internet.Install (n); - - PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", StringValue ("38400bps")); - p2p.SetChannelParameter ("Delay", StringValue ("20ms")); - NetDeviceContainer nd = p2p.Install (n); - - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.252"); - Ipv4InterfaceContainer i = ipv4.Assign (nd); - - uint16_t port = 7; - UdpEchoClientHelper client; - client.SetRemote (i.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (1)); - client.SetAppAttribute ("Interval", StringValue ("1s")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - ApplicationContainer apps = client.Install (n.Get (0)); - apps.Start (Seconds (2.0)); - apps.Stop (Seconds (10.0)); - - UdpEchoServerHelper server; - server.SetPort (port); - apps = server.Install (n.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - std::ofstream ascii; - ascii.open ("tutorial.tr"); - PointToPointHelper::EnableAsciiAll (ascii); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/tutorial-star-routing.cc b/tutorial/tutorial-star-routing.cc deleted file mode 100644 index 1abacf9a4..000000000 --- a/tutorial/tutorial-star-routing.cc +++ /dev/null @@ -1,108 +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 - */ - -#include - -#include "ns3/core-module.h" -#include "ns3/node-module.h" -#include "ns3/helper-module.h" -#include "ns3/simulator-module.h" -#include "ns3/global-route-manager.h" - -NS_LOG_COMPONENT_DEFINE ("StarRoutingSimulation"); - -using namespace ns3; - -// Network topology -// -// n3 n2 -// | / -// | / -// n4 --- n0 --- n1 -// / | -// / | -// n5 n6 - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("StarRoutingSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Star Topology with Routing Simulation"); - - NodeContainer n; - n.Create (7); - NodeContainer n01 = NodeContainer (n.Get (0), n.Get (1)); - NodeContainer n02 = NodeContainer (n.Get (0), n.Get (2)); - NodeContainer n03 = NodeContainer (n.Get (0), n.Get (3)); - NodeContainer n04 = NodeContainer (n.Get (0), n.Get (4)); - NodeContainer n05 = NodeContainer (n.Get (0), n.Get (5)); - NodeContainer n06 = NodeContainer (n.Get (0), n.Get (6)); - - InternetStackHelper internet; - internet.Install (n); - - PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", StringValue ("38400bps")); - p2p.SetChannelParameter ("Delay", StringValue ("20ms")); - - NetDeviceContainer d01 = p2p.Install (n01); - NetDeviceContainer d02 = p2p.Install (n02); - NetDeviceContainer d03 = p2p.Install (n03); - NetDeviceContainer d04 = p2p.Install (n04); - NetDeviceContainer d05 = p2p.Install (n05); - NetDeviceContainer d06 = p2p.Install (n06); - - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.252"); - Ipv4InterfaceContainer i01 = ipv4.Assign (d01); - ipv4.SetBase ("10.1.2.0", "255.255.255.252"); - Ipv4InterfaceContainer i02 = ipv4.Assign (d02); - ipv4.SetBase ("10.1.3.0", "255.255.255.252"); - Ipv4InterfaceContainer i03 = ipv4.Assign (d03); - ipv4.SetBase ("10.1.4.0", "255.255.255.252"); - Ipv4InterfaceContainer i04 = ipv4.Assign (d04); - ipv4.SetBase ("10.1.5.0", "255.255.255.252"); - Ipv4InterfaceContainer i05 = ipv4.Assign (d05); - ipv4.SetBase ("10.1.6.0", "255.255.255.252"); - Ipv4InterfaceContainer i06 = ipv4.Assign (d06); - - uint16_t port = 7; - - UdpEchoServerHelper server; - server.SetPort (port); - ApplicationContainer apps = server.Install (n.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - UdpEchoClientHelper client; - client.SetRemote (i01.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (1)); - client.SetAppAttribute ("Interval", StringValue ("1s")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - apps = client.Install (n.Get (0)); - apps.Start (Seconds (2.0)); - apps.Stop (Seconds (10.0)); - - GlobalRouteManager::PopulateRoutingTables (); - - std::ofstream ascii; - ascii.open ("tutorial.tr"); - PointToPointHelper::EnableAsciiAll (ascii); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/tutorial-star.cc b/tutorial/tutorial-star.cc deleted file mode 100644 index f13018b9c..000000000 --- a/tutorial/tutorial-star.cc +++ /dev/null @@ -1,105 +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 - */ - -#include - -#include "ns3/core-module.h" -#include "ns3/node-module.h" -#include "ns3/helper-module.h" -#include "ns3/simulator-module.h" - -NS_LOG_COMPONENT_DEFINE ("StarRoutingSimulation"); - -using namespace ns3; - -// Network topology -// -// n3 n2 -// | / -// | / -// n4 --- n0 --- n1 -// / | -// / | -// n5 n6 - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("StarRoutingSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Star Topology with Routing Simulation"); - - NodeContainer n; - n.Create (7); - NodeContainer n01 = NodeContainer (n.Get (0), n.Get (1)); - NodeContainer n02 = NodeContainer (n.Get (0), n.Get (2)); - NodeContainer n03 = NodeContainer (n.Get (0), n.Get (3)); - NodeContainer n04 = NodeContainer (n.Get (0), n.Get (4)); - NodeContainer n05 = NodeContainer (n.Get (0), n.Get (5)); - NodeContainer n06 = NodeContainer (n.Get (0), n.Get (6)); - - InternetStackHelper internet; - internet.Install (n); - - PointToPointHelper p2p; - p2p.SetDeviceParameter ("DataRate", StringValue ("38400bps")); - p2p.SetChannelParameter ("Delay", StringValue ("20ms")); - - NetDeviceContainer d01 = p2p.Install (n01); - NetDeviceContainer d02 = p2p.Install (n02); - NetDeviceContainer d03 = p2p.Install (n03); - NetDeviceContainer d04 = p2p.Install (n04); - NetDeviceContainer d05 = p2p.Install (n05); - NetDeviceContainer d06 = p2p.Install (n06); - - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.252"); - Ipv4InterfaceContainer i01 = ipv4.Assign (d01); - ipv4.SetBase ("10.1.2.0", "255.255.255.252"); - Ipv4InterfaceContainer i02 = ipv4.Assign (d02); - ipv4.SetBase ("10.1.3.0", "255.255.255.252"); - Ipv4InterfaceContainer i03 = ipv4.Assign (d03); - ipv4.SetBase ("10.1.4.0", "255.255.255.252"); - Ipv4InterfaceContainer i04 = ipv4.Assign (d04); - ipv4.SetBase ("10.1.5.0", "255.255.255.252"); - Ipv4InterfaceContainer i05 = ipv4.Assign (d05); - ipv4.SetBase ("10.1.6.0", "255.255.255.252"); - Ipv4InterfaceContainer i06 = ipv4.Assign (d06); - - uint16_t port = 7; - - UdpEchoServerHelper server; - server.SetPort (port); - ApplicationContainer apps = server.Install (n.Get (1)); - apps.Start (Seconds (1.0)); - apps.Stop (Seconds (10.0)); - - UdpEchoClientHelper client; - client.SetRemote (i01.GetAddress (1), port); - client.SetAppAttribute ("MaxPackets", UintegerValue (1)); - client.SetAppAttribute ("Interval", StringValue ("1s")); - client.SetAppAttribute ("PacketSize", UintegerValue (1024)); - apps = client.Install (n.Get (0)); - apps.Start (Seconds (2.0)); - apps.Stop (Seconds (10.0)); - - std::ofstream ascii; - ascii.open ("tutorial.tr"); - PointToPointHelper::EnableAsciiAll (ascii); - - Simulator::Run (); - Simulator::Destroy (); -} diff --git a/tutorial/waf b/tutorial/waf deleted file mode 100755 index 191b7dbb2..000000000 --- a/tutorial/waf +++ /dev/null @@ -1 +0,0 @@ -exec "`dirname "$0"`"/../waf "$@" diff --git a/tutorial/wscript b/tutorial/wscript deleted file mode 100644 index a302c39bb..000000000 --- a/tutorial/wscript +++ /dev/null @@ -1,32 +0,0 @@ -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - -def build(bld): - obj = bld.create_ns3_program('hello-simulator', ['simulator']) - obj.source = 'hello-simulator.cc' - - obj = bld.create_ns3_program('tutorial-csma-echo', ['internet-stack', 'csma']) - obj.source = 'tutorial-csma-echo.cc' - - obj = bld.create_ns3_program('tutorial-csma-echo-ascii-trace', ['internet-stack', 'csma']) - obj.source = 'tutorial-csma-echo-ascii-trace.cc' - - obj = bld.create_ns3_program('tutorial-csma-echo-pcap-trace', ['internet-stack', 'csma']) - obj.source = 'tutorial-csma-echo-pcap-trace.cc' - - obj = bld.create_ns3_program('tutorial-point-to-point', ['internet-stack', 'point-to-point']) - obj.source = 'tutorial-point-to-point.cc' - - obj = bld.create_ns3_program('tutorial-star', ['internet-stack', 'point-to-point']) - obj.source = ['tutorial-star.cc'] - - obj = bld.create_ns3_program('tutorial-star-routing', ['internet-stack', 'point-to-point']) - obj.source = ['tutorial-star-routing.cc'] - - obj = bld.create_ns3_program('tutorial-linear-dumbbell', ['internet-stack', 'point-to-point']) - obj.source = 'tutorial-linear-dumbbell.cc' - - obj = bld.create_ns3_program('testipv4', ['node']) - obj.source = ['testipv4.cc'] - - obj = bld.create_ns3_program('tutorial-bus-network', ['internet-stack']) - obj.source = ['tutorial-bus-network.cc'] diff --git a/utils/bench-packets.cc b/utils/bench-packets.cc index 22643a52c..387bd1907 100644 --- a/utils/bench-packets.cc +++ b/utils/bench-packets.cc @@ -23,6 +23,7 @@ #include #include #include +#include // for exit () using namespace ns3; @@ -261,7 +262,13 @@ int main (int argc, char *argv[]) if (strncmp ("--n=", argv[0],strlen ("--n=")) == 0) { char const *nAscii = argv[0] + strlen ("--n="); - n = atoi (nAscii); + std::istringstream iss; + iss.str (nAscii); + iss >> n; + } + if (strncmp ("--enable-printing", argv[0], strlen ("--enable-printing")) == 0) + { + Packet::EnablePrinting (); } argc--; argv++; @@ -279,13 +286,5 @@ int main (int argc, char *argv[]) runBench (&benchC, n, "c"); runBench (&benchD, n, "d"); - Packet::EnableMetadata (); - runBench (&benchA, n, "meta-a"); - runBench (&benchB, n, "meta-b"); - runBench (&benchC, n, "meta-c"); - runBench (&benchD, n, "meta-d"); - - - return 0; } diff --git a/utils/bench-simulator.cc b/utils/bench-simulator.cc index 6b9eb2c2b..1c096b113 100644 --- a/utils/bench-simulator.cc +++ b/utils/bench-simulator.cc @@ -23,6 +23,7 @@ #include #include #include +#include using namespace ns3; @@ -129,7 +130,6 @@ PrintHelp (void) std::cout << " --list: use std::list scheduler"<= ns3.Seconds(123)) + self.assert_(ns3.Seconds(123) <= ns3.Seconds(123)) + self.assert_(ns3.Seconds(124) > ns3.Seconds(123)) + self.assert_(ns3.Seconds(123) < ns3.Seconds(124)) + + def testTimeNumericOperations(self): + self.assertEqual(ns3.Seconds(10) + ns3.Seconds(5), ns3.Seconds(15)) + self.assertEqual(ns3.Seconds(10) - ns3.Seconds(5), ns3.Seconds(5)) + + v1 = ns3.Scalar(5)*ns3.Seconds(10) + self.assertEqual(v1, ns3.Seconds(50)) + + def testConfig(self): + ns3.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns3.UintegerValue(123)) + # hm.. no Config.Get? + + def testSocket(self): + node = ns3.Node() + ns3.AddInternetStack(node) + self._received_packet = None + + def rx_callback(socket): + assert self._received_packet is None + self._received_packet = socket.Recv() + + sink = ns3.Socket.CreateSocket(node, ns3.TypeId.LookupByName("ns3::UdpSocketFactory")) + sink.Bind(ns3.InetSocketAddress(ns3.Ipv4Address.GetAny(), 80)) + sink.SetRecvCallback(rx_callback) + + source = ns3.Socket.CreateSocket(node, ns3.TypeId.LookupByName("ns3::UdpSocketFactory")) + source.SendTo(ns3.Packet(19), 0, ns3.InetSocketAddress(ns3.Ipv4Address("127.0.0.1"), 80)) + + ns3.Simulator.Run() + self.assert_(self._received_packet is not None) + self.assertEqual(self._received_packet.GetSize(), 19) + + + def testAttributes(self): + ## + ## Yes, I know, the GetAttribute interface for Python is + ## horrible, we should fix this soon, I hope. + ## + queue = ns3.DropTailQueue() + + queue.SetAttribute("MaxPackets", ns3.UintegerValue(123456)) + + limit = ns3.UintegerValue() + queue.GetAttribute("MaxPackets", limit) + self.assertEqual(limit.Get(), 123456) + + ## -- object pointer values + mobility = ns3.RandomWaypointMobilityModel() + ptr = ns3.PointerValue() + mobility.GetAttribute("Position", ptr) + self.assertEqual(ptr.GetObject(), None) + + pos = ns3.ListPositionAllocator() + mobility.SetAttribute("Position", ns3.PointerValue(pos)) + + ptr = ns3.PointerValue() + mobility.GetAttribute("Position", ptr) + self.assert_(ptr.GetObject() is not None) + + def testIdentity(self): + csma = ns3.CsmaNetDevice() + channel = ns3.CsmaChannel() + csma.Attach(channel) + + c1 = csma.GetChannel() + c2 = csma.GetChannel() + + self.assert_(c1 is c2) + + def testTypeId(self): + typeId1 = ns3.TypeId.LookupByNameFailSafe("ns3::UdpSocketFactory") + self.assertEqual(typeId1.GetName (), "ns3::UdpSocketFactory") + + self.assertRaises(KeyError, ns3.TypeId.LookupByNameFailSafe, "__InvalidTypeName__") + +if __name__ == '__main__': + unittest.main() diff --git a/utils/replay-simulation.cc b/utils/replay-simulation.cc deleted file mode 100644 index 1ce94dab9..000000000 --- a/utils/replay-simulation.cc +++ /dev/null @@ -1,329 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2006 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 - */ - -#include "ns3/simulator-module.h" -#include "ns3/core-module.h" -#include -#include -#include -#include - -using namespace ns3; - -class LogReader { -public: - void ReadFromFilename (char const *filename); - void Run (void); - void PrintStats (void); -private: - struct Command { - enum { - REMOVE = 100, - INSERT, - INSERT_LATER, - INSERT_REMOVE - } m_type; - // uid at which this command is supposed to be executed. - uint32_t m_uid; - union { - struct { - // time at which the event is supposed to expire - uint64_t m_evNs; - uint32_t m_evUid; - } insert; - struct { - // location in the array of events to remove where - // to insert this event once it is inserted in - // the scheduler. - uint32_t m_evLoc; - // time at which the event is supposed to expire - uint64_t m_evNs; - } insertRemove; - }; - }; - void ExecuteLogCommands (uint32_t uid); - - typedef std::vector Commands; - typedef std::vector::iterator CommandsI; - typedef std::vector RemoveEvents; - typedef std::vector::iterator RemoveEventsI; - - - Commands m_commands; - CommandsI m_command; - RemoveEvents m_removeEvents; - uint32_t m_uid; -}; - -typedef std::vector > Removes; -typedef std::vector >::iterator RemovesI; - -void -LogReader::ReadFromFilename (char const *filename) -{ - std::ifstream log; - std::cout << "read log..." << std::endl; - Removes removes; - log.open (filename); - while (!log.eof ()) - { - std::string type; - log >> type; - if (type == "i") - { - uint32_t nowUid, evUid; - uint64_t nowNs, evNs; - log >> nowUid >> nowNs >> evUid >> evNs; - struct Command cmd; - cmd.m_type = Command::INSERT; - cmd.m_uid = nowUid; - cmd.insert.m_evNs = evNs; - cmd.insert.m_evUid = evUid; - m_commands.push_back (cmd); - } - else if (type == "r") - { - uint32_t nowUid, evUid; - uint64_t nowNs, evNs; - log >> nowUid >> nowNs >> evUid >> evNs; - struct Command cmd; - cmd.m_type = Command::REMOVE; - cmd.m_uid = nowUid; - m_commands.push_back (cmd); - removes.push_back (std::make_pair (nowUid, evUid)); - } - else if (type == "il") - { - uint32_t nowUid, evUid; - uint64_t nowNs, evNs; - log >> nowUid >> nowNs >> evUid >> evNs; - struct Command cmd; - cmd.m_type = Command::INSERT_LATER; - cmd.m_uid = nowUid; - m_commands.push_back (cmd); - } - } - log.close (); - - std::cout << "gather insert/removes, commands="<m_type == Command::INSERT) - { - for (RemovesI j = removes.begin (); j != removes.end (); j++) - { - if (j->second == i->insert.m_evUid) - { - // this insert will be removed later. - uint64_t ns = i->insert.m_evNs; - uint32_t uid = i->m_uid; - i->m_type = Command::INSERT_REMOVE; - i->m_uid = uid; - i->insertRemove.m_evNs = ns; - i->insertRemove.m_evLoc = j->first; - break; - } - } - } - } - std::cout << "calculate remove locations..." << std::endl; - // calculate the final insert/remove location. - for (CommandsI i = m_commands.begin (); i != m_commands.end (); i++) - { - if (i->m_type == Command::INSERT_REMOVE) - { - uint32_t loc = 0; - for (CommandsI tmp = i; tmp != m_commands.end (); tmp++) - { - if (tmp->m_type == Command::REMOVE) - { - if (tmp->m_uid == i->insertRemove.m_evLoc) - { - i->insertRemove.m_evLoc = loc; - break; - } - loc++; - } - } - } - } -} -void -LogReader::ExecuteLogCommands (uint32_t uid) -{ - if (m_command == m_commands.end ()) - { - return; - } - //std::cout << "one event, uid=" < m_removeEvents.size ()) - { - uint32_t missing = cmd.insertRemove.m_evLoc + 1 - m_removeEvents.size (); - m_removeEvents.insert (m_removeEvents.begin (), - missing, id); - } - uint32_t index = m_removeEvents.size () - cmd.insertRemove.m_evLoc - 1; - m_removeEvents[index] = id; - m_uid++; - } break; - default: - NS_ASSERT (false); - break; - } - cmd = *m_command; - } -} - -void -LogReader::PrintStats (void) -{ - uint32_t nInserts = 0; - uint32_t nRemoves = 0; - for (CommandsI i = m_commands.begin (); i != m_commands.end (); i++) - { - switch (i->m_type) { - case Command::INSERT: - nInserts++; - break; - case Command::INSERT_LATER: - nInserts++; - break; - case Command::INSERT_REMOVE: - nInserts++; - break; - case Command::REMOVE: - nRemoves++; - break; - } - } - std::cout << "inserts="< 0) - { - if (strcmp ("--list", argv[0]) == 0) - { - is_list = true; - } - else if (strcmp ("--heap", argv[0]) == 0) - { - is_heap = true; - } - else if (strcmp ("--map", argv[0]) == 0) - { - is_map = true; - } - else if (strncmp ("--n=", argv[0], strlen("--n=")) == 0) - { - n = atoi (argv[0]+strlen ("--n=")); - } - else if (strncmp ("--input=", argv[0],strlen ("--input=")) == 0) - { - input = argv[0] + strlen ("--input="); - } - else if (strncmp ("--log=", argv[0],strlen ("--log=")) == 0) - { - char const *filename = argv[0] + strlen ("--log="); - Simulator::EnableLogTo (filename); - } - argc--; - argv++; - } - if (input == 0) - { - std::cerr << "need --input=[filename] option" << std::endl; - return 1; - } - LogReader log; - log.ReadFromFilename (input); - std::cout << "start runs..." << std::endl; - for (uint32_t i = 0; i < n; i++) - { - if (is_map) - { - Simulator::SetScheduler (CreateObject ()); - } - else if (is_list) - { - Simulator::SetScheduler (CreateObject ()); - } - else if (is_heap) - { - Simulator::SetScheduler (CreateObject ()); - } - log.Run (); - Simulator::Destroy (); - } -} diff --git a/utils/wscript b/utils/wscript index f6cc97626..dfbd84c1f 100644 --- a/utils/wscript +++ b/utils/wscript @@ -24,9 +24,6 @@ def build(bld): obj = bld.create_ns3_program('bench-packets', ['common']) obj.source = 'bench-packets.cc' - obj = bld.create_ns3_program('replay-simulation', ['simulator']) - obj.source = 'replay-simulation.cc' - obj = bld.create_ns3_program('print-introspected-doxygen', ['internet-stack', 'csma-cd', 'point-to-point']) obj.source = 'print-introspected-doxygen.cc' diff --git a/waf b/waf index e55aa276e..ece4755da 100755 --- a/waf +++ b/waf @@ -37,8 +37,8 @@ if 'PSYCOWAF' in os.environ: try:import psyco;psyco.full() except:pass -VERSION="1.4.1" -REVISION="92c5652afa5cd9bc5029a09cb37c5ec7" +VERSION="1.4.2" +REVISION="81764acf62a7c7247901b9a99367b3a2" INSTALL=sys.platform=='win32' and 'c:/temp' or '/usr/local' cwd = os.getcwd() join = os.path.join @@ -74,7 +74,7 @@ def unpack_wafdir(dir): try: shutil.rmtree(dir) except OSError: pass try: os.makedirs(join(dir, 'wafadmin', 'Tools')) - except OSError: err("Cannot unpack waf-local into %s Install waf system-wide or move waf into a writeable directory"%dir) + except OSError: err("Cannot unpack waf lib into %s\nMove waf into a writeable directory" % dir) os.chdir(dir) tmp = 't.tbz2' @@ -141,5 +141,5 @@ if Params.g_version != VERSION: Scripting.prepare() #==> -#6<\%_0gSqh;d!98+VFjF@=S%O[fB$Ms8W-!s8W-!s8W*bKE)XL!&:/]#/C9`#[s?QpO-q8zzzz4pn'uSPe4ukkY;Vg5ei41iFrp$E/eH;GD#9Vq\B3A'Sl?[a+$-:Du:+Bb^a7OJD%&c?28U:R'VGY-gliX=,^a=4VS2lb6\RdJ!=)07%(XgNB_PZiNfn]_$Dr'gB=k8#&c4\mPWeoDftVk[+>*g4f51!&)(HY@&4J(Md->@?EeYEVF+;dZ0X2ChmV_I0Pr#=Ki,V84,$;S^lV#pXuu[B@Aao3S/G*l1'2q=l4H5lMCA?/_m6Of(RdtI0BW8n4ek+fsC`nCl.K#]ECZ%V.gCp:(Vb]p)&-5pU`E-U$N4dQ):R\+S)\)2dQ+7n%8%4Xm\DEhM(^]EO#2]\9saBWcl_&[dEe?DVXPrCYnd;DnXJ"^+[1_G;d'S[dD\OiP+ca:UIjJ[N)m2bO5+F!@h#rLI'[1>.ul+Fe&9r5$E6qg%QM-%V@dVMj*UTkq>*RB@a8)54a?Z\%_/i]9d`u;9uq(m_$7AOh4r4DWPfClc-6dIG;pAN@jS/>Gn!4iUsO0>OC9[hdbp%[qF1W[qrP-f'?XK]B(X=h^AT`qk"7[1"W/s*SYF]?[(CS4r[en^4GTibH>B,gAlm,W$s2ohRekIej@i6hd"!-h9*"(-7Xluhctm!QK^4,gAHGC*-gPHT<"Epoote(cN-qH]?\9YS6SGJ0\M"FG'"UeeP2Ha[e3hgG0H_ku&$2)8-!n#*k^/Ih=aJ@e7i.!m>9\HT50;8D*@Ia&&#UCpU^+UXhEQ$j5$[0*r5OoH``k$HgGUE1[+,&EV9jM8$8Hmf:1pD@%R8aHWOMIVlT+O^;g$;k0DF;l(+-3"#@9R[;"@;lJ#@OLHEn-?Yt(2mMTe%FnYOl03I+Ze_S;Ph"1gP#DE)LRG<=c1ghDb^g!Bu!HelIh*=W4sGItGuT/YBY4gp8V&lgfhf"O0Hq?@HncL-*eNt^tFpRc*4EU)ucHG+4,%&?YBUTqo)'iAUd8Z1HomkF.@n%BZ8qej)QKAQ1e]pe\:45=bb0!DI%Fn!tf=\R]4NnS>5?#]6#U[$Xt^A5Y?Z5_Kc4eI&\?YA7Wa%9._GRkP[kj`SD,fjI;I:AC.cNeB[\4!:'LX2I:ci+l*lHt16b]S6R+n7anlbi2Y%I)RnFh]\cVsA(*XJ\kE#!fpdsHL!I4qR5og(1rtp9(&.%/Na$cVC`*:2i?6ZOiagmS++_)A!X*JaHPS-Wi.effl!Bu;YfUrgI0NtHV8l]_fX_?;?I:^RGg+NA>8e40M54oTbeT'5P=-`AOX25GMFI\'1eSu=:s`%6'M,#l+tR;YN(PXi(rVC_$:PS+7T;[K1*FaS8lCWf,a<,`fU5qje<+R%as@u\BGq)t,%O6DXNYKodAhpf=L#/HLs74_aU0Mb`Mp+s(nqkr=er9r'TFGOdA!%F;DOK`bp5_6@Y#fDM3Mi`QH9RbBhF'cRSb:V":u"D9/9uk@S15])7%AI(r[\r)+dkj[S("%M@u&*KSct$N?j4B9/RVT6:;S&6=WStKZl?9,S26JAh>GS,$7=-d)nbUZU.Bje=gJj$'l>Tg+>&mZttn+9%,U6fZKKd/2JT2,r?iWel-0;dh6KEYaHi(ZSi@l2&&nb8J+Nf`ks;@,+8s4Cm%YH8ZO88dSZbXbqa,M-512Nd[Dmg;F.])>8kmkgEhOs,,191fcsBaZkX?N@h_s5QGcfq2&_Wh?n.@>;U)NWMMY#1P`09eV3-rU=U>XVL1\AeYlc.Z&sP0UN6%/r+IE3e6t.@[KZPW31/\>+f#lQSJMS.aZ3c.>#t5+CA0d8&e;@`n/Z"(,AobP9QH".&NgXB%X(=1;l#m))NbY@jO^NUDV(<9gNH+8PI<=Nr&7-+'tG$)hI`+;Tr5RVaddNG,+dD28fNR?XOW2+^_)MT]!8ef+pbD&,%^f$UN:Z%09?9n9X[9$""Z67POS,_feT(tbTn-u@V'Ju$UaKs`8N10[qJX=V1E=KlL39h*g#fsYL)/P;>]`Be4D)H)fcC2-JMWG'XZ;T`^Q@*GjD%#bON@9#`QK$u/"\]0=KiCBYQfuJ)'iu52GK-G((H*0P>H!nP%BhnPpSt'R$pYlAdsWp9eAtRP;H/e)O"]C7\V^cZ&sXjCl&Kf8S#,m/WC\q%)Q]t,h,sS"\c9kCaRRIOCW)V'p`OU9!^ELP6qMgKOZHBN?Fl[Z"b.FVGc'f[YnlgdSrW5aGS/4R8Rj\LtX(C6%tM+0pl()P.")hZN^jRP@WC1XbeW?>;W4:Be3j1N0L]s/7QRA)TAMjRZ[k*(1Atcg-h<$).G04OsHpXRUNME@jXa$atf,R-n1W`'NS&W;U)$`Ou1X%1nn-=AW3U';N_Zi5[+hZ,pflPVH$'jVV;@lUs4k*aX"rmOK),M)*tMp6u@iNK2t]'fa03E_Efr^W[=.2R5RYlL>*n/`l95mP8-QCeHX7?;/7N*ZWOUXaJ"u!8o-Cn(*XDp6oBjbAYR'fXe`oC6*2&6=uI%1D2U\nfhF6..b6*h,]/O?P0I^?[^!9\WFB_LW_66#_e#kad2J7V`77/[.p>ZGZV?OiU;U6B>1um*9h`ou,T;ieQ>(/)Bi8Y>'d8uW<7<jA.=dCD"'/?g%AYd>)Um[NCPabTDdVN+oW2a"#d^GDi/>O^F+gkl%JCXLi-+lh_=-VDkQYcr[,p]""/HlsK!`hJMQQFap.Wq%5NO1,gB;b.9G7O7U*0]/:6/q>XniTsnOdrB7#lj0#/.`p5A([_M9LG;4--6>:uM5-W_K,7rRAo?[@D.,T^?_KE"V)#$*O_cN3=E/W"IPA@(.6&+mdS`>mR[$],NCB''NA1ik*(=**2^m"YD6ZP`'7r0Pq4aS5_8::C2%lCr`A4k@-d,_&!TSsH#_OL_OPJseQL"NV^Y\RhL%+E-HZ5_ae)DL&4tZq(m_N*151+[YP@FlcL%K*2DL8GM4\@neh;3XZUsH?k1dA^Fc69pJUC!?:.aGQ%/;$ZjVM??e8('j\%5j+u;4-m2(eX66<=94Gh^U;8'P?#-Shsj'n[VIc/A;"re7+sM'.*[GrrNJT]$k!H-/G+i*@S4BY\mZbd,l0?Gc3l\,jpRV(n7Aurbn^*^ujK,Mg6,b[u4QY7+3&q/PI4X]<3d^8&2rlmtC0R'1ZQ;"q;BB3kkDa(jt'&c*nno4rdD^]^i=MC*/k?7&*<5pcDof]Eh(Z'.:^`Ld8l"$ia^8WO+t>-noM_iqYDJc5&IZQ"c1n,b;'7Uh-/fMDsT]0K7//DeBB@UB[2,4IsjYh1;HTRjV7]\9Wf7gk;M.h_VZR7OgZd8B=e1m"h?@#V2439&ninrJqRDRmX(%G8aoF*9dK_NQ=Pp'H%,pCX'lE_t^P0S%AEcf\)F/'F-l8@,,8@.+(cFU*DMTooXm[c'WeE@_oMkNl!Xt[$7!hpT;_Z+mbYFW@+5!8mGY*WeZ.^;&R6]D9HP7:;2aFqhn`OlaY%IKY)WC]_f=mUhpJZ>;[('HjrNJTOS@,#I`'2>1*k)3>"?>hbI57A[er#uT-7C7mHZ6n>]k?)8JBtdMCee,Y4U1e;Oh;WZ6/T1@!*%la"Y*W#"2qj-W/k"'S&=q:GhlAC:gh?,Jn%aD=&fNkS)rQ&PGEE*%<>>[I"F[(iuEfs5TG]Rg9To>-BO0,0189N!$N^sd<0("+r0_C$Ih;U_)C`0UM?M?Qj[^m!'l7&j[1VraPrTBqPG[#?Kr2,C601N*\g;g5Q8l.ip4mpc&Ull?^&bp2lA*O-VTj:c`M)V[JFV`H%uNeqkTN?M=PAZGZ4?"*(f&$UQT2>U;AYn!>R[uW04"Fnl"0-oVVD*u0be-M<1&(5bWO-m:Kfk=^]qX.$/[e$T]937Ngkms)XEkqm8$I,3N3jim8,@`j1U'baBlRQ$6n%)t'RTSF1ig`@H&\b2hgEm#MMd=`W/8e\XPj`*"mS7`<)[5PUT>B'b"2lDUh';9i8T$tDh4H<8$SAI$Y!_(2s8)#%o'KCPA+$Rm2"f8\J-;ER]Ulo""=FU*k2N0`biG3A,l*ON?()EM^b8RZs>J3%VT^ZB8M!*lk%3,c\0jkMe&UQQ'#GSYt12d`L/!/mZa^*M0d_+mu[-Ct/k-IG!Y8]AVTh6-eBH@cc<+G5D!a[G`hsd)5[aNkS2^(5d?Cif*DDO?YeECa`W`mSD*0NW`+jR<3eiISDou]dCo2ObZ"(og[j;H9pK1(^VmgkT,O=Xc0ooIbfJ%"sM7Y3@d]h"TOB*FtTg.&(4FB!1#u`^Z3!bZoKBY4PE!(XYfMkNqKW#n2]d8N&ai6lU,G[qcnE%%92r?%PNZU3USKQN_,tNYL6kBY2)T_!OYplC&)Ge@*'Xj6EH9Lph.o$$XGCu,87M>GXI5QUEOHc*`UTTUG\UjkrG$!AP+PnTbc/Z!:dR:(:&PO,(hoa5,^9j.q0$2O=l,ao9'a4aD:MI<>VGuRJl$EL>'IcRdWgN[W"YKOa@it]'VA$i0cRU+@SZUY`a0pK[nI%=`XI#8Q&g5#b+gdkRhQg)CK"+]"SbC**]rRQYVSbBbsZE.Z(9k:U=0.CR6$B!=t5@UK$t.d&$\2%&mlr,[nNDYQ@oep,d8k^_tEZf*)!*%S%iTNj&(!l-?SH=1.0EMdfOWL)EGkD@['=Q^7((]dh@0r\`bJ]^?'k*8YAZ*pW'-p3n-U+p78Vkm^2F6>rl7qUmTQX+Gb,M>,U-TmIsXFR;Jc7\EkCUln3s]nu9=c8CWpFj.b%A/fq<--.oQB"jC-h3",)7X@mb3fXI&-5%mTd;#KAf7kmRsIo&E^B\7t=`'ZaY@.s(og6Fk)Q6qcl]si00gTOt*e`AGc1nceu(jV(6PB6)B*YG8+nX09H"%"#:%f1_^9P%fiaJMcW$-J*^P%YqKk*otUf]WH7O'N`9B9Y=V`;j?`GE)^-&g:G\t0ggX\7hG`0S^\7?@QKJ5h5Y*.UB#M\lFh)mN$?VN"b(i?k0mF>/b<<)nYncJ@aQ+m=+7(B*Vl&2F'AJnF$aE6MmpqJgN'4_Nmq5`4k\4#LXJ@!i^8h,mmj`YFGAm!4"]uLZEc043o;@un(JJ**md%fRYMMWj)*.LR77VOndsu^%qGoBOG@<[pua!9f/_'#.Lj/&UNW7XNN%,TMiVXm#^5j<(kWhKBh7B\HKLm.4,G=+?PGdJ(!58gjCo\,A(1dpi06&Fjqn)s7JjC(iUSn7GJV^;X%2[$T>34rO/4F:)]I[@17kN&JPQe&$u[i8sfkju@Cd0kV4D:&-&YmF-g/Hknm:(eZqh"UL1,fJZsUQ-U6pL27]flTIrG@[(3&e]LI-jFIN"NPAr0:?#7S&NR?F_9d9*c-`KEl4B@gN6rJ\9t-TO&Vp7b,!eKl=lAtOF8jqXJ`L&>JOUjOFqJD/%Tg`ZF6]%tbF!+57^lsEjaQUM`c^G\[iSk7%9d+r@ad4%KU$`>NYne5BsOj\^"iF'!7UqM3YNu,HJ#`C(D(mGWb>^6c>O`_6t`p5T'M;)P%uhPhM9eM+%UR+*DdO5h%aP07Im:CdE/@uI24jH%/#D3o?^pdN[RfbPTfFgh$SCJU2q"2$PCTg+_?MIm-fZQ+PAOp@%D>=-j(9m]u8qR2R:\5ZMjd.Hs(l=]4-[0o]Yru*9?hN?-niX-M)9G+pchDp59(U(aM6.X78,/3ilQ+cF+NIbMC5tD_TTEigq8=KArp=f>pkD"*)V%iHe,P!a[l\YbC_Cpm1U-/eWn$b>*N2LEij+]GU!)9HZc>T6Z;180fKd3sA9J@^a"9[WU&jZ^F(996."7f_d%h/rH?lY%Zh8NCB/03u<$9$-@0$!\=*(lO1\P4e_)GoEGr-lE&q+r2)NST\p.YDmD7m]`so;\/jAZL_VG8V_Y6TRd:>'<'pj+A]fND7HhIp$eGAIgYVU*`E)[$1/^i6!Z+OFL08Vo:b:b68IbPtc/T64ob4oRN"Oapl8P5D0rffii.>GkY%JI/;Q*<=7oi5rm;afi2BXp&;#Z;C@C6+$qo8qY^#1E5E)@0prJPYUHB4.1^6A]p+c62@TNF,H+IGpm>c1d_:cqF/'orTl,)^!Tj3fci8rdKE;V6:EVYV9o:@m:g@n:uk(Fd^qrJId6`Dg.qVH5eB6)QY&;OMC)Y3n3.pCYkZ,)5e5k;!Oog].oo/'#q3m2E6!\P93^UDQl"X+O9G)f:uFjUkN%Ce?bkScgfBGgip&A0\,MBIYjGrmg?'h_Pk-)]V_"G;?6\;C/,!P!EjU5"CYT)kJ'.1:khe^:2o>2dIaudI;kk2',);8l^F9?qCJ)#mOF9]Qc&f2$Lp#,f)"jeit2$PhVrZeUK"$BQl2[:><<21ao!C;,@-3;]0dD%n!>0&g)8#k>oAY!otGl+,$e^cn]GL[=EuTp^mKK;"Vgj"uP'b>NEL229fH_uBA1Xn:a::8ifnTl>EC.g13IOGa&eilc7H2X3%G-pHLDY=LO6uKY;0#k<,((IFA^4e>g@$(crK4Ah)LI*RT:i?X5Z5Q7rcgU\$(`/12kR+HP^YBo2M&.lNpUQHuV-'kiDT#ERQ=9a.8!ZeT2L(@5i&61["2#8iijCnTJ=tUF'r$3U&`a48!MD[fr7A1IuZe*jO1!oPIW!ng>1-iOMaJa+u.t>WuWDjaGNbZMebkZ;kg?+]IaWK0j3K0j;>HW3JKZAX0[f2*&iJT_0jnp\W6FMCpWP*V7Ub:2DZ!OODm%(/bfk9huhuYC8%tlKiRG6pR=&&Lq4_K;hTKU[(;a5';e\PXRHijJHS"^qWZj!=?_EgA5Sl00@;'NYqN&k$9s=X@Y24*<)3WVE.Gf/<<15agB^"_>$\"C9aD/\ff!_p0,A=OX-0lTkd7jI7K.hmZP&;iHqVDKap'XZ.[!pMn6iPn0*AqN-^^M9+YVIIif=5k2Va"%1N?GUe@,@[UQ/X?L8tGm+5UR(Cc(V(eYTi]?tEGZ7'US2eQc+GculCR"uf,3)(2\8CiXtMse1&(jF>=e,>YaY4QAl,@d8!W99,W4-+@bEJ\C`9J4`rD)UjOJBK)dAkd+pKh[@qOMme@(\Rec:A'kQ8kQL_-lu#A&u.oRb$2I\;/O$>&TF4$d&dQqu,6Tj,Ce7<`"^Ie$k7U2[2r2KLlG8UM*f%25UOk`"isu,dZmerd&GW8K2Vc.];sGJFnU>n"cE&LHOW*e#QcNZaF:SUO\":=aph&:#Z!.N<9sZ_G9;[7\d8H\o+fm,COrLV>2F'rM5b2gc@K8g=H-[jJp$KA/k)J+"3,`Q^:f6+M2Nf_)?B*9G7!>T;2!S:H<%qpnA`\Y>$5[,"=,k]#```]Lko3PWSlU%-m<6.Hbr)aHYjn>+g%q>4%kW/f;pPDt?e^m4Y:?2D\[3R.$@D0eYtIGXChRbG*1B54N%\ffaMjQI4kR$>Z'o@./XmS3V%'?7Bsca&:Rr]E)D7p=b2G>[;B"[plZB2\>[,VuX?8I.-o6ts,`pZk)/N%k->D9uU)XbZlQ2ml+Dum.:#9j==C^uBQJ^NKr0r^!%2%kZ#K*]MgB#\ISCD0/OG)qg**5q`h?gBp=US23!YCon/!K]nrI,g7;@G52,#kqaq,+m;l$ME.beGNsT\>CgBknWQIG;m9W+]Wup5ZJ"@hE^r:to2slh2<@?`P1LgChBn,R+$bjR=dNffnnZZm1h2&PYFQ4L`i5bst&``bAeEKMDuM[+P#*6k*-%7]R8d%>4bD:kHP=JPp9d+u_0)??siaF3a?Bk6XhjGri)`iAHY-g@k4%]f"!>7<`!Ngdt7p[r\`g]!Ep+2`GokmlB\BI/1mT`uc\"**L4d0*(`WtLdMi9jl];fYOkX-Va]8?.2YZm6nE.6Ap`IGdFjsbOjerM52#VUi]iru4HI=Y&Bqm)(1X@nJ(pY74\_Xn^UX=m7Yri_?+/'4Qh@=0ocDASi@FiR/3L(i`i/UU]lND,`7:@H*!J:2Rt^(-qE2QBW]*?dcuOBPN%l&Gh[$\T`n[@Eg"O2>u`Pmt6_)_=9m[ln'(/UND3/I+D@O8gSl\6P5ii>RI)Yc1i.q7-+QSG=66UU<_Vh7b-P,QF1jmc[5!&f)!%:>SGG+eOOr#^W_[$K8[$_I=[b(*>o\;Q&puCmu]4eBm.f2M$#[r"5NMZ2KXI@oQ;DWdVITC-)oTJpnB]D4)F6p\m-),f4/8l&l\8"+b+NG.99+dXa[qAP,%XHJU*KP"$X;gW?VtNi`bC#chY<'5ld@I\JkSopNA\X-Nl&f8mjha\:4g?*BrgLR^*#<8Wjg$UA*GmCC0u2D^s?ZSpgY#G"1a6\o#HY6@g/XqW2L&\r2LENKB]\.s[D/>QWV0s*Ba#$7toM4&o-L"\_3g\\ItGIOC(Opj07_),#^5GM(#anLCin>lLJp'2uTKro?G^30d@>r9/2KkuUHhD0.^6?%+X1\!LjRsnhLRf[dN5K+@\]^X\f'H*5V7mOn;%pGtfbB^M[)qbX__f]M:NmZ.T(t?\baBJW-8CBm;X]`09%&O-r+%4s4,G:Z)f^JcRTad#$Go>if`*Bh7)gh3:99i&UP'lVG@i!PiJM?ok-!`5cuPpTI$5EAg!s0V0F.Nq!3ksQLAGB0IX0,Ah'U)9Fc\HRi',1+";iqV8dpX8.kQGjGce]0RN8;])XhV<\3H+E.eiZ^D1KWff:KpRgC#6iF3_:oP"@JuUermFK%KR0eJ^Qh2=3p[02ffe9f!kJt%]@?N1hAM*8\no`A=QLu`kQ8:rdpPF"gDq3aCg\'4l%'VVT5oIA4FYYB-tJK1/P1_+,uEW6MND3'Q6J@6`2s=b+sWL7Ur:ggJlqSmVk!CCM:ce:5sH&FB':KGVsUltqq\F3rH>Kg^:J9iih2QKcU0KYgHR<[N`KRo]1Q9[T:;^*LuraIfd1sORIsc4kka#s1jqOVo-o($k^JT"pHmlLbp_55#`i&!Y>gDJI`%%pPYGc!Y?9aO+2CQ4A,.@$-hP4`rM=c7CRtk$72ZnD%;jp[(s0*(W6"$pZ_cnd5H;7rXnb!RWcjQadJC04iCIt!)BrgjIXWB^)KW$F#f#?%h&4Q!e32sadXNli\L<,WXVNGn0onH5h*Ab,YGRk&A+uqRj-HF#XfAD1:@9/sFlknGZF'gQc*r4>C25[#>Y[ZslEGd0F)-3N:Z!6u[FmRg\G/&8kGk:O,+Y>58VX[Pm/)@cMD%K];E=RT"SM63D_lLlfZ!/PQ?Y1Oi'1iqBae.RA`mHC<8mCWW1cCmFidpC6?^SoZSh0d?KL!TJOeqCg.`P;J,,=O:Tnu0@WaSUa-0fX:FDoh()Ap'+\N?ld^)mg32&WmT#h'dQ)5fsCmR;kUY,s-!>%Y90a@0:hb.5'CQ+'tfLJ$io]O&A=T,f/&UBV.qnG$WkaL"gKOcW;&c_$bRWbpXKl`W2+HKMA?6OC&l<*=9*h'TjSf_Fml)c)FHrHWk[EkedCn(3?^nE9a=?b9*82qD.'fQGZtrZ9st4Hs>CWHe>Wl/qq.A%qchm,-J<+fN30ch1%<;<%J6h+do9Yh+;l1t`@EFSTsYn!9X/?R]s/d'fq:g\Fp[f@MQ&FABCc0W(P'Ip'j%-)I5M@D-aL?Ir6H:>lU/5Ep6b,b[I7%;rC$@KO%Z_5eK/SDu*YRXms-dDlJ4+YaKDf&H'(UkNl>1]#$7q7O]XpC*)fhi9'onITs@s(ghJ^31o_'0@$cUQGTg6ImlAB[nf0`%VNu@C@$`?rsdZIl*AAoW-(Eb.NGE9'7Vqu[=OB0K2?Ju]?(FJ=*uOQ@S1%8&Z@qCIudQA'-o_gZb,Ms%G%AX:(cd_1mbn#!gW'524>T"Nh9c,uN@#J"tMKN-CZ8eP'\d9Q3/Vj.mm):!+.k:N`iNl!/^Pa!F2FS/F$.f')dp4'VB/tR(NqP>JZT:\7WJ_+0]S%X\8Qf$,79)+_.oTMD/b=\Q"]tVqSArSj^oAF9Sa7ODYf7f?oX.%p9AL\-LQUKrk>_Bt]R3(tZ,L8M&:$;+-*"?eDNI.[l7dc9o1rekILL688E@@*rrVdE%_jb"==t,Cn#+m8#=;p+HGjVGJ50qRFZ;`;s2LWX,VP%aY?BTqCHs^`Po"#$-VaNG]$hT6W]AX[^,!CFqdsS%(4!=_-;rB"15m0K:)D@MBbTt;k.iLSnmLM:9D4gWKHF[a3]m=+spe/?#ccP[-oBDd)-+s9#c8N:[=%Bt>7$ZQB/4o,Mn!t9Dq#$&dp/`]V@L)9_&c=j#qlTO:)!_"prZ@1S^ZRdGO(khdoS66!(_9L!FdrreF27?YBIkjW!bHdD0_$95D"IXiN,e(8+.tb=kP&L/N&5\NF)W7i&9e_)Z.^oJ#.FHDouEPsk_"=QfH>H-q51lqXhPfV@1aCVpk9DAk-dg)uApQ_fj3W.,n&\l\)s4ft1:fS3IhCf;%Zs],M4V[iYGDcLojtiqXN.]gTE6K1chi6e)2VLL49%g8aC#1pc@>D0i2gTe]dH[XIejIU%=_E795=**BI/E\jM6q#4e&K>"(+^,Y0?`=*DI9)gb553cJ3$1oD#LO1D364c=C]e#^DCMijUl`32?d0fgFoZW/sl!*&U4RqA>a+#*akg&d9H0hHa@8-=0t'+8lqYXeR8%YGA-_OId_ZnlktesOfb2&K>!Mc^IV@W'>#4]iSZ(8'EXWNlFuk:aX$4=,5A_j/iQ1g.o@@=#p_h4n`l&o!WP;F5gse*Z])Y+L,L:['s3(Lsk=S^]E\AoiNa&>R0A6WbNLa[AT0(^r0^W1_e"Q=5X\iZ6fGaMEG`cfG-MhtXP-2?0*m)jfpj3M)i"2L_3\50+*`OVFI7.ANFc#/'R\O3dUe`gXRUoj'4@F>]SbQ_t;L4SsOcId&\uqYcPWRVeR1N^l*>Y4LHI\P&o,Ne/'@AL5h&FD0k9e)Ai\Q.>NZ,PTI@+qWoaEbZZqfB`&-h`'`rJ(=+hEtUm;V!@cdGTPABlh'b<2Te.*m./bF]Ii2+\Sgm$iUq70cP;p*G.Q-5lmH/dc,[,JTVO'B#2/]@_Pr*Dq^*J_%Uu;V76qbL_ep5,nWJ<\-RY?&M&R>BaooX&K/hoi>C)u^10TjaTAgoQ7+SZ!fTB<=2JaPYk8b@&VJcQQ.(JT`mJQ?/Bf>IN/3u.-oRi6pR9P"r0K`k<7(o=JC^r7W%+C@i@8U9DMk4lCUDb]IWm#0"!JI(#,7;9gGEK-t2?3j/r7e-bYWm_7$'NLr5P"I4Nb79gA;6h)ZCi5M9$H&#TX9jk0W*4]l:$nF0>R_>")RQR*Uq$rY%Y:]7bXFF-'$.7et,D!h=^bO7D-o+cgqY$3Qn[\66[LI6'6^6k[Jlr&H*X#^YKR(G,TN6='[6qrRp1Pf,:1dom-QZAb]hLNQq]^Lt)9I+U<4@_=[S]90u&OmH,B;p2Y8Qc&R_-pepC`8ft6X[-\e[g\NBOZJ>%0[u\)m];1T]0J#:rhS4CJdj,%%,``Q7;.^h;5f/>VI>M3I?C>%\@)Kg>;SOp*V1>iJRf`?c8kSkI/J68B7![*#'V+UBfaD2_sl&Vt.]=.ed)bQ^K?-JK5FC[38\D&ZV,$7MT?@#PZFaO(@s&7orW<%R0>apGCNb`#tdKG6A-doP%E_E:O1+tNZD"Y:n?*,['-<.l1KVroi;C:R1b)abU$M*dB6li+D#``JkSNS*8cOJF,'2HF,rJH`/Fh9ejL6j+"nU(A@$ipMRhfXP;IhtI^DNX&_5VPBi*q@7KNLKA@$e`Zd9Epi3E%@alAoGe)qOFo6D"9FL9,!'1a*\_H-OFp5"$O6qaD$XNW_@31@3^u!8d:d-STT7c@!tu(^Bo0:7j:!FNQ+#os!L9WR%DjMOeG=+X;aA_&p;%*h\S[j\o_q)0nFc_QiGm15:h"BNAI),'MA80e6.Rl/"/tYXZY2`pN15i:_V3r_Xqh'`7#KI9+O%b8O7I$g#8ANIKS!Yr2pJ4U_b&iR7h@)M-*WT.;Q7"!NAR$pkt8t'MN;C)XkC%^16,P&Tj\/[*e;4N,\7/e4%N?$LbNO21AZ+jSd(BjL*q`hf1@qY?_(IW<1Oq31Cl_2`AkgT%CXi"8i`tV73:`HZ"-uh#OUeWM7+QU0>&;hP)RA80`%\@24qVG!,9'1.#THB-Gd`:rR4i=`#,3)CKN^lD3fUNopTaWOPD/YnR]D(+?EM(%8L>_:)$3%:gG6YkE`u-#[C1oRB@r_mC;P7sYWNRtd43QC;p>3No1,`i9@MDL&+l%/L_D.g1LOUlmM9ZR%ATi<:5Ee%<+Ro+UkfJ/YB^M/e@H-@dt6TV!ZGVIC/qdn$c*ISnjShH)8Ij*uK.tV!uK*riZ!n8[7/.iEl5hFWr7koD\'i*]3^s^toc13Nfd/ADSC5*]-\hQH8fq$[@+b^Kp!f8L!5H*B\\=+1LmoCFQ[bS.M:l_96kE@gXF1$LtG73MHa!%=b.Bu^ntQo[iNOPhkGp(G.o?\4E`6gb]PC1U?$O[/bdu2R-R82U;\O'\-?uSKVApl_`ad2=R8`gXm;Jf`(DpuZYm2d4Hd6$jIsuB17!08jI,5k,\hpC!LhIn&=Qi;iH%S&s/`O'1'Pn9'#+fMeOCHl299[Z]XaHW[S0&@QTqN`p)%a2nWh%HAkp)Wc+)ZYa16LbKU&KE%;/G'CEE*R(?t9$<.MW:g%>mS[8!ES5ID'Y]c/)\p/7j@i41hdOP[O3Gm6aP]e"AstF,nh9@0TIl[_L=rnUKnD<'Odro`>pIA*;m,\;e=\+UC^\Ioc-KE]PSN^nm/&n>9"!FVD5d&jpJ7(\uaU7P=HeFR?o!hk;L1;itq6%-Fh>`oH3'HT>r1f36m9fSaVO&7NLIIX"elphI,&o&b$]#A1[f`6'WG0^laNhVZrVebYWQj5Uu4A3g6T'G-Cg%u9?Ehh11Z]_1s32m_Oif:hr^Fe/"o1W;q*rBDdb-O8A2&pI=D%kRH/*T"boM24>6+D$?dckB.?ad`ee,AB`4Dgb)2qTi7Q",j!pH>mQ$2a&qL+gW(_f7n>1G#RXk]q3Npa@Vp`DL\RI4V0MI@J0KlWGcseC,d+?S9"5n\CR)nO?dVQ?aj(q[5jN!W)IP;imBPYKf:ED.?^WVY+PLU(L(KOS8XQ7aRhKaLC`HtYD0)pr)a:$`S]i74P!#6c60EtFj(C#b:/Hu04_B0B)!GPnLN-bOSZ&G=)Udt-@%fHP`J!((DeZ1SHNS&/[/LR*L=]miAogWiHFEH\3\G-"5nl6`B&R)YMsC,jep]KTZHb64)l.;q?:EEa:K/\e5Y+$;i1-hsBq"@OL&\Ti&qtp<8LYgd(m8DZOE#`IuBm&KUKK?VP5"X__4E4cAuKg?C$0K,KhnFBT?#kH9_q4?+EkV49/)PGBERL;S]*,o#nTJ7B">pU]Jff7.J??#6^Y^Xho>%TmX6D^s8U=2GBGmGMTbYZn4IU*5RcMu7S8U:ts?O_jc,Y0>*FjtjoJ2#>lr3u5+9t3CRWNe@D_pJA9kJ%-Vr-iq]BfkG^F+!`W./+1&.!s%jWBrf[K9Di>Ol$t+QI)l$Sd`G)$D;([B"?)2A=g)Pbd4'n/>6"/Fr`j%jOB1U1,6BBje#l:PD*g:]L1Tq>>dW9KLM\dmc\\nY2+LOEH,jdRh!TsSrtjTTq4BL$e9f_AtdG`gS.fq1Yg/Tg5puM3_Q>bpZWOf/SLA7d%M-4+3Tu]7si)I-J*U"7J1rrQH@Sm@h/Mdqk,d[/D:`?5c/M(Stf(M-9_b7Q^tgH+l-S?,K=Qo`bK47j*H&YlhBQ@f%O_XmQ2.CBkSOJ3[(\.S&RX9`LLEpr%f82Xa?O6r/P]?N9g?&(nG6rpSMsm097d>-90mTp;;&,""\'he=BP*pdAugaQq<@f485]3Rr#:XE2V7bhTZV,e.WcrXE#%qXi[H;'&Jf0]7FaM<1JANua0n%s'P!>S+eQ4&;Z+:?(Lh9IKtODKnR7W7,Bm2kl]]\@QkLh1NWcsL+9]=N4N[9h3C:7q6X'/G77msdD[L,g)"5*f#[Z;te33#0KL^IdBDC+SB3(0]B?/dWbuqJHV.9eq,4u^WThG3ZNOAo(GqM>-+D-^r<]AtAC"V@A+-`C)rGs`%a%W=l=`l[eC!ApE9cZc;abKno[usbF`Bk)_S)(3"dROR&W;0[B;^`6eG=V8l+()]l.8n!h/'R"c\nY:VAQ:,.L14Y2@VI&e7NA(P&AIFPjQQ;Q"hI8GbL_j;a)Eu']1[m#^#YC3hr`2OE]9$K-t2"[-QK-Qa]JHrnLAJ05pcf`ZX>J4iSuY7;njlhTGe&]\pPBeK.2+`sIf5[S6.ik!"\2cc8)tYMV7][K8VJ0QjBCPL`N#.dcPIp0Rcod(`$+9Op^JC>W8;?9#Zu[C,V/Y?I^WT>N@]X,T=*[FB,BZDc;piiNURG*=>[TmOmD@0"s`n:k+O]63L9%eV0.qtFij`S"_okpFljmebt-hT=HH8o/Z"i-[l*dW'/a)pD*dW.MF<_G8tE0p*4*>?mE+h[4&6TgrmeiU1XPqMu>736lrb]In)]_5/hs7*c5"cVYNXIYgi]X4k6GQIghEl_RRc^5EpV@\r<$iMJ<^Y,c`meQ"rQX\cT5'tqr<39oBA([>,[*9Dn/0&Kq>6F@P($mAmaE`AdJ#X4)d,&8%MQ.[X$X3!;sl5-J6PJ'Y]:-ojkLP8o4=\7]CV'lRJ\6EdE5!$I0okQs`hfF"d&Pri\eJfg@7%&ND1X-W9bl)XP]Q!PC;6p^@.K%!G2@06;"O3L)?r;Kb8'8(V2D,.&$s_$`cID.AZtK_o@6^nfL8H%HkXrrRLTUbng]S%(m1fmnuBdQb][%tjMC52;=*.`55s2u*c[`BGu)m@ihTgGMY9j6''9>/GLj1Q.+mpN4a!n6:%F.#Ap;'oqd#)<$eOF"^3?`L1b-d@j,8l!C-\Y3FU-p\'ahM8;JFk7Kgmc1.V^f)9[Aq)u75*giB\*b8T`ZQ1fjZD@b6fdj?@OEZ=3kkFX3^)/Q[BqI<\1Tu4l`KAX8;sWk0M'G;_VQFE/M!\#ZNJ]osh9LESlYa12@l7-TN-'N+jMj%;=07M8qUA,0T@:^(PPP,e13(n4;@["/H/h!&HkY4;3YA%H*&$/M8D>S]\2;RdeItN<'6N_;WP:K`KgciTmY]uGX1FUdBk:'0Y05uc:4^_[NaZg$71mVo!USpFnjg^V8*b-CJWG;!G%Qj!X0c=.VmgkJLTYD(+gu@77tqc6UQXZOXR.&D4lmqnc###4JYs-)pCY@\a^1_Y*V`)0JJ%daHPAlN[MEEE>4h35b>"HNrdNCmWimF/hl"!CL.@@,?$Lbiarkp>Hg?\F>DQRTR`N6f`9-B'u,k&;b9lg*ftWY*Z3ZUdLk>^-'g]89W0pK2-e=(d2hWQ3YTQ=ftMl%/2k`5s@-+F3-UpY+H[[Kj&c6E.oE>qW.l*;M!;f!]$pdl^!>q7P[kFC;7)PgS9O!@SqthY-N4LHK.LACu`7L_+@s!jHLe]lKl9NF"<0c0ljmu'j_KObP4E6isSgSS!IAql6NCC>5*2\Hkf-i;'&tYKCY9[0b.ig1O@r-F9B;ru<("Th*ZpRU!CQ)rkFfEXHUn!IV);%`+_HWoHDo5[Z6?Pe\kKm&;>dY7Iedkp'j8=[!=R`P0:[K_rOSLR&a1D;p.OSq]aMu1@cQdmOSG//fJ&(0fKT*49n;Z=lpjGB)_^&aXV'#XdP7E1O_8bs+fu:KT.F&cWH=0`:?-aJ!_?-?,:1l1A^>CfU7Rot.`+NcZksb%23to%PW9!ZtGLK;!Q1$eI3_;B)h\C"up][q%,^O!Z0f&Z;X:7Op3=HF3a)o5+MErXHKH:!e$7fF)YE'*&*rp@_dIY9=b6@g9_r(.84$JVF0$,2Z;Tbq+T@tU/1OWD\tMuT=UI*Ad:-ALWhp9OC"J]q4JqL_XUQl2i3C*LP.lkXFe$qD-)_8FkmYlWO%fOU9Gs?j5nC-j)W_Y7FMu.'#@\:9.Mel?1&?J[gO\f0Tlfh^FCCt2&'KQTUYD!GZ4sstf7V-ON9#3-h*SmO6%#[2HOYj_)=^0kF.1t65%gUGm2'h$J,N[.:p[cLl=g`rmBU<1pUjfRme,-J(R#,?SA!7V9_!7-G\ZEX?q>B0r%J1?udsp$s&`b#]m.jq!4]X\[8)I:qD_VZeOXFKs6@+!!lf$GB&isbk#Q,.`^0R9g9KJFa2aU&d0Hsi.$SF7Xm=^T`'*KjoDBes(E0DVfOFdB:J?B8?K?GPjR/Q:UnR3QM<_mHMBDe8EUBeG4G?,BG(;b:b'ert\OCn-6Y:JR?gkUU>2HR,L.\T[.XX5&If]qdD2)j<B.g_SsP/D\7%+LG\&+t$=2A"?uj%Z6QNV])C5:)gJi5.C5SL:RYE8ZQ.HcVG@hU<^Gl1:$%/+EBFNe/^d$m0L*f0?\3l1DJ&%=`mEhAWiHtVTiD\$_)9[VH0*HYgSoeB1scSK9J;3muL^32"nAWIMMLnfRN`8[W4*2I4J%#9U@-OY'l@OAQ28lW4B(DaUV6ZF5[,#HT75g%PP.hN7J4V]`ABYd%Z;AD3V8ARPlB;JQdn6#9#"8AcM*r)BcGVs-AF27Wnlp7bF5&6XKC,'Krh9T@',WB'lup*DEDe0gO5[9F&a^Vk(3_@$s$UkYY11nKP&jrR)cc@M'n\u<:NDZ_oP4XH6TQ>e`Sg6*q@c2stZLT_[\`F9k;HK5K6bmHZlP4j92\QUt0St;.1I'H#a($@F?plfoRs=/;iVbr.fsYdG)2pb%k+LLKI"u@@%CVb.0^6^c-LD(!ps#;p*RP.sP(&1ZpD^ZSr#!B@R>Fu)pj#%]K(]BOZ`Ig$VtNEKMjNMdD9nV<5gk69rPfqa:K>20Ecce&h*))V1oGn+3BgX\6X(ILO'&P9qYr4N0V'i/;9-NQ,G/e;T_%W;/t2:R5kQp*%n*$)%L<[n&:UCeKI#02_mUap8`]7Cd*C@*dLr#&\S!^@"u-./LEuCYXea0dg$HneUIH=mii[IFdtc(>#Qa.GTn8AD@QR$]7.*a5Ih_E`Xp>8\(>QIf.*MnaXq3T:U1BP9VBeaOYB$17=W#_F5&,A=K`4G>&t##6rmA(,)k:#Y1MTrRd\,L(s?6?T]Fn(RNkJBu`(+Iri4Hqkf2AY%a_W-g^N/'W<)%2>"jkDta'Q/j+W:A3$[W]=TJPT:RZUKHr>1H#!OaKNiKCogum?%\iAH@;gGBS7jlS>p>DA8l!eSFNE9`phlL4)-0_%X^6.BNuFJZ8AYZPDnbHK;JEeeDo6R-q#4C6[tS]a(J1:'5ZnQ;rL2ImG?%gX)K:eaU\CNRfKE,?gQX:SOP(rk25AgjU%gH[rNV`"1Jom(3'+r.B+."3Im^Z9TkP@rjIMf[KOTi^Goqgcs!d(!j>f1qeNA'8FoDkoQ2"-hbLksT?6YdZ0=dpoEme..=@,dIqnHQ;%3pc,NcslUUDPu,^Rm8PPe.Vq!)=aD:FKSK]?9-Q<9>&P1kmJ5,U!DO@M0t;0-4g8+mDbjLC,+_;RU&8P_/)0@VI*0aG'Lsac9.7Fu9Z16d$]>2tWYZVXokgr<,IYC9/^bMprn%M\2[h$M/!rb@#`9dKE1Om`,q"m/=RZ0+.t*9^L7a-'f(uj(E9cOA(US_opY[GNR+,E#aj$i\Qr[2RHo1B!Sl*3"lBejtGbM(jL/dD$P*teY\)pCj95XdqQR:cO2!,%prW2Z73F^>&L"l(OIbjP%tE7]aI)]MNN(q;6$-lZ,%Y;K2(`e1YZVb\7%gMf'1gZ6Cn5il+=E7hj2hJ-mNZ$,>184GNl@PC4&'c,Qeur0p-gk[g8,YALqh_q8]#H\oAdRP-cHDc0![5$,r&o8U`%Qg#.^P0cX@ZdZ2Q]-m\cf;Lh/qW,kBT)Wf'[2E+#G*"AB1DgDcX0(@RFCP8a(7ha7c9f#9kHXY;FEQ0=>KHXipiDOR=_mp[sR"3kX&h5Lq]%B!fR\B]Wjp*OL3UMmBEeM&3A4Y5^hTLF/;`F;>L_Naud@arKn``KmNI3A%;!di-i`9lJ4r%ApM^R57dNHJR/1^`dr5.35'.aeR7?_B[QiM;V6e%7eRFHgmo.,#OA(d3ZgWm?X(**\EGtQ=^*LSU&eRJU)'N#f4(o5XNOmQjTl;:D;-7FOE>S2D?0!hpX[IDCFnY9o6H^O/Kn-T3+gPPmGJSV.nOd=`ob\=XpO-KPgkPGC\')+Fa#Wl8"'7H7V,8HIJj`$4L);,=M#2G+kWg(D06EQbjCn1ngcofrW2Ju9l2O@9m4'_36bk)uOq:+dhLtI"^M-Z,8`?bm7iQ4#V%;I'#Nm+NG*b9EUY_%.=6.gqDbAec5#R"cNScZTSr-M#;,_l#E<+tHo/2ms]*sOu=&s";T2L/q:PB7p,P=2q^U>8aa7BFY*"X>O>dei9k:%bqN.>[$&25]?2=M^7XK-U-$dChA,XgZ,\Y2`6!QBKO]N=%fiXcU:54Gg'LNoX<$N=SB41->sE:R=Br1Ed(nEsq(PS!p]&@jQfdE(_6ZmTlABk1$q4'4QU>`RCl5@"?+l=,HWR8QMdjgl"U[lmN&b,p)&`JC*HJ/r+pS9"#a;K0t#dC`btc>P]d:"e$[(jX"?eaEeI*\Sc0@0Y/T[KFT4`+^A)p2PO\B)<2t`7gL%60qL7Qr/4`/>!Ic9#`aiL9kSOEqF.>te48UH$$d0Q;7b!EL@"Xp$,_X52)YI"&U\aB&Ik=gLeagJ3[HhEk"pkb7s%>W5OCaI_L-AYg%#K*mRK8A(N.u>c>=l.ne%Q_#mVf5);h_,&tchkk7PV/S6X>^D1=4R@u-,+R"U5LDie+1cD`^.MB?`>;2%)s-D7T`Hub1jCnA=nO%5S$SK\n9H:KjMbDr+qpCrTL-=UO`\/GC2"sSkjN5LL\0K16N9m:"t!^o'`;-:,H:Z"]_LB,n)%PG[FPT_Q6ooo1X-F.MX2@0<%ITtek"c.0ff?]gK$(%&=;bla;bk9611iW^f,S@7t,A"@f3G>'/1Y$;@b!E!H*^VLkaa#ar[H[K(f*^#(MY'?9S9J^G#96-DnegC4H[p@Ihh=F(]0o,0!/o:(d"DaHjDicudR"Q1^)MWD+@pX%<,_U##1!?"G\.b9odIhWj1"!M^*J)=KH3_d*MO_()3$B_U*Lia+ELZCLg1m7lt]q@G2B'!nZ[Xm[-Htgfr5T6Xl:kM!1f$/V>=Sp1)-,)(O!&Vi`B@eIE%C,Z.oadHq>UPQY.MGZd6nbo#5lW6UHVb=XbR;EMJC"D1^MkrM,BCLoe=>]6bJ)CC^FXLC'*:?pl^D.7HN06R:d%XL)gaAZ8-IC/'HR6W8IddqtjnE=AD7AOa0S36bAuW(4VEd1LOn5GS8+_66PSq'N/1!%/iofcU"bVIkA',<:*PM[I/?9RL7/V3K+MA:Qp6")G!Yfk^e^2e]8iu^9\=+"GB40iqD^[dCVpipKWm\@c+6Te`Wr;(A2S>rbDA'Q"5*_'NRf6d5eUWJ2t,sI1>e\N#o/Og6mgZe*6#IEDY!%/gCuIKqjo\P)h`I$!WdpO_fMfqTPjZ/&e[Mub/lt="(`]iSW-ZdV50+Y374Fo0Ok;AY\ZZF_WE7-iUN^Dk6gmWi.pehmpW!\]LZTjfPsKK^oWgO8M\2S)H6HHggt]<)lldKhQS];r\:kjkncoor_=T`FFG7K%7&FNMpiS2'k_02'YqDB;O;$>/1&H/1VtP'd)O!5G).fD;=W*/Oqqi2#@g!Ae:)WTO\`?&;J$!j`FF7@,\=*+X3%3cXR3k*F<-<=,G\O7_0%5l+>#uJYlFcsODsX;0eW3TK1Tn.PJ4M6$4)b.p+Y,Spu6)HD=Z=2in[#C-]+tE1nl`<"WU%oJH3n*+ubcjsFDUf82RcdXqSDRCZ;VcLBYatJt1%;>HW8GpcCW_icOeqq$Hn[DK12>Q;XA'@1(IIn5+E]!!U$7FGgCU6e@r!$[i^8tPI=c(@RjO.ufXaM@\`E6q;S7e4g&$;]\S2u/2UCI"W&SA#)a3B'/<&c4DC0dJOS+_/*OP>j+b&]6+hr:t8AO+Ar-KFcc\=VU&@)>+(:/sTsj[ubg?g^o'"6e=oCg4-UE*dcu)PGhjkj'/V0l[TX<'+QF(8ZHiGnJUSQcCEHnB\`&Nj5,1$p#9hF6Te&D;\D\P.VmK-6rqmuTG""#<1F`A-0V)R*Q+Jeg/A2XmmGA8r+.Kr?\JJnB,I6/ehc4Pq>:H((pl@[%i*XDk#X-8'CVTpZ`b)uHbdf=p+.7_8d.cs7YSWoOMD6'P<$V?$a2#mnd_o:+!'BA/:JWZbk-"%l-.cmF*6UkiG3iZ\HMJS#DhOSHQO"TImZ_0iUG;.AY1i-02DX6V%l5Z&-r8[71_Pl\q'k0idcM-1*@W+.ljo3O6-!.p&MkW+;"sF"ot`=YY%kDqA:Ygfh,0)#BYlqP,2^d6a07.68Yja!k"mJ:V75DJf;pFCJlPXgt^B$#Qn6"n+urmr!)'-4$!#Id'I>\htQsKqWNSM#nW5_&?sO>50nns=/4g7a4c"6O4X"^D!>`uNHh$YNOIH,g(h46Ch.L.D$s)-Yp@P.&oX!I+EALEeGeoTR.C.QS\6_0oI2cuH["gp]-[9RO.G0$Yj'KCS,,TFU1W2$:,g08;4:<$BCFfgoA4N%]i&C`NonN1,[+X7=e`BR-qbrR9iqBH>2m5h?D9@B0oReT'%`+-aphj?bOW,#8jY@i7Z<'AP@hSJiKN+pNBMu`\!;PpEmo0iCKlfO##r:N\(Pk=V,l90QnLRe2m[C,'/\&Cli62m*`K2_fKh3?]Lcjc@H`o.Pe4lbBDl#uf^[^8-ZAQt2]TjoaM8Y'Q?lDW-`1HqR1o@.ojhOS7f57gcfYO>\F[[%`GkJQ3hPI-PN4D#ZOVqpc=u1S;X"]3la6M<&tHDU]hSqgr9A2b[]5aoTPhBZj/Lk&>`HZhnkoZH1RRusThpq"ph0"Wfq@uPtGb56.h3uSoX%'>nakVmCYdV+gRs)Wi,d\5\#-a6rU8;CZh>T?G5I(ET$^(>;eI)%:[YV*rH,jZJmV+!qY_/#b#E$ZA/H5g]8o(;B&`=;;\ETZs?\.V7]33A/F/j?51DN8SB':@arSM+GB]/!S2]lAY1.r;4puJ(3I$I`LKOYJkU7rfls)E(M^_l^2sW`=rha>pR#1`j-g,%M`V@\^*_5e*cOKNLGd!e`Ss`[B&)YTD#1BRcERqhb\nh,.?0"0:a-s:cbmA'<<1!'cPP>JjZl>-@k23G-E4C"&a^FFCn`.lCsMNj4<@K)c0j-&gE%%1D)XpR%H"hUu=UjeG;2XQ/*uCXL>KYM)@K:KV$R4S]60`[UpBfEj$n%XG//Y9D@aPo_rj3@a-H2V4L@Jr8!?G*joHVHISYW`MbIc)78LW(8C8[on=g.>%:E-/9&J.XrLgAXk%JG657)$:0%-cf>Oc39$)aJ8pacOlrKEiUcWB0?:c]p.#[l9c,`r$_.YqL/D!=`BOt8CSX<,Y:%S^"6Rbs2]F./n+usQHo\b:+*YojWrnFE4f=*s$$lAn'+OEsj&&GUJ/!LD[@g+';Hp,-Ru:BJ+JVm_3@G+d+2:O4F%1<;_,BN1;6mtUY:\j0gmL)f2%U`h304Xc(.eGf*N4s2F@3f+#C`"2Z1T!'b,SW'*gKj?j.tcc>YU0nFe5;2$j(h?7&Xnko/0ga6\W!lCs`;.0sITFp$@j;F.1^EqB"l9;A7Je[(:(%6&gd+`m)J(3F2/cS>nu0Eg-si0>MqQf@)"\2T>3=T.BU!N\p.1Nu&8V$"N!AoD4_.p8<\)k_JR;l>+c*'u/.qL0i\NeP`JIFH6.h%&V")V2d+LuQdkR:--M)u*>O8eZB.Fp8O<(=68PU(((H2+b/4^-h:td>P5C',q'XN,Ws58W9eJs3n@!OkK5peW4.jf7s]\_J\O'If!JW&!%U#DbeK\\iHpXTDZA$+/>a?kbKu;0GFELa=0\QSV%ic8QR""+:iPI/^IK3o2;-k/ojt&bjE$*4aP.a8$&>$0jd*#g,sV0dZ:C^U/1:C7.S$n_,TN[F-DU.*ZK0+XSDfD65r5=fE,YLafj)RAtgdA+OkT`*1.KHuUL\PPEC'Xf^#m\mkr?,*A-.m-n_$_=4\8Ja;CXgR,jr0ht%qW5Z20XsS,)*6[=Hn^Y-(FhrC$?cbg1d>"1^iF#`aP,/_#9t.d>q*.riAco6V6n0in.1$Ss"5\%YG@A-Ws.c,iY1niVeW+)S:.igA_2?nm,+f<^8"gH1Un7]IGJA_\'1+f>"?68C.NO=S&gOoI5F,;e&^0Q-hH.@b*/QYWcEZ:jKkJO?Z$8R\EX(?VCmcM=26big6Q-8ilM*),K"jXcmNn%2?;%:E!:rWq/$b[o'*M';U!Y]Sf6>=W^%YL,417bJ"`f*Xchj$L&diTb2PA/N]9H7pF[->uKMhGc6N2]F]\gC$)Y[;UGEAgDRU^H*EL9_HMr,8!FmQ$]k/a0d"Kl&d'KItjFU,(2S'7ujRrRoqo:E6>Q-[l>QKV(SdVnZajg;Y3B)oVkDGnEB#H4LoaWq7(#P"K#aSU+<0K,5n3[eum8&8qY(>ide:##c&\a8'_srZ$JfU7VLja9=S4@9D.&?1/%OY(^BG>l0J%B,`fbqj-Z5!U22r^78dI#i^6tNf7lhei:.J;:_)=Q'q6'&;hOp/YjP;b\fDW#bSeOlN_,<=]g<;F=YH8AGQN>ZT2l-UhFmRWX2Q%jPbm$BO+o$_[mcWHX4g1mU\.^"*ib9`=7XQ!8sK2UiE&k3eOG!9T'@]asGcII0\SEZg-:hQ.#VgDE9&JY&-L2icoc0ih6\]e\Gr%Z=I5`Si4P#k.,%X[HrT^FX5i"4[(QM:UhXJXXuOD."gS+nGH1F>hR/7YtUI/:%@TT,g&c"aK3#%:Er&^5-V)cs(k=KZ#Fm`9*XR;FC-R0U!81Pc":b>&A!3p3gGX-S=V0U$W65<>@%qNJ-/Fh=j[JcOI'Xgrh-?VRqUn*>J1XS@sFqgMeNAn*&2R5GQ#"(DSV3^j'+%Bek7Zm'':WcRd6VW!6h]IrnqelG.+-I;:gfClGMK2ZVfPViY964nS[75;?6/ReonGJlX`0ULqs>b`0YLD6XPKe$G6e\iJm!YCh1$s]f%52mI>pnS;5cdWJi8BL@sU0NZqcQi\"OB-"Fn/7"GQ"$q_0eN_k'Aep>(Sp(Igk4cQ5f,'sjhJt2S0-^r:XRQCDnR\(QJI`f1f8!uL'mA:5ZNiBh7685H5CGltdDacEP>*D"(Wbkt35EW1sHb(-]k7kJ%g&m:r(YlGaQVh->c"5?l;P=@BJi1(^*:Y1h$:p;MV\3,KS$,2gJ>F04hG*g^DCjC5%,#'KE!=MY:YR1*RQB[NPRB&)[QWZ(g6a)OIoB0_q[F_2AO$9\+nomA-On_p#eu9;M@O;r@e2jJ%i`DBYlRZLo!pRH6HL(DiGh."lJ)V(>(3JMRF"$EMAh_f-#A2r4'5h"KLR*a@oe-WgTQMpT`sf/gVT%RB1Gg#M%,%H[4O3l!9cN_/dVE$FLsdNdj@8CBJ_MF(TM_e`/IQ2.Q'&W5@?W*[M"iP5j^)](ZD:]mR^ZH+fX$#-/BTfnGI\#Y%3nI_f8_cQ+j$,;BQ0m[HEH*=S%3+Z=N;gXc8b>@6p_ZUFKe&!g(B%YY(AVWL9cJVb'b8?VUDp_3d'nE3)P9@iILVOPCl@2cN)g3m`!/D&0H%oQfgi(Gh0qRA4(d@Di:_2Z<52$V%mo(bW[$YpPTc;!VK+B6>mg8+9&"3Op0@ZkN#NTW,3&4*h,RsI)seP9#j59p"!'(J=,?"eO.#9M']-[ge5<(u5EogFY@^hqr,'4^Wd17JJg)SY(\DVl^DuH-ATe:sYAM+mU<3rkoCAAZ#j(\GUtGA`9IZL2Ak.hrgNr>$[YTD9#s=57'36;U2'aW;$='WLEuiZ>I&>'`\Pp_la!Dc+^[uBjpq6T)m,pPs?GgeD1"?g&Mu?.#c"hZ.ee3V4D_,1_#fZ,uj7E5H>$nEQCbiT%pfj;:oN++BIEK$aenSWef[C>L9&\D)%RbcP3;6MT&n#&[(h-UZTj['@tH*1%ErBN?+P]2!+hZT\D\a9gckK+s"pbW41rT3\+t.DX:Elj![m*kM!>"H[!=Wlcg)4rk)7>Dmp:Z5AS_>[H*,Z/U[maY"&PcL*%XaIf&(7nH[o7n"^u(;1aUORXBtU^/>kK:SJn[s?L`s5s2rJK$BYZAW4>"/+E]QkZ4Fa!]XDUm]Hm\u[h7TcM&@**#L\2C[F%D?P1Zi/D_8Q]rSP)=#9)&h)Jb@A?koY0OS9!6[o,E;#f]P7'LjfH,t<;DDm?U9$[fnMbs8f.fi-Ajp]j@2Zcar?miGhcOcl:BO>P\EpfpV\RX6*;O2d07&/2]+J9HbDrAn!PEWa5K4_G784PrpKo&$=b&I:i;M\)U36OlKek#be:'-40_N/TDWbnl!D7E2Y\1R#+:1*Fq8Oc+Vkp^+ZddjX[NM3EMf;>k)[i,/#IP'c7,jGLE9d\$=sIa@bFO#"nOm?Di);qV[YjBQ%!k:SHY"JI?)YbD?V`'P$[0ukB[_;1R\eQud3D`mS'-WS5`_u6*t5;k0jpePQ^p6;rbIW#an#JY1BQ5=5K?RSBtYU?bA9pSu!rakr^kP@ISUMfjCeQW')B3M^pA3DIj,fp00Br:q8NTpi=^.^o-9jr"A.k[]3/5I>3\NJ*&sJsc(M0bp1h>D3%2FR%@;^a>PaKWa^<5*Y/O&iE2Qntge\*Y`GrY$jZ]=l)OVRU,([Cd'WbP3&*-':U_59:NTKY&Wcp31!(5Pu.p6AJY@qo[3:gDPC0rE-O,7X-'"qDLE6SWE^_$CK5V!;)db,;2Uk9Q2h.cBNuW[$Rm\-pMaoB]nV;Z_q(MZ4IL;jLY$Z(=`tj,sg_n@-l*"43>6A[h?m'3a+-nH[5I'!JG9VJsbHQY.#[DG'TpjB8g'sI/`T3#t!"[jQJOBg"V7b!%F8hh-RNcE]-R/oX)-h@]J0.##5A+&MqJTnN7I*=+0/:=5+@6d'9U4P7mg^SF;/Nb(qk.2EfS:=&-WWkiWXt=JOG956SN&Nj&cN0[jVepRIVdK3[uW>JIhgMkmQJY\Af-IU*86.n8RPB_X6)tEEqEg]p9gZ%R%P>TK=Npe5%/KG1*0=Tiu5pFX@t?q+OcKHfI))DK(_5Mke5^o.*S,#4H5P7!hk8"SF2im;DOZAbA/m]RW20gC*G'ai2(9sX0/f#ElP^?(G5'X\C'!_S__X!nT!%YnX%GJ>095&L@Ok`dN8LqfgT6I.(*SMYTO`5`cJp^W'C(q+i)=`5C?i64n0@)5B4f548@cLiOFBhmig*KIDHIii%"rR5BZid$'q8OUSu)ADlgj..,4,BQlj^Ng:YG@gIKkFdh@E4ZL)]@HIt@#"YDLL`pIs;_Xc)!SN!m+pS4;lpGDNqF\GkXqnn<@.j?9J@6]fj]/(@")<%?oAC^Z84B$5%&PN`tuS`_(\\kLo[b%eOf,84CjUM-9CZe7u+0/0ttqemsHkm;^s0GFp*kP4:tL53FM3F4NMa:!cod[#=pTV"0`l&q>Te4d2[K10N?aJr0._r!e?;'i0_JfW^\bYTUX85#D@OrmUC!B)ZUeIi^/%qjtK>[CHCG$$]F^'i`O@@;(;@aNW2IO(RC8Om=!IL3R$Z3qo?0rX[V1#M\N+IR:hX#=p6;s_DP=:rLjf=B0jGQ`1?%tJm"b<%lM27?c6D-,ptJDq-cL(bm:KZI33fS%==)fCkqXU#JK?ste%6hsfOaeUTOrl1T9!/Ol#Y109R)^f-fTB;-2_2RZ)TNi#Fh[]LW8J:kTYsqb/JD!A#,:)f%\rb>6B1(N>r)WFpin9E$+,Srl',4=UK1n[jBi.o(7T-!17^e1.,tlX]K-G;%6&DiUK4#3PPBGuW`1=$T?>1n/Z)BpT84[9Y.IJ^Aag0[Sd$!tW\$76u7"<-?-c>9tVLj-HSO!7pC7N"J]_*>2n-ST"`a^Ao,n<]jI0ljTLbn1\:fD!VMi,`%51*M<.kKnT/PL6<#6i0$VS7(cG"M@uV`Q:Qu6-55NgmU1Ks5g#*Qq.aFpL3u[S5s#JPduao6XggDV"6$tdKLe8ZIc;@sagBc-O*R='U<[USkihPIg[0A64Hk;h"DM8;I/"gPi-\8N4Z>]R#8jl2[p=@[oT>jP+,9Th`lh&]Zr^Sk]D$aRWQa(k1rtJ.coph`gf435r280]foW/l%`^sZD']4&9Q^e!RYaMX/kSY#i!kptQr4)3)0.tN?q+Hr>%RbKd&9Wgd)"eZU6uXQXs&UR(\Ut6eL3`j;%I4SVSb(4nP)Q%Jj?*Wb#CAF<"o.=!#s9ZP!'80I'6*N7bWMVqmgkC=3-gAQ4_BFS-^HP<7Y$37HeXQH$hcjq!kV)8rL[5k+t##<*`/Bf,:D#Uk>F+Y3K3*;F.!%s7I,Re/qqZsSF60s1N@1]^lnQ".,VqAS]RQ>38NRHPN[rh7a2qJltK"te4k!HpQ.8s2eR_tt0I*%-!f>C\q?%N;%h>elEUH[^TXQ2Jd>tkaAmr[`e4rqKq'JBPrl93,&Z,.QuU/qD=6XDp205u8`I\W_KW3I&l*X#nuTEJX.LLU<@fTKBW]M+`D7iLY*>O!oG*@]FO=M+D)Y.EemK%l8]2l%+_Z/C%.T77Y_gi;-UYN>"ec1T]Y2sAtYhj.LKTVrD?pBh>JX;2Z<)mu+S79'4Bi@4Un@/Qptb26XYC7a+Fl7=&baF2N`-U2hAf;1L?h.,=a&Lo$.UbE9%#]BD"j"At*4oO?O]t:J)$*'XX,2(jX;8b@!`?RoJUpO5`1"iR8aDH^n@72>%kW%F*ZpV&:%FJ8!hKf:%Vfi']Yp&%7KD"[.O7Yb7F4gAt?,SX:jUOmfhF-kC1jUJYLQnRF\tV@+9sSQqI*Y/oo)gf53!#-K)4SOKaFU#J,sN&n'_+#=-u"a:^aVR3EFfX'j7,:hhd;a$[1(V.bf@eCP86D[*uMU@MDTeWrc(QY-LJ:R#-ClEj6[jSq#;<$j973g7e,4JO_!?nh)=Memf!a+q:n3.hLA^s(+CkYl]FsI%d!9,W0KJAm?I\D7!tUUl>67f>?#T;?jVM4mn[Ct?g1A%i28@2Hh_LZnT"H>o5^;jT#\M-$Gq,?qSj)'kfHG!L[?hEG>haW41X5//-uM9%"M:O+(@8<\\;GR/m(RV,48pre3A$^\cTZ#n7h$;Z7$kC>C>f(*T3;"@<+09F"3^hdj*I2g19AeQM"V:gL+OmP:'8cXRnKUEZQ+Lj#4*Y;ugnYF;H$qZo37hoj3ld##ns'`t>Z1m/H)b/+n6'k8+jE)?;>=Hg],6&hNC_-fRL,J<&G]F3?6Ad\A?!WDkUBEm\lkt_X3LRY_u,Oj5RE6rS-JA.09W]2a"N&Oi>e.0N3lT^-q_01;Tr?qf%R@p>-8?O#f*u"=KBs$HP:ZBe1o8-;*6+W/@(a:7p2o-Gb&d$Mr/f$k_Jm8JudL:p_KHc[\NX-@3$j6_^q.U3Z'dNpF9\C&?EZ(Rp:V*M-&.D&S<,@(#6mf8L(bt*bp&Ak-hn7bal,:)7U9(5ONR#XHQDP-DOD\r8_h!RnK.2Ie>O)ecS_9,mcNH.rL>3$OaCT>SS2\"WHnH4BJbcj:.@&!dAn]o\cbopX3/WTnfSuM>\1%>K&:mA;8dF#gWjoq0`j?hpOc8ENHOo*-`SQt,9pXD?s=$Wr\en7T`<*PlgT[0lNcT(0n<^[PQtsfUGAf,Je+jl=CB!^D9usTDEh:-hLu8o#slg+(hFDUpm:!$#pj>L[U?.LVEHm/+PGOp!f'/;gDP,-6Y,G(T6/E\FPmJRX'FGN@SAT+@jg@6M0rYM6L%]r-hl?B3f/ct5B'\N"j1C:KbiWk;a;A'U07d7XN,Ve8Nm;4+I[IU1f(Ygt51PV#19qBV*hNAt[lBd(C@*IJ9P^A@an)=+J\[>?PQehK3Dr8!NaWbb9G(DnIU/R4GB*&C/Y&ONeG9:X*"!&+&MDkhs`(`_fQkt>o:!)>I5B0cq7;Cp44(1[FORLC4U.7LH&87!cs&2UAX&;!Zqt?(fdq1]YPJ]da%h<8<_DPL`4teemqoI0UK$6C3V(;a(K"@hD#pFdCOf0ND'h3\f**c8!]!q4g_pU)W5K&oe)s%s!bhU@8rd,UP?+04b?"t9&T=EHp@;ioP3d*nA4d=k$`SGa]W;c551G450DtQk.7B]\%j])Ut4DsIgiCR,+T&QK5s4HaHp2o`6hb<>3"=BNK^*gnWoh!_U>YubUVC-YApJi2RN@&=5UikYmY0^Z'qc%[.G,Wge:E@oJIIU[c7/4BjOu721^,fq4Zbjdk^FD*@>u;aRLSQ,WA[t5FYIQdMO3Haf8Qu-OPH9WY*GULs9GaQs@)?6?e.E7\;m`ICed%)1+S5,L&kh?L=7,&IrY0Q5e+*Nf^#[*A1Ss)/'N]P$D\$_`@gPaRN'=_J47J=&_lAKT!e]U_UBV@>[@5_c8"#i@_;PZ.Qeq-LLIT.nS12.&_-N'nM%Me.dG%MD?>#a'jmaj?N9OhWQf;ApD#NpI(Y8g)iGfBKBcC5Ca#WUC#LQeopi_nNG;7==KB$$R6g.>.V+F(M4M&9s@U=o7dO4R@9G'-\qZL^$rLkKh@-?e)R*`DXb[R8j^&EFqI>GMnO8_'l7R/;pa#fP9ROt9hof>T*-5hXSSEYkrb5f%!QCp-`eFLYDhQVV<.LpP&s;./,%R@aQfR'lp)1o_3r^*e7E21_\XV$='B5f,j:[%hM/uQ;&rpjG@+=rMDJXnQrDL5[-3$-9c8g:&u4(J]5P66G+g?@Xupr4"!a,_c?74QLKq,>l^+'rc/PIP5jq-94*lJ3o>%*1H3&HaT""2QtE"+uMER[OJ62#hee;($X'k%48k;c<7''FP8$-dffmN`8Z#ck)C#2g'0!",K+0](oM5^)4Cd!7\Uo&gX)clS=ia[r:S:@!#V9\crJni`hQ$Xj*oc4JSlI8MCI:n(I2+Oa&8b4K54[aMh5rj?uFe^e1>M44\331W\0[061O$9JrZP%!c"mYHro'R,6U[N50`ZJs-m+@gdS,W#B6?CDh>$^L*n#CHthVUeP&hPJ]!M_=?e&+TVeU#M(pcS4N%tur,aq>gWY[rLL>gL8U.=)hH9V)a]81>ZpSKs_$H]Lo+3j-&IG0Dag[X3:27UpnZstF?Rf,8OVPskoHOngED)T,kOH$5WGCI%Qre:BPEQEZJ1C_@$*JTfUpdYHHmZVu"1I,pV(<";0@+,0LAL(eNEsV5Ip^&Vnk[dZ%KS_nKQmumP885@1r;1cP(&)>:3Na$e()BUfT\1nD@D&d#bF&8['J$]433b:ufg5ip9Hnp/3lA&!$7RoNHm&BBns"gj6,S#G!I+R=.4'g/^XDQC8L8pAhEhlAfPqDJ"^2J-pZUOH#/#^!=MQkb#:>5P5;9WWJZH,(a;Z.E##uGL]`$+SGoF"!oB%[9IM.o-:BI\"*X">q2^&jd4&SVKbgS/g-Dh:3OJdRo?KjgI`RD+6grJB/.U65V0c.--PAd(!H/mN8pBl^k!QA))%rF-Aa1;(C$@F#A,E(R[Nm"$+G-1,BocbhQUW(BEeNP3)lUqhGcH6<7_S*Yo]L$K`k%9u7Rn-+P*hlSY,6KAKmOT,::9o7U\F4:8RN&1$';`IG_?8m40STf:<)F9qSn8Ilq+3.>bsHS[W)Lj^@-0l##^BgG4Lt;'kiqIj_d[(df313"o\X#B[i2=,lE?0:`uO&WS4SefP<4f7$60r+7C@*W@?%#f3;$QXD_=`*EZX[4eP"#/$_hKSgk+jboFE#u/.kPmS[(#'1CjZIK0V,\cA?ZN%HA4qp(U:88tn[c-[OpPM+s9K-jP!=3TO0sS`Qg%JMf@oZ[XTaM'lFo,XOYX7s\uhUS2mWS!I@:8"Et+lIjE.K7#T#c3\(A&9f%'Qc+V<-BEH?q"FEP-eYq/mb,&'PjVdm,_74IM=t5,Gd5)3\OqW3Bc'3,hIYe?9%n13W0TN>68TY5^Qf"he2W88U#0Jn!8IoRM@q&!YXSaSl?3MFBos6oGWRY1b^5;/L`D&1_?B+s#fP9`%8Q!FA/q,gLp#omDA,u1HCB\B*8Pjp,F-=l-F](f9VU3t\[&WeUW?R@B+;>+l@Wtri7EfGGbY;^h^^Bj)F.ji*F3cig/85>1,"%#n'$>si@9s'##+Qp):GWK9S6o[0hg5W,6@9g@53_mAJ%aZVThV>KXF,Z5aZU&PE`5o7+A#lK.%E(9>pUDta/?nTeYm:mu%S1-/fo]A@^sSb7k%JSMa@PpaYHR*`;1:.^dhbK0&Vh2s]ChJ.P3te7Q-f*[3Ltc@k0SKcM.>nu@r4"e:[r.,T.`mehH\%<45E&Y2k\-e0)@lJBc;).#\(G45F&siMUFS(oiWpA'SV9M[)!u0$j(V^<8g.TU$-d(+f2!.^jGs'8"ih@*8-g//Mgk#@Vk4>Tr]@mG8ZQ\"dic#TJ$r'RBSOr;K<&r3%XiLd.8.#Q\:tP!0d]e3BQ=8-<&m#b_p'oq8H`L*Zj>q2*R;r]Ho&WsU0Kg=LiG7J1R"=R$Tqok'in:T6O;oLV)_gOE.%rN^_6\cd"N/S,n8&XALFj4P>iP!BF<1[7O?1>?'[^FH6?%X;@Ilog0o.]b2*"GBK(.:6R-UPbjgD[dRS.]:%O?fH:=]l-_7s])&0W*'7Y$Qb&_5fMNpquVUSq52K@UHaSnHgM3ic`o*BM1qgm!OfEC"[TS1#pO@Ap1?e$$o4M#99p[^>rcG@DMu<$?-QMiAj%_&>4gAmNP]gJ@rI]=\a`F+XbT9c%+gU#@op"aJfT%q,X'qE\a#[+Tt)>&:a^D>k.5t^iUm0N"63IjHXC7@,]CP1FNsc-0M5H?aThfeA:(reh!s"7f5=pDI\*,,I3X0WS1bMrgk^S\6:Csf-M\Cg;IC\6J]ECE83i,7kB^@BKI*17`aKum=DHbFEK2"D+etd;dEi]Q#4"#%hb)*6h7`BnCf'4KA(>LRDc;M7CotPcgs?:`0`jk3ILbUb9A'HToCp^&bLWR(cBY\T3cREP>shfH9boo4Ddj9tg`DAG0r@'(Eq#%C"WO!NG9!&3"I3T$-%gNC@Gl%el5gs*K`:fK^r!;0keZXX!7f6D.e'&+%T):.$MP8B<6iU"^AlKb&gZd3A`6IBfn#bO)XF%V$i!V@n\=N.E2T,_6e`CP@>42tGAG'Ktga!:d:!40ucF*#oJ#E+EVTO[1l[ltY4e(;6aFs-`chfUVq]GR;>u`W1PIL'p.PA]2A#e)T_tPu%j7TgX45*:HVT.q%%f@Tk?C2<&9eW'*!W0<9Hl_\c*JI`d7TfdY'[n]G(DD:?KdE.%.>[Gi"9d:1LVF^Q^!c33JnGGYCaUThIL'?s:YFbX?n3@fXM?Po.Dn#/Hk^_%goS$Gf9!;L"D2(F0oX)I%eYr\T.O\HlN[O=/.:_K'#;INe+9hD]5F#]LMAb/#VhE-!aiinQMej_.uIY)d&kKCc5!EZ*fK.KI!E=-*Z/L%JYUp[\=e[31]&"lkm/3!nV&K^K].Ob-JdQlgEH*:j!_L?i.fU125(chu5dU"%cU.E+^F=\BK!X)1FbTM@e8K1V;Gho9mGCPK;?'7Lh^/u'Eko5>rfE_%897[A?BOVF5/nAQbi,Zn6r.AECmiig?KI9XeOOVWI6/MhQM=@rV/Y]3YYTjWM5[boPghmC+-I?KfK(>%1YGbIH/4.>0"]LR\(a8"mo@d^9'-qW*#XT,:YmE[Ar+GMior5LW."R2L(r".UqYdu')[TC4%B'>]#pPN\8I7K*[9>(Me4N$4,Y4CD;FEF:+@uj7:f9SN!^LTg8Z>ui^lI!^7"E=Gmk0+.:*`m0(tLAFV@-#5@?>djT3iRRMNV:]\mCU%Z%doEU7NP/m#'1I*Tn@jLl`_]0N/<,>X6VM5W'atD$a[f]>&fLn)Qb?!^Zr#J>eS>heN`U/-hmsK?jsTEuglul[E6UEU\!`Y`_r(Z9XC#*UjC;b(IM#4(au#+qA>TEa[*M[hZNG1Nlr*@g7m%"r!T3lU_T5R[jBhIQ3p_D&(`5*sh*bGMI8s-R:G=+.IIn+^$->$^-,331]&\ILgH_p'=$[+no-F/*@K7+B1sb"Gj3GVn>SO?M.%hL9t'`?[]!HDl0CF5TiNc&VNZfla2;]0H'rC^\*USA067j^Gr`/)]_a,pUp2=TFVD%*R&u#,*F\b&h&11)Oq:4[[29eKVUu(J6%5c5r(<\/.T,JbBW'd-p\X;)SHaWfm0s*YnS[WCYb^K3/tqpcG;u8r(cJIqrDQEaXFuKF!\_JWfG5(i"RE;,Ca%A`b!*It+,"WE;+sFg7pg,VmlTgRrmC,_D_+4o,AINp^fSBSZ'HF*g)HGJ!Tu^/*Prpib#>Op?(pH;9'l?b2Aj1i.s_*AfX_8?]"(V)/]V6ae"@PEo9VG/B8:3KR-5Lqhe=8;K^uK`Jm*1BsSVpq(0\59`K]n.>^)&VO9k7$&25Yn&BF?'eFi&kBMDK"db.:@X1E,s)qQMa4^mHP\g3_2g.S)7&L[G];ql'$79CG1KQ%MlsnN0MO.LTp]=7bfs4?+<:^-Z)6ZDt[tOt\)569p)&+:O'W"V4pX.'\SI2t*q:r!?:Fh.#o30ns>qE6lB8n2I=dlSa:Qk;uWg1d@:O2]8Zah3r$GAoUA8S5..K^_m:scm)4LLLOF;f_mGk.EE=2A3h!$*(0fl@RJ9?FWRuB6Uom=#de`s>:E[/NmhF,=A_AdLKTQ?4+873?&/:["8`3'_Q%q[@"g)$]\ctLk-@HHi0+mE+-pQ[XLdbZYNo90heLP9;6B[K8kQXuF)A'X>.I^/=5R?aOILH&#:'3''M"V0itp=[h1T0=N[7#DWPKcl?6t/]5Q;.[VE;)m8@cRU3e_oU[1]`l7U"Y!e!Z,KSXWqDlJ-YenY9rAJ%dBQq!!Wm#@lP^mnP3g[4Y:/X6Gn.C09HLUXn(,YffT[8^/'Dn(e8Qln2n(;@+kL'MO"Nt:MT*Y$[Q=t[A+CO/n)sc]FUK0m$8pC$68fCl']FI=kITejDpu&S=\DG^&eNQpd$q$R43K$!)W8_tL9mc(I\@X[8:]'B7gIDM3L_EpgM+gM4/^>F-;Gd!0j/uj5M+\bDN,^c)"U/?NYNX8VDjS]+:'apZ%c9XFjf(%sc_E5[*s&a"d!Co@j,_Y<$d/bUfNC##K4Q=a6`FWWAj>,@r-JGN"SH]nQuO.rS5Yl\k#2cAHpa!7r$rJPUeu5fZiX"(A#+n51os,70gXH?ikc"hYZ2l(7,TmYWLdEb\e/%:t0=ehO[hju`8^QZCi1-$R"1gTM_]Y`nemP6u98NJ)fN*9#NYl1S1r:.4I(,eD^t2ghKtH=N"=0M?M&V$D:g+efJ`K$tdGXSstNi@)2l9LJr7=S8&40pXe/RH"qCQC&m6)'%,@740eQnp+f;QM%MXh^$\2ui6San-CAmlqDY/nVj>!$FkGM99T(*kR7"4&=FnBtJsuQ!iO\'q65'!5+hMu"_RVt2@9Oh;NMI9lDQ"tNaZ^qBQ=EJo56f8"bN^M-Nm8Z5:[[Q?6Z6H6fWf>-uURJ@_o9jN[-nB)5iVE[aubLY3$ut`I.6@a-@Lipa.`&OCSL#^UH]\[M?XM@.-JF3]_7Wlc6L\"8O,a'K#&k52X<_,\MgSF3-=7+"dGa+B7dHoJC"$hT%CGm0]$d908,hFb4fff2&d+L;P`ktK+6,R&Z+&5=Y0IC4fq[&\#C!t"18<'VkPiD8p=u#I=`eE&N9Uke*kKGjpJ9(-?Fo0T[Y0Ai:l`h]I+-.2815R3<8HPo!#"_7n-][%srtL5g+J%_We5(h$Ic/\dS8hjX<<5@0QX7pa2(Bl&;.Pf+b>6gY]GVbOgD;BT)jcQ8\lUajoD6*kiN3R@D]7`>Eq"p.?9>XVK(gFRY,<#h9MRnNO*+Qg?sr0aT`n5"td[3/Qr-K>$rrlkHL#HNi17b(q!?:lje#sC>2WG[3LWt_Ea7rE_)\dr(jX:fZBQ!oYaHaOTM)kLtaijH#s&L/nW$+RUCgS.O69m(4!p.#ognB5bF(H25q8YJE>g'MMKOY)9oJ!uVYd+b*:GNG0#Xs@enXZ:KFPhB#QIZ0a(ASX`7a<@7(rd`gn1%p6`9C7B#Jfh[M(s+9Q5`f^N,7sF?eJ:T@*ifpdhkU@AV4LA&`8H>@S-m&Fl/0Hgn.jhbG_IK&\uFRD]0e.on6XfmVTiqc3c:p@>ar2lV#B;fJm=UOV$]37#E&Zi*oY-#,rjS)O24u'Df#\>'J"I"]pmh`EV?.4Z6kbg5Tn(W7>=_5ojLfg@-^)lS>l[.:Bh&foI?OYZ,"fP;cpakN?=af>8e6$^6Ab9CI9Y'T$s0&@f9>/LZC%i6'&U:p%PLl=./`qC'4*Kh\(#Ak)f"'jQW0hfUkB#br^2(&NFJf7[+PT+p];%b^p#7U\;(i%B1[tSuOHG_/'`\*$5J.1Ii8t"@"A;l7#qlC;GWP0)5D;\c]rImE$jao>*`T8[0Zl3b!a9Oaln60tU/.TnK@k)/EGi6T\Jf9SPU`@t+\4N4Q4qlIH41Y\n"racR^Km7^H>4Z*qP=&ZK31l@hJ&Hd$ckljCcgEA/^)OdBeG1YQn>7=0Nn\_S$j7HS#M&K&As_-qAR(\:@9#=rZ4AL$V/&ESVg$q(59f3"G@"H!:ij)%@tN;=q1d_$pujo*PoCm=a\q*/CLE0Q-scfBoVE4[FBik65E4jQ8j<83rV6%>^Rb)`1c%XiC/E0]f*t6bD_27d0b*/^(O0f2H<(eYmD]p+[H,97O`A1LE9IEE8UkD(;3l/\qSG!KIgM*bI6`GG6J2==[M)G&2Zp+m#Z9r:.EueW,DKBkG`G]!6::!"qtr^rZ;i,#`t!u8AI"6=m%>DE:`pLf[7ep)qm@rqOhf$Qurt1ICNZcDD5g=r<(UO!J&08O]4s:V1#JsC2;B5:)U3KRP+CZ__(n.:Z>34>Lo%-$0YW#m+L`<@NfP7F_8T9coCb@m6X-!p,l8Nr$JR`XX0pAZ*_Tj@'WcWD&.&fDOD]E`AJp_"BnuC9iR+HfWr>ERk]_2<68WNAi!@Zc'ouT!`5@bEan51$Q"^^Y13o[P"1N6TV.Z)/W[/==V;J!=QmP;-L7Kj"S@g#6+r_J,7!FgNJoQ&&-bj>"YhE<&'fMqUbFm&7@G`"X<\Zm$&3qcWajl3+@cr@LPFD`fl6$H+Tq\.]&;?\crK:@5U'Faib\?+5\iIZ*a=->I/4+G#qk/LK-!8Hkk_<+_7@9hC]4X6@hc#7Ceoo&\n\]_Ztt>D:=Rk/!!gfYM*La>=3Ebga7A"#mG/L0E'93<)e!\KLPMTuZFEa.pQ%dG_k)?@!F;?_jssa?EjZC%*\XZ+ArXboUK$NUTm+n+:Im`h+3%p1>g%D.XWuTR8B<"p8CG<$en1+DBc'`2hOPMjE:8lo;=)\iZEBRFY`8c]T9^;VR,ptX:@uAg;Dij0V_<\)c>rn>"Tm$;8"rT"!-N7rQFcpomPX>8j46l?/LTcLr=1r(DS!(S406:BCOTHa50t=nJiAq%(t1LNO]pRRj=6DOb?1q1W_S."?(?e9e:#NVB7SNBa*Y29pBBA`s9U!(=k&0KAY$sCmtioZ8*]Sf<+>qI:E"0$VcQi)Pp&Y&H!9&d8QAoGs"^&Y<6^^2]NNOHdcLmY5QZKX8I]eAmqdF@G*=<3;6VpQS*>UlNU&][oAfO"fVe:UTu$IdYj-Z$Hd@9d1EmA8eQfB?r2\c0d)\q_gsQcm&TNKYT1Bn(`-+(8NkM7I#XT*S%a4e&Cgc+FHlVfU?k&*o!iEuHU1=hH![H\ie$ki$UBGmZV0cbR,15sr+?!M^:I?c@FS5hX$2fi]9%jY2BWU&J.#N==WkY!=CI[eFMMHBe2`SI\pOeqcCi&T21oHuUgL&]WDUL@"o2BcA%@\RS8`_O5WbY$fXi<9^u;PN2OUo,]8TU^+V]RGeAgFfg;X_:6oQ+,X%2_p9fTtoRm$P?&qOI-%^U@dZsth@eJX698i5H"P;ts3^s:]7'[:6fp;g2W;;*!jjqYLb>%EM(D]F8K/R;Mc6Z$AYV3utAR?)a'i>YYZNajkEF/3c:Dl)UrGtT.CnHC1&iKbmg@&>-uMnOMQqu@O!a)q-l`;-IS#5i*1e\B(MU@1l@0[HdLkI%c&C)IJ6Ji#/1!`W,)GJ1O_n\]5F<-r[kIjN+*4)glcYB;n5E*72'D6Z1=ZVJ.kHU'CdqRQ;o9k4BW0R^sW1NRqn2leWDn:aACT\p--Og0hX;s=;&(!VmGi'/2rGB`4(+]l&3Z,8/B\YM)#U1/<@l"tTh.MUlh]6$*.56r/gcK'dQLYD(R,D(V?)&<-r?k'M4Q8[;T^5tVHo0WAGLS3Uq*=J;l4/GHh+2;W!ShR>la1[ZUN$e"e)hGKh$jgj\NGU^P_q2jR2AsQ0fiNNRr;_k`*VX:g.#21i%YXS1bOC^,9W`c%rn!rf2HT<.W16eL='-T-&O$mZEW%Qe=8C"D'm,]EH)%kK[#0gPpFXMEBV36X6==Gg,2#3N3p#g@T=d87PO!MTbJ[WEDr%%MB6hp850As-k7_=dZcQL1Ot$_LSYG3"6c,iYuRZKBW7%,gs8?gig(e1NfVTT5?b5$ApeP]_KqQ^]p^uH<+&7#iRX4+&NHJK4ET]1Z]"".gLB3!Ai?DHo*7Zr8I!2i8ePu"6LJ25#'%jqRB);>=FQ+2fq94&)4.gYOVISJ@kR)D2*WqNYm5iJL>!o1#:Q7BQq>;<7>i,m_ie;ABsMR9AJ5bpL90[u\otTT[dl1lXh]%BZk&jKV"&QQ%bXCN71!BR2XJH&(D,,VUJ4UTZP?DdbfJLkBbE%$/Ucf:[DPJUdE=N0XM-h-1POMPD[t*p1GNdD[GAiB'P5(%E>Zjdc`_a;gtS"2c)sLn__2^fVKC4^21]`(+]_Z&C9n*crPb+Oc*J:Q8KAg1%NM4`(q4&8INp@oG0si2'CN2(Y,2"8tK72rCKn1,->Q8i#R54]L;A:hf78t?U61Jk%\kbWu",m'dUEADXdpMLC4cs#Pb.!cpbT0T@>bD]K/l=Op&d@>4s*nX$D@SNF^5mB0!ad(uoBZH)"^qEr])*$'.ON*Ci>YIjMPACW@&p$dTZ8NIMW2Z4#L7X8oU!F`n<[bkV5o/Q@8W'!,)i>j)*(?Z.!bc?f=TdSI8tt,$%T&PcLkq>%5s0.N:PDJ$@07@+;Dhil;=;L72?VH4@9VWZ%;!LG':4KBWE*#%@,N.uCbZVMQ7g>c7AeHP6:muT)bq97YAKdKd&*R1`%qL@@@a81as54A]'B8WD0;Wt<.Iq8A]4[X:E+o5&n9r-%WQ1M43q3@`dt?P`56B[@],e^U5"HR1N3oNr@(`\XHhU0Kabh1BB?pQn!hT^aCU0G)Sn8Ud2hh7[;;0K`IT738Z%]___MN0h5uE^(gth/qMdbAoc%EGNA/mbDMaIQKH]:)+e:dF;@m>TjGfFm,C;3\IOq6cY>L/hb[_U7;%:7C/-3I0Jg23Hb>X0L=Ae=kE:2u/%>+nH+)HbjP0,B/Ct9%Cd"SWb4<[3"LXXA+\CBsudF+NN1Ia;K5eR&(M_Qtd1q7>PSBUs=]ooU&k0qbWV)>S3..>20tW,^)kOCNMG'TQ&&[9O7rI#fLd:,*GYKDG\FZ%Vg78_uoc=_8B8ofJ(.2)Q&HCD7'Vf:8jY=_;6F_1h;e^DnPJ?$?!=b1gm7J0UW=nnQ"%60!bDOM5oP&E1n\"$`3JFAELE?fd9CM';6a'Oe*GlV;g6Ki?B[nFbk*QVHFo/`!n]siJ',DS!H(Wl)jEhOs,?9WRn=)bnUJj[\5c1)*BIIM%1];fi]"M*t$^A;j#L"T9]^uR(4V0'Y]#rkhNfs<(*s)lejHegmP-URFnY4$aO2U*RG([glg;LdNcG=rV%"o-Uju_s"n/9+!+0EK6&1iIAP=#L:l6)60#7R]+D(e71l`&2BVkdD&]G7l.!=9%pfdH4Z2bM*1OO+jNNV#7)ei^";rpQ[6(FXt^cA-e#)'5g_"S']2XSs?<1I-C,arY7RjOg=%V*J8Yqn1hd4ur>6Z?OgQubUhOMGC=88-^J&eYdok&;GA^b?Y.PB4CdOO_apPj*9`"bJdPOHNF_#3.>9mPqSCN!#iKO:JfHYh:@k.Z(C.`<0M`5dVP"1J6AqoccW'8?$P"EWGn"Lo,U=M$YHa5`em.#jj;_;gPIN+BX3UaBK2?.q[&`6A`(*3+DWVPS19a,`P\'@fe?A;CQRI$:a+dYbFESo?BPDFCjeM]SuZ<+D^L@R1-k%?NkZ<&Tu0U7.?*PJK[=%#dsLm6_0[ih[&_6l(Doi(oq864/*;$7G@LaB_.h7bF)3.j_'.b'",\2`*!(nKE.9,rien3Ecr-\<5)nLXjHlDnaicHLjfZjra4,T*1p$'\S`e8d[i,t\a=r5P7fl3g1-gsSA[aPB\][IFZF__NQBGs774:MLl-:Aq?%d:^REo'&.>nVJ=,PRp-SAfWe-C]2g%d@Ks(A,XD[5P`M"QKlqt8$O>iSJ6(Y.QmHea=B\OmOpuukc3S:J$/l'PSWG*h+\.?^p06FE>i[:iKTUu$^eJUG"KJ\Z58Po@/qpQV0t-k:bG*VN>Uf>D.T\=OLWif\.@HcaOF6piN.]`G\VEbG>?$<9^LPhnp@(OO>;"(s/']N-&qe<]I/q;4u*fVCHApXTm#Z72aLKg>mm+YfDg:`f5H5;;;hD7_m"QGjdAFGG;q=j^'uO;SoB`JVYGqRr,NCihK$4rSo>N*8c2/\T`."DWq*B.NTFA6_'*d!YL(jLAKIRYVe(l"3tTW:>NAW5SJF'?sgna*;ejH*KL9Gn8)&j$leB?)'DIeF_"_lsuWD[17H&Wc&K40=?iuj(b@!-@o(60=W:#clhEQ9If_M!SrJhX#TMfmZ4mR'h6Ht[/eJ$@=n>VMgSO?#\S?+Z/_!=1?3#mgrql9m`^Ys,$R.@Ck4#<++CF,K<26>EAec@kj_Cg>c(^u%:^G;no[+&WN5L?W`c(Mci:D&C>b"AU&I:rrim@p7HaHt[7=%?3hN%L[1"4C`\*@b(p#K^DW)bKECblDnp+<+4UI%rC9+NJu/VRP&93)i0BK\C4M].[JA@B6>QV9'+9/F[iUWTVGB5S/umPMpaX4]bo1Bk1Y^3&eQ@oJ_g&4bHn0>QY-de\nL(qq]V9@@h$'DcJ'7QCpql!EL)_R%ZNNLMAgpYlAoOB\[*l/[$6F6=<3l]jLcEi*"k3KQ=7?XbqR-jCOE7*5*G8B)Vdb)YZW#:5\=@2VQ5Rq41\:ARZgurU_)?Y6cZ^*#iC^?Hs6'S=dG?:Ab5@2%u[;hsQBU%9&,d`f3Y/T,,S[Vh,4P,S*GdMKWN"H\EUhiHB*Adj8(.3bjG#XT)Z+V0(4k@8I=H0>7EX-^m-=`!H"6nXRY&4mS0<)`Y^W?%@(0N5LV-m_YO3`gWr&Jbtn[W[F'kC_Bo_/)o*F0I29i7&4s%_c$Sa:T$NM9FI=kOP??8gU-$7M^i4EsocgOQ$o7l"qRhKS]SucN2)MjU9o%,ib`RNUj@q_9bQu'cEZ@d>4N;kcYq=?G_$s/eDG$W3>Lc/[#tVX[[UuFoN"4..d7Y@?7Qo`Mg)#RAcX`&Q_%1*>"Kr:L2=K?fKA>[%4!m(F0kna/B@75!%846u[)T`;oe(NBumG4g:P*N@1Z;!3Zh/6t1VV3K$,?&H99Tp*$>=P)oTP:]pQ'G9(DH4Sg>0T^p]#Mmh'5I=,G,@kIaXpu,'iF>]TkjBA?%%'*A6GeK1q&TGCMMNW7BPgd&diAfV3p"_kFO.oUk2WM/Z?'/WF\Y.412*EWgTZ8B!jIo8m/3+j/\`JZ5Y@&b>lZ`7BXn`?/I2+L$rX+k$Nq-6e%R_ul0mY,[6S[=2n1!&,Z!fHS#V$UWQaWL>>,`g&-F;sgWfC:Z[T[^0);eu6$dMt=(3/Qodga:VZBFlM.WN)nI9c)maF7ApCuAjj]9fI5^[fb"?Ak&5l83r8K?,`9MW@>l#:g$#k[ShS6sR+B^b)q_c;PHQcO8%PYiot1Wn]cP%D".;#0!6SS*eMdK6UO@lNKBd2/QPB_'3:D:Bco<,a^("p?M3.hWab">W6b+O[")_s"7@n3bVG2_mDGKe;+_Jn\JFB:RBT!Q5U?6'4"),RiZt9sMY.:#]aC;u6h7HSTTFHNV$LA2aZZS&C?B0NbP.cr"+(9bWun?UkVi@jbeK,'o:R>7H[@p1R[8MMiK!#Ya,1"`=L-e>#QhJl%+D'aFX]qj1PKe*Va=")Ce#i"D!;F@V@c=oe0J.ep*$d3GMrhcKhhl=R],iEn$Y;F&B6kkuE1AJ"nun2;$q#nXKN$W%s%iK0#oOfZ>U0gg\\48QWr7d6?7ho+e'iAOXU'Q<6(cC*N,6n?6Vu;U#+2dF=r>+5UAKdR4EkIXRaX`W`WEuV2+Ck=!O7cV[B92U`5\.(n1-DsBTU[9s&oHXGV4?gf/ZK1\\WX?8^RMajTTg`1+#h[;nt1;OX_Tdj#GBUZFk2L>?d+IaWuAWG`*&i`)H/bpmT*@:@LN2#Z7!tV(;ei\F3,:Q_dB3#I$@a;#+EHpCU9sPRf8R<8.q%0u)(V!pdqRoNs1gV1*UT"'cO.R*LRoiG;f>;r6E1.+g'nV/"hJmrCK-9MT/GRFiJmDMt"([Q4;EqYrr:JD[=hL>TQ[BcgN4AP-R)s5DT`n`UK1'*'mk,jYI2]qf.2&o0/m%mnAVg\XQ+](EnK"u\U8a=lqN7&^oEmj>7h+H8?Bj_,;jO@!p[5]d0q\,0@jq_S2d1d;TeFf^^#T5g1ZW.eLAX@(ghe&0<:uQ:gIKcI06Fc/`j$;gQcQ'@![;]4-Y^uX+<#83LL!OeCbT=.#@<3oo4h3#,Vc;&>'cA5j+@+)c1oP7p[?'mj>q2eS$>G60u5i(p$k2XTAL.0aN%5%Vt4mROP`G88>%F'P?UjA1&L$nVMXi<92B<-L^2p[)f_$8D':0#NC[QYEEREhNo6%;,cE8:XMjd?O^rqrC#gnQ/u&=[5(TpC?3Z-mZSnEFNf7bY[_[O8#1@,J"h&VI,2ZmaZ:J!/p:"r$Y/u4I+fqidlbVqMKPfDHG_e'?`5E(GOfg!7,VBhrnh/?>],dH5,%"KFcd/."cQZ'G[_6478L,REIs59n9d>,YC4eki/p'qWp?,s%b6\=XKMipJRpB=h]um1?e6<\^ZrI6k+p+io>q:l/saY?STm]=$3Dem7(AH03p];3k-4hHS6L$^K.N;bE7>.PcYaa&iEY+>mgf."h0n-lW_CE;G?=gd28C[,t@!;?XhVENE7^pS[Dh+]pjInlmcW!h_03<>cLG$9hi"#"O26:\"kk8r9US#eJlLXbW@XBW@CGRehOC]'4]*V(1U1Z0LYWA]1Oe[5V.c7'S'"6$s\s!<,iRn6DS(Y&;-N`BOS]Qie;=kVX8:@YX&A(!K)D"]:eG.^=_,^M=b!TC1b93&2+'QLepp85_d2Xd'N'2q39EOn"&2H6,fe0283<&;M0ZJ,8coGIeo'7)mo5QP9slU!->N$=7\MZ[n8LZ+7sj)D!"SHS1=RM(Df@3Hm_ORro=-SYP$`2gOeFm16Ur]Q3tU5]^hME@'f+@ZtX2cFCi:TiSpk+aq9-jYn<%YgWHF;23-5[9rD3W(r<$u?*C9\]UYa2AbZt3#OXS>JE@LS3,$k\=0Ah67Bg?mKC`9aYs@IHlS[d"A&64Up-uZmOGele1D6KdKke1]$VZ6[Rh,)_mg/hl'WV(D`IkO_k9Fep_Q*;m;:Gh-B&lLCp#'6Wh?G0XjWSXoh*W$T/>;F(Il6Se0s*kB-EZb[inC6"I1G^,g@:o4-#"5AZ9q^n3;-e!'W.1?N:uY"*+GdkCT8?6pNtY:f7m+`/5lB8Ei0K._J3RBL(c*gi.QkYZ)7R7hS-)4@%-+6@n3<:Z1Zrs/(`fe**m%&iEbQ4lqlhJ^D1m3VQjXcO%dopJ;Y![ao]!";\J">cj2RpQ.1!r0[#.C$_/@\.odgqs"&18R_9l-b-!LG]>SC^(@n&00,Lf@a+giR/2#s]s7::&$onqu^8>L$@JK!!4jUs;1JW(5D^"0`YXB;a29ij/U8OcFGXN6JmRp.S++gD',"Ci!g/8@"OEjmX^k>pG&2?:kK`YF2K,-=qQR-$phiulp?Iop[n)`7OWU+EUWdgd$5"DeSidieN,jA]mP0kb;eN<=e9k'H(k=n$nFDPM8SfWL^c[)H$[f.k-Re'PV9jk(lUt1N.;VG&aLrQ8C->?)]^+LZR+./,q[]qE_7$LTSD@K^l[dhmg>@DC.Y.'GGF*+NeR_2X*Xg]L5DVI)#JX)?q-rPR-7:6+"'kAH*Vqg(/T.$e9u"HX(UO>p'rrD#5`2sD/$37#tDID.M`coGu10t%L4P@B$fr\N6Ao;H;.d#IC.09hL9%G9i3.TLHKG"E5\8#4TgJiN>S-_TBQ9kf'd1VVp[1biX\Hj<\!4\7I$o%u@5hqba%JOi`3YW-V%:_j75R="qCle*CKOW/g&XrkS'6J97RYX/QJ\hGeQpP3]pO1(]$Yc*\n"8.jEZJ-7fY;E?lbl'S^SDq[8uTlN1WeC[k2J6WG*ff0eL0r`\*RWN0l1pCOCf#YG2_&L0f%G*/K6BR._#&[XIl'.&#cj'4o5W]Z!tYH'%I/JYrpsbD!+9I$[Y9X#hC?aZlD\H[$k*j:ra5CEO_n!)ohW(!7T.Kaq#qQ"K0D.gHIPJ!MRN$+Cp9sF^.9YS#G*a%;A@fY8thG;9m`im204Rr!.EYCGeeE,2K:^'G8r_j?E#cP*_=W-kQ].X@'kYnnRXdKO@Ck;5Qfg.cZ2\A\$.cp>7%fl]Q'gZZkEcVZ%-jQ51I2p?Ta:6eq0Ejg4is1GHN[O-5Rt+h@dqCl[JJ@$j-ohPhj3YP%?fF'f^W_D\&#,Fo&.?\1rDf9,:sg%Ug]Co;c#&L6>`LjWRbW378lOM9e'@GBiq7T9U;d!Zrj1VfW.q!3k)3@le<[Pj[^&/OJqOE'(k@bT8+24(>,e5(&OXJAcpXRU`m?r'M@!-VW6l3A/J+"7FbPV*l104AK"UGXKb3o1;'fc(,VP!"fVCCqb9m[Or'_5'A9+>`KoXJmlrK2#(TZJ55kL.l2Hh7$Z+?S7$AceU$PMi7OWDq'0i-?@;T@17;PA-HIscuaLDE>[+XDm]834SKA-46B$(MXOD>n>WTldM8:]s0LK9DNaTjST%"\H8n4:0nC+'f'U9c5u<6VM/P%jA5r"b2ZQGm:/+Q.(k`PCBn`Fa4pn#D`$@GfAJA%Ro5$\t,n5[TRfU7%ju$,E#S,656TT*rcB>+S/"cMr,7hiLiKI;+lfK,`ijjOT7M[i<*Lf66>"rh#@9^)a+K[HmO;%Jc[d,/c&>8rg[*^tNP'X[#jC]0*_s\N]?Es)=kY/YN:,mKc=540g=DX9g*&2E(ET#7@YFnO,-)[tEKHu2[%(gR;PFg*Tt^h:r,VYiFTgRdnZD71`np@YSUK%W.cI&;&/c*GD):X.>%J-Y#-_QL5k;pR[KDX@7p(]Jd6tI&V4DR-'0(U)"@_#GbL!5M&[W9GOVMOH_d(Z3VHPJ?p8:9".i_*arX6O)'H;;&,<$??A-Xn"fq)5bANhnK8\rX:8bEhHDu^a3q4fi4-\]0uLB-5tf9$_pklVK,-KO?jA:FE>Rl13R+U#_F_.WWI8p9D?(fcLMO0lU?ZC'P?cs-FX17]br!M9WZ>I9IGLDJ)Li>[]M\7>NkEEB+3aorg\r+_7k`hTi0Z^LJ2tmCmmdHcaN+uj4igdP=MRm^`(.QTVU>kAsCHCD#3s6?.uqu-L+8IC_H+j3u%8fCNC78k`Sr&5is'+FNp9#gCSe!!:g?3%WHEr)(d.J]EGdd&%gGFi%n'KTD#Gi-1L]T:jGDe;J/]Z[qpaXFn!c1OPiVUL5e5Z[IBN!@c7f"fkAaqmVbh&$)/(_6DtC+DVcU4SkXEENq$hBI$5j,2Na]A@2F`))3;No#)g3NOEu"[Ci)#i3uEul2!cZ#9TY*8:(V+ZVVq`(Z5Xu#(VdtZ%@G,F!\SXrU]-mVR)$E;4XZ3=D/_h8K>=#8Rp9W?>7r3fd"Md:lV]Qo;[J101/]G!aAIYe\1'g[/lHs66R];*V,)[5n,h\:%3\j9)E4TT0WRPbZhf[qc[:l%'@6i\\)0/oBF9"&!YMe"q>"UIBYp_#>oX:p[8d$t/-m_:].2JC3V$C:C9*GEd?,%e%(MpT;Fr*0duiOiYPCm)"&l]jPmJT.NtC3_)k.hL?SD!7,48N6AKLTU4^X]I8^.Lg?cmiRQC=S\`iYK;Xi[BL=#A!UdZi!K0q0)e=A_c$EPelbDUqkUesfT(!];/5.6]gEK+pO5-uL.u4e$8@8CjJA_AeOCfTU0G7Q),/AGS*>6B!dhOf"3sb)?VmAHuJA(bZ[DCbA*faUm/1`<>D-:lQ[Y/I'5go\JWcK6NA,al;j:**q28k(@BPXGD_An<+sqTJ3Kc1(Jq&M5i6mS&Y468e=_V2kI/'O'SXMGJSr-`!Qo@Cj[0h8SE'+'I(.;bn+*i!a#OqfFVkX^m(/#D?D#E"(8H$LHU4`OCSmgiqN`Nb1r\oQFRn_\'<^=Ngk+$gU=:mF&cGiDB2ZX^M0b2.h>9+1@&]);/m4M.DdNjHQ_Aq58sf;/I2Q]d6rGU7%b#V&.WYBpEE>!2b9rHQP6!p.Tr$Agc<>oP1[\rqg'e3`Oen1*b+>]]6g[nG3qfpa$r$(lp0q3.:(reAq>\=GeDM"*)K9L;Y2Y^*&U5hM@gE3JJIm>E,KMDE3ZABpa->^a9a).>L[7Og`[Gr@%!=\V#ObRlNZkp7Y6u.X+l^uoBegf-M.ED$=t()P(:_]?=u_?Ge>6\Ql0QH$cMVs`W-#ErA6^8(\TciC]PAG@_5geMRDelV@MT5,rOc$5p<.Hobd>UXGh<^j833G:I,g1e,ih$U%$%+/"=B4.C%E>2@4!VLP4'gj8d7.G!K\VPHcp"+j!-r&j1]Ns=4P9)`!lIe!^UH$8#RT39VIU'oKG%X(Tf=0niLYWGkS[#^<>nLauOgDimbas+QXZ$0DW:&ECB/%mlHp<)`uf26DH/])eb:!,=tg/_ZK1.=Mt#+-\C!4!etFI(-oBdA93+>Oga%D9]8a$?b:!"0-Ma;!EkO?9J3.96(/oEBO*-f^T08ACb-r:oC9'(t]pBALQ3_L;f'P=fk(Pukt53p,gth,?[aGE_>l<>ptE-[9s.[t#gurE-?L^Ob6'.3BYD:m"&+/3s_tjmr4T@F4N5412X(`&8-#<^Jb]OoV0>$g"MMe[j=fq(GA/:H)KnUd>(^!@)"[qg!;UM'lbYg6lE3I%=Y>H;[.1;_t^hES-%VLQ%iL-)d;)_WQAt0r=cH[mnQ!rqgCAFPWY29FK'aq&>[u)p8Pk0(,5S'C`X"/#8Fc2lQN&H&N[dILd>F0r(fh2]5]@mG,[AMCljAFWjqVEjg7XEJ^K58JoOiB14siS6>`lVL1?`k*34s;a>RW.1n;XbFHoJ"'@#@"^(t4jQ4\B%#WMYjUY'q;EWkaZKDdl>Vfem&M7'@T:#*L+h^WLPLj-SI9p__hm:P",ZR`PN5m"bT1H41nI0'dI=B58YH5Qe(]cn$1nYs>`MJA>!X1,@NC/bskrS+=8t#6kcVF>Oao2caKFfB.kYQd.3qCPfQfai&uFRk$Ph`\Z/*PtUY8M]&lFbZ72neO&O'NTe#HUqr`&,dSK`qQZ8L#&gH)NR@7n1m1/>!r3\aS[@pZ*@$W=VODb;7-!7/#5mcEHuH=22SNN+?aiY_L5\2$;W;fg`EaK=o71;k5DE)7F(E!RTt2$7]l.]'pR@]r;"90`R^6.B;6&/#*^F:m#ZLngnh!N_6V.'b0fKK+/PMIH7V8H@Z*bA*IDEcNc]mpOAQh2``U;,0E)RC<2Gr3*6kmf[S+I]@[/Je5Su5j&'9;l3?+-"c7Ge]j:V;oqRH0JhK;bZ3864cnLLhkYJ^J[S_cGpg-ke4-Oh[gl4kl279gG-l&]:lq1kB1>%1CA6((;.#*b7\KpKH2(J#E_W1#D-OC3;(=P%FrfA)iO=p+hsIf"Ce_B6+C<)[Yg9YI+j"QU0Pc0M0U$#&)cOo_&*8CU\EK(4`gCQBl/4dK>%_['Tp784)05'if.h3K&Au^s7)uCriMTVV1;&WiA]";r0)`@,T^)jjdmcsB+Rk.Yhqq<8Oj)]'9)be7>$jK$E)E&RYb(_$gfrS;N#k/(mN+0"lZ(\N_g)oCkJE[:aOVg5i!\T[a)Rr&Nd?-8keik:^0d.eJ&>LOTCobZ_l+8dp<0;fkBP*TXX8>B^maOkb6;\i=M"sHeNU7$69<`_fT(OZ/*Od/l6n''W@6C,%OmZ6:A;;"c'.9#j]Ro*m+4@5V=iLr$/\,FM'f!5N(R+n9$j:`=5/NdfCgUf7ZZ&K$0eJRN]pgOiX4J6Wr]6QV4'C0n"tle:s!o'3i!OXNeq6O(p.(sku>P)Mg`d$V,Yd*3K?`OcH:#ba$%4)\8:^aYu*$-d7AQ6A^&/%+l?>FL(hKGCg$"Zm;-WPEkSi:%XP#*f9$,Z'+A`rVo%2382=GnQHRD+Ok?VqVGa/qJX'A%:kL<:5;DS7;YRjdmGZ*m@uDfk';bePC\DgY2`(7J1k<-I7lD#)`X0?_:]hVe)XIB9*:uZ'!$M5_iO@hpA`++N`mFolT&HPA4kb+3Rg^lV_WH#KBKopIi,1U_++2*DK3pPb_;Tcbu\PXZ\L_&Sqa"pDcjD2khN@[&]g9'?AuL/#Q0M@qp5B:,T3W$?@[tf-Qq?@A%15&eNnf4F+8D)tn?#@)XS2K>e4U/+/d4p0ggE%Kd[iX?2eNR=.aqc1i:F\e_:c/&:Ee"-AXr3ln_NAGWTXJe7t4sQiBQAHg,Z8)df+NKP>5kHcM'*&k7TG0XVs#!FXR#6FRq&+?*aS&Qr58/N18QZrXdj[rZ`KC,**P=,=7@2n#2\Zs-io2JTb&E!")n.`*K#@UDWF5g0_+SHU/@L_i,6A-%@mF.k!f@6d92WGA,ZKrSEDV*b2D=&4)@/cC`F'<1"Z[2HMEm!5Jj=ngh[Cb,0"nP`<2t@hj)#NG.O/c9)'VojbfHfP)cTMTVRBu(Q&8I6-uH4("G'3(d>]!411huDU=ou(=Z%WmuSVVf`$6%Kc&*^gn+A4"':KL#!pY4B1NPARk,.0qL4KX`jl<^DiPL+P,I5WNcVgfF97<[#@D"J.)fC0V,IN&5cF4ge*oVMN?9daSjAJKSuCaXee^Z;aY2<*W7`K*M5H(El7Mr%H[4)=G`ZH24lOA,pq7\>QZp%j/HKLCncaLd7(h.0`)?RaJHQC[p`Nr?_9k1Sc:'0c54'Ih'9p`SZ)k=4]@`\'lVHV%sUppf'D\A9/3d"!j6!hVg0\0S.6D5k9:k($"9N):#@%0V-utp;:K`Zj>\rn#b<^:c-@oJQa&q/S%'(P[N&4^UooMZ]!p"HOB1t+1C+U9Tm84cFc)e&5$IfdH'.'j>nuIdNd'BSXM3P=KoNlmY3TXVQ>@,ESI8##f*LUDBZCA[%e;$n%em+Z&BQtR&e>Gaaf7=&AC#-A@X%iK0_l1RNnn&Mo\nKDCT*h,E:5/%g1;lDW#R'aU^&j/G.;"7n(:,FTC45!Pc6@B"`(uW\Sl'&NGi]JD=7gfadW3qX3F'#S;WC'a:bDDs.E*ML8V(5E$Q_LKI;VjQ33Ef_Pe`$'FUl\*iUc.NgSPW?\3/"4=R+?RTbEgdjPNOnO'J(23n7P!N4c!6TW*_?\A!p91P*5f?=#&jU&N?8mZn^@3u()U#O>(e,Dej-hYl1_=@%<'f4>"@qja+P[W24+#j$Y&)68ZcL5o_-QM&!;40lFiQ!g1WY(rpVM=q+AG8.?mI)&Q3Z`54FXQN9r5$=li17[^3^.+&>DYt>9j&HH@XO4n4Or!M/Aj>LY-[sj!40cRee.$8rr:hj_(_%Gm2cB+_JVGWm>?1c8bS*(l"kjcJ4n,D=\L*7ODhUG;U6`Z"1,P[<#E5V7CY]FfVWYe[ngdgJi&p9VY;'.B.+&2Nr$"-LHbh;6t*Rdkb"7>r5XRAT&m(PtNDL.;cKS$F!DV#6^h[+<^Z\$f*`jb+$;?#BB/n@2JB"_rm]FCC%\TV,9lVd_pYAC"&5obLbaP-]/ukciE_9NjV-b@)0GiZe5nAY+ug=5`m3%A5=PmSFd9dm5psn3!jRYHj,0$Z./TYK^/9f3WgT'>T9YP+[m^'3Iei[Mj2gN/q'9qYKD$%h0GTVC4/c#R!C8M'3uI^kj6HJuKuq!T43S-YSbqPm)U'[&5hT4^OIc[n>c"&B50PG!V\)e1leuf=I>`b(7&6IbH818;2LqmCL9Pq%rJ2*_Pn:2Dj_@\@-!X&naFooZ3iZLLr?/d7O'r,VOm,HaN[b4WL[8D9M;M>ib5mS&(,YVlbIN:]HMQYA\b>aZp][+5e*Df`3L]B:E=VYOh9(tQnrNfs\qZ3>p"ac%*+@V0]#ZFZ%Rn].u"PZi'#>cVm+iOjX5=`D1iuboDi=@L?F[L*n,-"3X+M3.fMGUR^OWpNC^B+94(VV"_Eu>5%!HAiEk63'+`3KC36qPD/c[:]Wknlf3QG%7CRQ'1&#+8<=+j;,$`6jSU@[&3fh0j%QAYNU2Jm`qmOB/mR$8gR6mK&=,6MP2=&i'A8/#I9*?#(%TiFak!8BqX!5f5`c&to/67Woh__g+LB,8rA'!,n"N(o+E:/+P-@a&D2[`2tISsM9=6"CP>N.Mu\/dd1b11r-i=@=O1s"Nb@1Tm9p/LK!oWr_GStj)W;b4JgB[N9^/r2&3",Ag45D6[c%JM_j&,RgPQQE42[g27$\Dg(r;;C,9&/6Xr3!'.sj7@ZnT:JD)U%@KL!dJB'OdPjcU'F!^^20C0sd@S%kB8C;c#cQVtmetRkaG@pBh$+Lf,!/s%fr9pUeeNOC99'\0?3a;NN(6(jUl7KCXa`A.Sp,Sj[*`ob6/C21^kV?gK?844XemD#;23DSlZW)a>6QXkajpqPRU`KV3rc=D#qc,1H*rja?_[3g?Aq)Y)%so<48Md#7E4lq!4\apn;>%b^\jGi0fOHED//1)/79A*P(E\#G!b?79TeiCS9lS0.S'=T)Fd#X%Uc-B8!s=jTC]$-0j.X^W4nn63DWrl%asMbThcs@Xn@*8d3P3E\S6U0ID"&o'O*On4gH"!0F?WCsEZo\W.Y\=29OhrF>q`P5cLpRQ-_JQa$Cj=6<0?WCO>61Fmust&'5Cj[\@M3u2\O[bYndX#9h,N#I3dhn[7q"f9SAgJPVX9lkX-Qm@;NIH#)rlgH&c`m`5[/+,+3=VG)5&Po@cJNR^nSX>RqoOadJm6JRK"LudH*@@*JK/D@=%G";O*$=).?aI#qQ"4a?2*ON+(L3N_4$Zb2=#JkCjP2CPIS'PmasetoH^@+*<'"BF7^(+n6$RJtR\Kfm#Mhp]JDR/j#itlPm]^m]MOL[6IR-m(O64p[UK2oBi/R,E>_>#hPiG#XfGgiI*8-SGs7R=m)`PfqCKb0YL_m&PnQh#0_&[f/Ei0bWuND[_5V>t4j1T<_YI[J@s*3NX,jq/#2=Zi=YD&HgQGG0f/kIgRQFPJH8HGbi$\3Nq(JVsf3')'<,@>kRr\)K9&iS'oD;/93i=85G%Y]n%M"Ak_@4N2O4$9+SqeXdX@%84(1q5m6:YjIqt&O+/3U3p#/\[V]g'iUpSjqle[VZ2VK+KZ?+m'Z)8Fq:ZY].%,aUAB^ISa95*@,87G6Tji:EkS).5hL`M)K@(>KP>E)96%`!q=f*hMU(j/fa2S:jSZ%EBJ3q4*$qq[$8i,(9]eVtMh*0-qa/OQa^E:3_=5^<,kK2fob^G&gp;QW.(ua-!dP8+7m=:!,9TMfhZ9t7,X7*tKscSB`!R2jpN#Fok3kU>1S$[_g09RC95T)JJ*H3/[]*BPH]?N.BDu&fIF="h63\H&"dDO9IP1UhR:R%t`2OmF'K[LJ5]Uf3H$W@n8lA-Ad]Gnab!_]b,e#&/$31+1t.$+W-qC!_=O[S[\"]!1*iHrMW('/'lQ>Xaau7>P%:Cpt$Pf[+Wr8f[a%^3BH/hTK/D1HJtc)Uqg"4/'sutk]q.ctLbN*[_,/gi,XFpo;[%VIO(@:bR9$(.*'[I\ddP6e+*ePk5m&-pnJI^?:K-DPTQ1.nBcK.KioLQM*qbp]?M8VKccWSY-uAT/e0faOnF(c(.*)PG0>)KJOUPt6tj6pZed6Q0N6AlPjg7_tmrJlDrMDG!o>.5.5L,h"lY?BRI%A'!Cu)2/20,\^Hq56i#ON<(BV-l*s;Bh!?SQT6!NN?F/t'd4hJ@23(0DQDj79YV*nJ6#qMi3WCI)$HL)5tA(Y$M_4WcmKhq`'V\G+N=pDKdCRK5\ZprL+2tZAj]Q$!3F)lOWc;O%cRQ=%H1V24H.L_=#DuY96YS?9LRNjo[dA@l)CfEf1O(^XklsbQK/TjGYBjOEKDA$Bs8p/,\'FT9sV2>+otgJ>)+CLNW@L2"rLb14;^RSR8FMr=%L1`a?[-Cb1J.NobAC]+\"74+@9;XH*9AShQkupbpT[QG8o;J/dkWt_3u46_t87l=!>E"p9`MM7HXc([s,uS0Vho'N3bu)2JA5dJs_oPhKF]"Q#VHoOq=CmMO15V2)?Fs%,MY8%)K$4h'.+(HIR3R1957abeudld/`RcnStWr-#COCAj]U$7`:;%dXdTJ<(O*a7[k&+"]V88`]>H8.*s_"PYbSOZ'S(J;2\("WHC!jBsu'^5]mqb(4h\e;a=:po1Z\DkTcH))3N$0`,QK-%E:!FVDF/O+<(o2B_*?c0V6e<,YK:-]aP!R721rG[2);ad/jdFAU8&CQb+W/HV;goH.nHedHr.)d_K=/)T+PP9`o)lNQ)3(IErhK$Y<:G]>f[MORjlq.-![2@oX+6]4c7#">VkE&9Zf6`*d-l!ORAT&R?SWP=3YT`$:#lYTCe7@n:(uRQ`Sf]\7tqWcI5;fr*7CW$,8R%^XVtpS5jg)3T$Co4,WYBGAHEDNb0#F[mZK1-@q5Xr-pe@n"(3&T;7(6$&:n7]"LFnT8XcO`#:Tr+D8;G<,9Y!l+\]PGB(\dd7I]&'P-7r0nZT\(?\;k]p5H"6)KjV3<`V[U[RhlHJSQ#P64c^NnX/RAqQU<`&;!<'+HLQ>!0flJ+,?/-rq#/bAU)f)1)8;!roI''pB9I\YNrU/e0>#d!/*fE(p&g,64bCfP&%=iF&%.jjID"^e97SU%rB\/Npc@Z!oc@e9u[_XLVZ=3NBa8<2V@q!%D6kWjr'&"6_'<-<^B95'K$^2Om!/R&%#T<&Q=rt]+MP,,"CLW(6o?#+jl/n?4;fQPQ_Mq8;&!RB%;1_c+,p4c.=Rl:@=W5M&]!\+@(T.1MBZLns&!]7+H#r<&qNo`keYs+MhpX]=WuG26O,VGOc[`d421Nee`no)W)\+@,CZFhpNE,]3ukfRb"B`A&@0jP;&@N_Vg<6AgJ[EaQ%6&.X*t5I!5eD0?!h/[TsP0;%n9@HpiK`j@(_pfA@&\I:F!)6k4tF$KmT_T4J\<[d@Dm-8_,G8nq>V/&'a7)h2V9bR/k]<&3!L5\bg[':;d%5??>\rb)=A$UK'B0Y`Q?jiZ5^B%H5G?32OY3.-0AC_f-`MT\/19CuS2rq3@H;\+uVp-1qb`cqLuOZgdXLZ"b6nH/>-ktAFb:U(M$l011Dr3P1%?2c453NLH!FUcW&DS@(TF`9Z%%`QW*'B?]U)a*.0-PsM+hBE2,[_%;Ft.U,V*DG01`gPWMnGd+o-t)sJe$*.c.g\56*!4p47HYu0b78b1!Vrg!]UHm5&>U#i@B_VGZu'N2->G=TdVZ7tg,>6+CL0fXpXfq;cuFYS+d+9b,=Sh(Cf1BQ0oe([P8[#q@Yi#8KZbnmJB&ODCp$u3dUe)BAZuOb&V4dr+s]/,'<"IE$7%BZ"&V,ANDC9XP1pXtZ!8@7u8(RZHW_o^5U+nTel[BsANPCo,+=,3oO757rfHEiimnWV]\>VB_LEOg^$@ch0X]eF_lqUjoVTh*4Z\_,6WZN&&;if2uY#,MkY7Sr:!m#BKA3_jd<)oks>%V:dW02*F;#9ZDj(m8u/`qhFkhl]DV=h:FD9n_lc't7hJ2Vp:MS(1J.>l.t],$(Ih(aA(Z\5q!I<=7>qKI*H2?Qi;=.P5,BV9`f8lU1IU#QhK6ou-O*0*sqN]]D.GrIO6il@5r>urpXO)s!iH@34:K@YG5I1;70*6e"S>/aTkmf5AQKseWCJiX\uGkjGHaP9Ar#1PdlVn&8&U>MFt$Dc`#reW9FFC7Ye4sH%H@Dn[-$/5fEH$\";TI/SjCj0HoS?YJlgV15;b&"T\-QM]c!fRksl?-O$`A_0WE"Yc>JV5aF^+`!/5>%0AF&apM@M/(hZqNRRoo7R:HgM73_j6fjNRb%/ak*b-ZB2q,+cR,_`g$*(%RG`"EOt-CLecVu\pUlZ`Q_?qDTR9s[=aihKlHL;Cj11LRJ^A*rQe5q"W2Jj.pNsTO[I(RY^hN52)i_Eq:=Eq\P<(jbpCOVtA2GeI_g]eI]8_['F-PpgBY$#9pYgf%n601%)'dgtEQW<7D>TOC,MNgK4Ks_I*oZhMsD:e'pZu.kQp*F,$eC+o&0mYZ^QGK$DRdZY)&aKOOrdF!B5Rh3o"IU3J8[<&ml@o%G)a-/42j+gG^N:@5a([L.9p`iihnd*GiO1@FUmt*rX&6'.69X)('*r"j%,9P&_5^778.SO(25$dSYc:3Sn=`hh!=+]$je@,LF[A\UiLRFA=o,AQQ4CBh,\qpjcm12\Ic4[N>P/L6e9U&c:tc0Z;G#(T8MsY*7??BP.2Tg8%XD1`m2=-\o02`H"rmt.o@$)[*l@L`OmF$i6qN3%?,17JeNd.om:"E0r".k=Cg@E%52(Vc80r@N\]87NCGgrM$BbKBC7AgAr69@^7Lm+A7BD`p#cgRmb1+^?*VIj8o#EHUt+gn]$6@H9TO#U['eh5R$NUR@)HDAEC#=i,a_;8Gnj3C^jHf4(iO/]Js@Cj#J-sK_8r3H1.U:7C&a42A/RL+e:@?/'EnTon.S<3!YYb>'\IsCWF8*X4'`N8q&KQX@>VM#DimReGRuf!:gHiSrP"*LN0%ZA82q?HBrj+TKp'jqZ@!T<(u^*7#$OS/!bj7&1u(g@r2s-aN<@>^F"j:>SeV?l6i0]tUm[YPT7$)>F0;GGhsI%CUdQ0&s*(e9)aXY&Kaa5Lc[UW'LUDn*Y>&HCU?SoK="JFdod_f6lPc5N>GlU9f3<%1eL%C@Z%s#8JPfCHOpR;q+D1sKRbGT[pDX@5pp"^&1Z!_9#\>_ka<5DCUH6Ge%7'PR$]Vs#>\J_h-6YC0Lk`f&<=^`>dP+NVIW5,!AYBUtPnY-IKcq.-9rAa9%`8W@GYNqu7uDsG;:r?+9,%8i1JS!cX;"8/)e6.7NF\>G(_\mR@Z5,U,%,qSF/p;9gIVa>k_aWP*]8(P`&i>D9I#/93*J`VZ/`fc^RcB[7[5"M&S%L/g'*[U1o(P$X@2:K&u7p1AHQ@?QC`V8ACQs(Clsl?A=QO;Z^\?\9iArfQr&MK#"VdMW)aa/iq&Q1Pn8N%dNfJN:?YqCC62O?6=LO1:1@s8PcA]nJi=X2e?e)aS;JP;P"Kn<#&flN1Gq4,,/QO*JWS%\DaDP#)[]DO[9>XjRoCk@_b@$ub(g2J@E/i.C0NcF-UprY1-uV0FJ[ckh9NPCX@UQKh)/+bO]J4c*hsD"_fYtL%AX,iaYQIl>;;,k[q:e:*4-,a+T]8ug6\Y4Xq1JV\kdbt9gs\/n"Q7Q*)231'Xi_GCl\ftD2]Ad>Z[>%=VGZCm]j+%CYG[=I-XAZiR-fWba]=R'sWX`9f5R\BdAj1Q'VFjYd,P`YGT5B\[Gq"/4:%:'G5U]BMm*["4f2Sor^[B`&*UF0iIC;c6,GlYVNNL-=">HnaCgP?;8A&M^(r`h3L08cVO=l@oXY"e$Zf8:q$g1__BHfa,$;c-!h0gNtt\j\A.:F\^bIs!+lFO\$E'6oMfhR!lp/!K\0':rM.mbm6C_,X&L7o_!!pai(!R+/KVr,\jjnN#?ZL&Wo>?Vr\qfdqXkO^.qDSm/B`T>cZt(1X=;D=UYVK[RP-_R%G'T*e8Wl'0[c1GO',gT;Qb35&_S],SEF*5m\.p!8c[Y=3PW)7MkQ('8/@bA%V/Y&Y"q^LcDn&@3A)D+MnOW=3bYfrGp*gQLoa`I(`=&'\K(fQlQYs_F/Ju:u%&iR*(4Y&NB&D.12_"/P$+240"XgnF:1d0-H"1H@]Tnld5t_+Mo646>31F?6ZPp[^hB4^$2YZc3*uLt[1,Fn#a#Z#tXJCn;7$4`O#mrf%LJ-e=K)V.IoAm\dJ4Tn;GImU)Mq),>WP'LD&IXu6O,)?1,H!g$O:2R'JEu9>lg">b\5YEth+>`PLG#^U^6k>d+o^_bLms?k*0UR\D#@#"&s[$tq&Ng+#u;?r0,tND#!BcnGGtfI/c_19fgWX*C\k3(29Q)duQ<@'Mu#[i9j&?31/R4MhY`8HKN9)^*&QbWNm@J)!"?9n5\sl0PlnPG:!7IM6_VRMaL?Y)8M,V%t*6>S!ZD5MA4!k(CcQg:K0'qpGT]=Q\.X!<:2/eqI]B6tRj?Zl@Dsp8@(S9GmhHL>%__@&54U@I'ZZII%djHPd=>f)p#CIQjuUolG^KOU2$Tsh3k(G+(GJZ"'VV3[3M%Tcgqs'@nNo=7niFtGX0oIf(NdI_6`>N\VjI6Y^@I1Gbi:7?SPr5$4V0VG&<2chMpGbKMiG[u`7QJ,%E/*Z6XX:Mg`d6UV*a[m+@+B2+V'1Zc!q[ZA5q!7^f]bp`]@4IPILbtX2]&%@_'qM_p_1jp&kGJGSs];(4.^eF-jL#=l/5.rSpcg"S5iRuoI-RhAfUG]nGGOdIV^%<.\P.LZUXdqP@&SG=C;A1:iZt!MZn,Yl:oT:"!Q,%:6TB_@+cH:2##HP6C_tCaj<_i_'O_B\mBL5CN$+6R0HhT5Bcq"2Lg%':#o(:pKr]0&1b#,TJq2M/6Zrm?9&jcnFTt7<(op2t,8f[XBFj:P/KHmC.@k)V,fXAbHOEuAO"l$SgeHP(g#6GlJR+sSi%m!>07:6(%:/G\bS2Cr8T@9b>US@]oj+Uo*&`_(@3h"Of7:OXsu#Tgi]UJ@&@BW&l4B>BA?aF9`"d\)I_Y&Zs/'p&VBb9ua1H(KX/#O\En:KAW?q$A"je$[&6s)a\[74k:I*\;SgMfU2u^brCM0:7U=;V'l-GBOH&/N2aA86*MS.XuNC7Fi?'/@0=6@[B5n6bnR^_6,lK;3k3fu9XNBDm4%d&Y%EaRRd%;4B&0na.MB4^ak.;I"C]-oN56iY'hM>Cmd`6Fo%(A\g'k/OJDSpikn;`MbpprDaTP8SrG0(BTj#JM!RBk/JU@Dp8B*HFtdXhOT_,HQVDP8^`2RE5l0K-6]h"1$GJ=c.)rjd,1:Or#f+$e`$R^m02VEjq4q#W>H8\aoC\2G2BS9g#<-uLQ9b$c0Mt)-1'%'@_L3?d`bi3.?F%BPH!s'Z`Ui3H_Q-=#U%K.@"<<&Z3?_QMQ.iW=?K&lI@%eGG[-TK(J'[";!(eK.UNqd;maQRG;["hu]2M\a/8e>)6-JdOX?55=cVCL+l@:N4AjG.QJQ_SZlRSM-a_8R(OfTP`$/uIDC/MuMS(("[@eq0Rh6uU(%#4-sUEM>B@,Tb`)C@,hB@eJ'm_Ch;\MSk4*WLI-NDK%gCgVl7R0lZARUGde.6@tL@0)+qD2:k&8QQYINX\f7)%#/$^M,]4GNK\mg;..7kg`Q#Qm>"N<.i"@5o('Lb]9iM.M?u%7?_LfU,i!+[HZskRjOoN&NZi9lR)%V9sH7?m/B'U':d22@r+k!u.1NL5,X9!02rUg_tksTLIW@Z*=nnZ;fYSCb%h+fKst_i&*jOG=@$iTEep`WQ7+'&iNl!$ngV6Z.S9#a!%=2!X!1JE"n$'(R(TlU0Z.IG"I%nNI"A-m5^+\p]ID$XSHI2O]a7T[QA?5Ej.VY`;-a"b=Wii\:iSE9i4Vs/Lu78e[Nf'[Sh&]!GZH!+0OeL6Zt_;edf]a1Ic9sAtY4)c+uY':_UP"Z#04__>*T^g0Ac4A,QZN0OrGDoKEEFKZXkPE0MdElU=W_)b-]j+FRGWet*<'[$W7!#/GH"*aO1L/@!a8i/>UbAhc<#MKoch2;0K$$nPU_r.P%c[fnT5bN6=+KgU5:pS`TOQF=_o;"]a8Obu0T6.B*G$8BVH%9<97^]f"khi!:iRTXM`2gh^uS;1R;YUr5\WF@CbD,-^72k?/LtXQggZ/8e"A+TgZXXiPq1'>1i&$YgaWA9=(S)&XGrHH"KTJ8h/I9f,*Gf4VPAZu*Jk,@B;LAA]TH6JC:m_GeQ?!-f[Kq=f[K"ICdVe_[rJ)nMT@jfMVEr1AuY8YNf^G7]JR=2$$q5snb>_DEfsLe(V(G1G*m.q;GW;6%B6>>bSJ+D*K1X-eGl;@'`70L]kJ!^Hn#"cEs#5SHme"UVaapV]kRgMgmm%3fR*l'hEtX*>IT!28@)_6-ZL3@&I_pV:JhIQF/VB[TXtmSSO^B2eq]l[r%BACLR]G\u6_V+LpA/%L/mH.7K:F'0d1tFJWK@6%3!VcqHD]eR#bfcDT9[PEKmT3&6[b_+6'4f@M1"+Y'`=@ag`3p&U"+#hKr%HdCg]/61)NOgc$?[@n55"0FcTf(j?aA7it7]t\mIoO=gff]8AA,(B4\r*BQ:3H)O"MUrIe\HoeY>t2$4_rNg6'WFOG0L21M5'p$FV4aUb.hNe=.Bqg\Im>[PlrjAo!?Y\iT?o`@9D@a=cc,1_R"6>dPMnlW4+E#O_4Q3sbfbC%rt4[f/#%h7?&LZ4=8f#ul+K8L-UcG2+,nnAg>6@I9L&r$Ok:=X&6LU`tmu-jGmt7j'[?mG[+<%_>XF,M0Pj(7&HSPeequI#$9$?c8P(1B0]+pk/M0LOaFHp%&\+]71K>&\X]?m@DnOW:NB:@WLr'LS14fRM(l'eD:,>Y4[:000[/2=<24Y.8Yo6K5+gd\kL0&ppU+(U&o"gEW"AeRZH9SQD=X$+a,+d]%pQOu]/Vg&ZKJ9LIPurE9a.WA%@$YN#^.!pQEiMC\h-%IdRG4)6=#J5-cn-[tK2clHIMDkZKLkcGVKd9!]f5Ge]imM.#5JdE)0(/Y>_mbBH/862*/]&j\@*-Vs]$kB[bM[sU10fEYD7*(R&*!A!PkMo>+\V=*8+GqTk#pSl='-O,Ied'YR!VcM>F<*PJ>!Xs2,T\ZgNC#mmC!3rQg(,b/IbmRnkO21c^RMk/F"\&=Ri[BZejB:YBk;S52H,i$IR8#O<56!Nkas&\?ck%k80/:IFANWZoW+<9(7O]iRdk14_j9E9F%Ipp\Ttj>S%GW:??N_q)C3h%2#PsL9=jG6<&A/;QJC1,`M[l:EjiWe>5T/rkTWJ\)QH!YQVJL5>CG4MJF5S`]K?=e5WUopIN*/%BW1GoOD$;[[SRBUf_/i@_mAe+bU.%9T_Q&,V4/$YoFo!2B'Y'!WB5Y)$%:E.O8Pf-[)t/B-XEXG4+dTZ>5dq<_TJmr4BE7gM^hD;)WrH>)2[E",\T.DEK;_!Uc`.B)Q(h54ZER"**i4iOOB*h@q,K0Sd'dr*fE1-$t*GUWbjIJg;Q_&@V_gmfY=Jm]pEb6-qgf$0,GbHfUM[&gXJLK(cT=?Ds"brd@GSaeO?mqk1YX.]cX,3C"i8+EB:Qrpk[)#N\SI"R6Qr$2$]AfJQB-DQUNuR&&U)Rp@\FSJ8J"Q6I[#.oEsg=)Uj25tXV+`Ln?>63.$2<$MQg+K55?A3*()%0gk9l`c7s^&J>#-)52oIoAHL0^Ie.6N2)0"q`(&^G1J=Fb)qj"Z6o(K&DX6q\IUm/];">-"OB3_LqL`e+p?]r#u/ObRtsgqQM+K*d,q0d\9Gl-;#H)[Z$J/6B\;trm>%tF@$`iCdf.#1Mi5^&t9_s69,_2NS'V[ODI=G+Uh$%+)=.(>2DbB0b[8-AJu;i%7AZCR@T:sq=>[aVaDA;h]BN)Oml!m7QPE)Jg9HQln8@"&NK#^"R"b#KPH38no_0oV&1Qaif68*l2]>QWqRU6HfH&BdBu?eET"SRgk-)?Gd^g4Kt"[7C`XdRhrM3E'tc84H'U,+B^jOVQ$%U(]sbWl#NeBoP7&-j=9*]\CQ6`5n[@]=b%J4J@qhltJ3mcdLQTcnEE?<\&]cpYd+\iY4nmeB>%44J@P.a&AC?$PH)a?/E>KsLY:A8[9BbCf]1@`J+rk*j)L$11`C8U.7E/VEP+S2["O=2=t#"E1pp>(kg!huU4:C=I,N?I;.r22^`NEYUY(M)*!;!c8X1q;S.PQA[^G0M2p2Oe&=2ZtTe0BdheG'?bR6:\P!M/b#=6R#"BE5qY$kWPutf:.&d,u!oITk=;(Z%8"(&0G7P#Yfm,kN;!>,jq%jS3`WZ7/D2%$t=n7iT35E)GMFp6)hh/^$iSu@.e"FO="$t9cQrTehM#oYp55Jr:6I.XL)YZ5*"-+fitGQ*<*mfLVVb02('Q[8(k^njq'%:@JKC[V`U?LrmRqX1P`F-.QEFU;2ltGRrF@."QB3o#B!p=&+m%Xh?M3QQ1Sc(.o$eL(/T13E0KV@[ArqAa?*jO.NK?#P66sU6)jP'T2Qu#cR75(+B-u7q.f-@gd+\b%tgA)?ZhVu/:;([SO&J7;>_RE,M&EnB<9J2OQ2Zc'c19,fb4f;dhlh(eSsan&]'A,fGM!PT1AlFp4'FK^\@2X&%ghNbQ$c*YOc,mkI^btqJ?%Yr-j_,hu%u_rnm`?X7bHOa8Xn!J)UF2s)6NgmdDd":X/nThuA1mrP.Inn+ZjKp\j"LIt.9C^\@bpq0bm6njY)%2=>,0Iq_?Db#;>.n/E+$9GW*G[3+O03-G.sI=[>WCSF4H)u??-d"E0-Mj])>XdjYo2J`f0.P_Ka'8&M?+/UMHJ&jG;V(#@U%a9-75iu&YN/5E)YT+-B6-K5[#Xgur+mlHtK3-XSk-$B97_JUWQTUP?g\mJ2d7sVlL=*lW6^7S`gNY?3%Wi+^A())!,/GS%=]e#lP%IFh4/+XQ?L$.W;jO1($.@!BI!B+OM,BA)>hZn8_G6'H\T42US[W[R:#oPE(`Y1PV/AX@$M`sIMA`F_!h":t8UY1L^U,1&ADl)^CiN9>H7jWl^#ahp+@I&6]5DjmZrfi`Uikd,?5YZSCL(h#brVG_XBEJj=JHT[=l7?-+-cAiD%R&P'irr*%GI[3U9a6cL;R6jQ%6+jA@(2f(H0MPO`QDtgk.gE.PX2WaGb%h6C6a%(nX2hl"B3<9lpn-fNc\`)eLB\1ss[`2Joh]thCAuJWtYYeS&;>@;JV%i-D^92r=//S,TL#R\a#YL2C"%#tM7[<`rG+Lo`J7m=(7$*a@j9gIb^*jR8mt!;`KV1t"W>9?,65F(;\pNdg^()MQ@F.cX//MMA+FOO*f!!)_(ZuF3;]U3/"_etKD.:l=1i"rP)&sPW0NmdcM_Uibad@%->iG*)Xea]8a;V&gftfGf/V/@O4,5ZR(`g9,nS@W4Y#;\CHnUi4&utddU:g?*nQIiFX2lG]'8-NO&5q_hi":`[_g5FNB&jPFd,cfL:,8RDg8?.I75p2_K#3sA3e8B[!A4KY2Gu.5$[g`74/"fZal@pEg61phh:h'SK2cnB;tk/MePCU@0@PA5s%9`>`D]73D+p]*La4)cB]Ofj7LD[/0T&E:+?MT^:YmfE4$aD,&D<^!FV#b4#Xh.r'Rk*J>j:fb!++Ag)"os*n:K8VDU(UnP\.BbV[h_$R*GRknj0/Hu"d'2("m+DR"\BkD4TR`[benllTDqM*k!T)J#l`-LpM1(Y]]#iQVqX#3Wf:3oIp,EY/4$AQSoCTXK'Y1EghGfK6.KiQ(r$DuSYbO?k"A40O=0qkF<.?^%,ZWIOL91JRljVuM[5/Xq%ba8[M#*jO6c.*gUsYF]*Ts0hKdC.Lo(3/5ULV>e3s"K$!k.5@!,RY$sVp0;P7mk+>U[?7rB5aNoErM[ph?G-".c^Q'5Flc0JD]/$0qm5=XAhg_PgL7b:$JTBAcFUV4+/uKk:6be"a@q]Op"73rSKF8S!<<$NjGIoM+LE7X,Q +#6<\%_0gSqh;cs6EG:EZjL]@DS^PGL3s8W-!s8W-!s8W*b"9:cQ!WW?W+Vk9t!$OmAVk!X`\&JCJzzz!!!ObTH+O/;FH3=(Ufd^MS@Y*S5QsSTEQUlgKKSPg"k?5F&GG`Z4Fu$%\(g?"n$+<1Z+ZUnDYA54$4CcFZVMZeM[p?3=oH&M`oF:;:B*&&9!S7!bf@U0lJbJhA`/mdq$JK4\dZ1Bo5R5Xh`Stf$1];AG'iW58/[VXliHl(6X8HaV\uGAQ*lI.uLk],tUqX0&dQmZ)H(Bf3GL#U9YI;-1jkii%^>?%W5-_UT]t;j@HbSZi,5^i(]m4>c4.fl.^6U?FP[VM=,]^DTCSHS-Ji`qe(Z=bBaD)ca25k+?%"n14Z?%.Y;k#K%S4DF9d6Kd=Ve[3n<2,qg!NiVa,UTNe-Vpe[^p$eU=[J:u*^:Dub=1F:T,\4J-tFmkmkYhMk_,pLBqrM`pcQ]BaIC4M!.n/"uLfY9gkC!$;g@masMdpRU\0gtTj3T'#6SS%rU[)T;Mk#2+_OIGjj&h6)n1]0I=LhL!PkmX;b@]sk0;IIln9\)-kjp%@(bpTSrinK)nd^<\sKh;BAOJ,h][K.HBQc*n2WDm,QkDM);;G,ohJUpnZ6H_uJ^Vr)oop"@$+oNTK4^#T=Fc[0g>N7,!)n$h*Lmr%m5m@)VnLMUCo]Ua7-^<\h.]m"h9oAFK[eaO"i5\WI`I8KB>%s`QYfA#Usj4$]q]IqpNiOa8K08#oTkkas;*fk4,E)lu&4mq@dFS1(2h/FBM5S'\>./NX`++&,4hX=\3cbAUSnR!qhmW6&"Df9de?/8\QPe,%@,A"'"PjPO&\Z$T2B=GMk]rgko?@BN7p?AJdh<(>9H1S8RjLY3t]m"kmD,]+X]/aB7SE0BX`m:Qkqep7T\_"K=DmoN"EV=W@q:El(PtU4$p(EfZJ-Z04!#%TtN<3X"1^Q93.?d^'14g$5e&i2"),,UC&t/q8!Wi[l5X:cs8#XO(1J-i.e=IjtAG%d*JYms3TE"rl&nqt&#Qtf1Jn^l%@X=FZeM`)s0MFscct"sOhPB[3W*qFcK1u>&!MBDmz&L&Am1sjW,2*E\u4;?6R-CTocpo3VJ"sho9:ILhTHA8&k1]cht!!Z.8"A'.2TUHcGJC&kASsiA'4lE7-!'T6=a7\auG3-KU;-^Q=1U?q:>):@Ca";RU!Js`8U/"M^BWfM]q5S>_JA.E8mdhiYA;$9^FMg!e,>p^RJ4R/=*;Ndkt*/,9i$i&g/T?6D=gm+EXUdMMPg^5m-8,#_'95RUAU==5O-o&.c*@i0Y'!,q+ui$rKabMbmA(dNa^_>q[":o%Y),=L6t>"$p[Bh$$s9k't*b&!%[`mZ4_ZOKWm)(CBkBp8[&AZ2Ps7L;q[K..CD/Hq=`WCgpQTk6Q#OsE:l/WgU=.Hq)-4nfKOljiZB;"YM-2\_bqp@b`KOdu).GE/1sdf)Asj:T)GHSd8Yr)u$32Z:g-]:@1mK@8VP#J2JVHW^YVOlV,W)766=e2JCkag=m39sDf5BZ3P7#1QLdCIM`LQ5#"0MG9">NCb&8<*;);;-=fA&T!VF/L8KS<@63nc*Ik:M+h*;MDR*;A7WXp6:;bk)4M72`!h?Y8l3_I1EoDdJm\l3&Vu>`'-s91A>B[6Xd[gOJMS.aZ3c.>#t5+C;A)MnC.0kGRPCKIAYdGIU;U_sCmuaR7*Ne2GB"cX/MSE;9h]Cnee#qAN*6T,.jiB"AsURgWC@c6.SS'k%5Ppr$8@jh;J[c$.2'b$2MQmLbdL(^7$uM`dO`gN9.>skL2@P(ZtbFSXN&[GU6/0Y+@qf/V)F.;,u!#C/Q>qVCaO#+=PI=i7]]e5!no(Q!nQ$T+e)qO,,Rhl,VoWs0sO3f:t`6."\G)L$Yi;"A@C3XX=V1E=KlL39h*g#fsYL)/P:`*0i2%iL6SM\R[0.S.U"YDPd6`m=>M.Sct$N`;[TNRU_]@i@^Bbp)?CL#UFDC?e7-eE9pR,jVMo2EPd+U@@pmG`,VgTHZ*J1TfW]0_CmouSUm!@!A>q=>bf&0cM3p1NR5EWdCm-\R.N4L]AO`CN-*`SafMm\777h$qQ7\(8,n.Y)(0_PK5uT?I)[TXU82<)_U9_r[8QKDd,f5(J;'QrO/857h%?"'*2OR3J,2+WJ'1l%7;3;TZP;8re)\KGHN.VKbZstep+XLri6Hg9'<_\cm9"$#!aP/PKMR$@..2#P-7'T1<67n1UR$1E5`F@%<;R)UQ$"GMTU9[1OgG;M]=\NAJ&D9NN8VI=(C-mg#)@BWSUln08D'kK?1*Mn9,b$r8o#3\AM[%9Cm8E:W=c!c0dVf+.ZG%?%@NHU<_]9"Z*b^qTpS_MCbl/_`'S5fL9XR=/J]3MD'gZ/%;=2tdBK*MCg%39b%[-/c[L=k4J/Cp8ZCDs/%/5shpR]&,UCItoLBsJN(<(>E4[aLXJ/Mf^iOD7E4=f&'l1oW=/MNH&g.VY.lPf67(/B\]!M3utN1=BZ%;G>7\b"\k3Bdt]fe5\'-Bs"4(9.:3?aDG'S0eCPmUpd(^fb"m,`O80&gM'8Zg<")`2,r+bRg!WLK4N1MSi^[:/J9J$7]@UX/*pkYRYHqrJKmW;fQ6O4YN2jcnoam3$jJ92Q3s=frutG[PQ%9U)9e:>k^UP6qJ?h.b>kqF-;R*.L]*"]s/tg,Yml+GgU(@k=24M!$X-[FCObZI=W5Ju3G.RQb35J;R9Tn<2[TuC`kdCGQ]c.Ts%eq]91OG2goR#lnU$q`bFVgqH/p$'#J=F%cijNYeK5?i:#bGdu\R9Bha.Yt/CN'"ebaDhe?-eIZp`_M2]GXMC]0o1im=h.usER>u8JAdQ;[,P`#kXj_j"]@dQV7kHIO)NRm[OB>lYj5&gUHY8c_%9r:(-)JMN/uYCKZWm!_Rt(Vu>td78FVjS><)7I+T-/d*QpL"`HNh:P6-ukA1Dl`%S.][oQ.?r>qmR'3UPrdW@lO=^q3Oo3diq<14rZ1R&N*lL9I(gMLhcK=Xgnokk25daB#ikb%Yh/K_'m^_Ro)uuTFJaPKQdk<9oWj9'HaE9NC3Z3,8MQ$Y(>irP3GN.(9JBh95g\t>/jG2\njd76P">!ljk19#bX+mk6e*@k/nFP;Po]Ko_NTCnHGl]0O]`S@1&N?osG%%oS:c!Ar>*i.9U=r(F'89o6n=pEEt$>FQ)8/ZI9-TAIo?\FV.U"mcOqA/@hCR$6ea-\Bg'h'J:*55>h23h0IjS#!\I#1W)"$F#%@c@GRZM#,9/&Z'4=;L'ap;rt]Wo@NQqQLgqu^:9F9ER:Q4uM)muX0C!K3ARAu7rt8?^+7_0%6koI2+)Uq25&D/6hj.#2431@NU6"lN'G9)#+tM<3H(gil]%)JbcC&.(n1r9"KY[5V5>@DHhCD&RePjl*fPr3nM&oe-jIuEP*Gl")6e.QUXRb#_Jr]?E5tpmAF)$0k.&6:93\[n@@JWm@8$gMugIfHV)-FD&?]-ICb\H=!n4>Xrmf7=;s,OZr7ekkU.1j$'6=`E,:6U.n]I-JgG(+V\CX&ms@4I6jY\V]1Pl%3`VEg#r*Bao/7<]hj.nN=[WeYa`T.qH(SFqR$3?U.IuU=5.p]%3/7s>Zl]hU]kmL-*SVQ+XZ0Rl03[[ZNUsC(4MMgN'(KK`c3M<86VI]tmqJarOIjEYBkp%\"!p))Fh=Vba<4ZU`l5rSO#RJ<1($[;n#``Hsh_"L2UdLNr+g5KFoqWC7MP;@n53?);A34>O;q6a7C.$@%XHE(EZt#@[1/pH4G^oMR%"o!+)J+sld^(8p8:UGX4rEC]4:_V];]V;@/.qi1#:0n3HE6Xk2C%q@7.B-pj^UZ.R\c#Qp^qmsnp&&[Y<77I&8K0C5nHX+>YOP_E9IpNhfPfs\9"E#7\Kf-"BN#6`O2.,d.k9FnLUV\HYo56t&VYYS9L88GFRY3gW\d2mk5<3]K/ar7d`A`t6M/aPkG$YbUqj-@Q&Z>qN$SVo1UrEbI#ui$mb(S.f2nO2M-Us?qU2adQaDD8j0doR+>[^#mjLj>S]5K.@\)TCqX^bc#L-Tbs\[;%+U6Na_6n>YT28m,tn-TgQ3%Vn-E1-TpS?>$mLM%_HYV8a#9\?]C02@Y,_n,piIVqBmTd:[P1PLbL/f40ABa<1J2dG!0?4nZC0unU8V2/'DS3&*D%I+K$fD&k#--Bm!G_LZk*S_==,(FelOJo!\<.3V.k3]jHUGZ^?R3[lF11GhhEW(A'a'6saVksW*M/=W$gR'=6;qG_(D4t]Ima((=LYA$jrTo)mTSn$=GU+t_r+S&7.=H8@LVRe%H#ToCl!ZZ,//#pcP9AecPMh7kEpfWOKuV^Ztj9U?78X_lp;n#2B2*"l3=,dHDlI$5oBkO2A]hju!c,G`"8ZZ#H*FfT(,5#n%&8"MH=gJbu-3d4?U4M42ss%DUu3@W]Zn=DK=,s9*;SqSuP6-/b"&"MR==E:M>0A5NXT)%s/PhTD6''#@PL!HJg5kO55'uV_=m.k5SgG&4L_;=1@Qq%;B+R%OPocK_dL/]ci_5ida%7O/Ml]-k4DctjHM*(cD/S^cpgl5ldCY[3DVOZ(Z5X_%C`g2&@&&I4cT3M'$E(571S6D#b#:4V#euR6043j\b?>DA[b4=5jV$^&6F!q_IrW/(eW!R^U+-28YMet&?D9,JR(Sco4RuGY/[5o71C6l0TLEqtFLiX3lXMbN2EJY/;e+i2Q37AO-Dh=eZdH1.ZDnEaR-f-"BG/XIU8aDOsFG/ZXJ$F5N.T+jVn8TBhRLJtO'uA')B;+&R*dGO1O]b^p%7C(-&(<.lLOUYAr#V&5L.K/`BS94md%@+c9OMW[*m'/cg[3O7;>q_Eg>/:TG.<$=YjCPEWeWtmg+)fecr:H;9)L7[5WE0%K/aM-=k;rXX#nF9N4Ij]JRPuIRHXhFAS$qfPNYs]iXb9N.lQBb?)Q8k9A"OEN^W2>k5P7q!\>BRWB+G%$L2OTS/M5Djn&[Xtc@>$R2Z:5WnW#]-41dOaS`AAa@"&Um\qcb/HeiphI`R5e(b:qAfeKaS4FS^=@U?G,Za@N=7mupF>c[Dm)ek)U1MC(A"Klrc3Ou0#,@cP]rGG8Zq^<0&t5A)VZ%XJ5_BNZ`90-LZtQK2jUCZ):')iiMgV/cePKS`MeqKNbh#SM0@/-t8KTl'X/2k2JHGK15`dS>m>WKO&CSK\=BKT0M_?.bCgmYoGdN6S=[UDqVNWZbPaq'3NlToq+%`ola\fqOF%i_fD]VL=.l5!JuUrhCkf5p^38#'@Q^CO8li5T:crN6ok=V1NJ[eeO4o,4npTJt\]Q(EU,(G?e1;L2o!R.,)TgB>^sc4FW?pHa`fL2\KU7o%qPL]0k41RcMnS`P3ENY.=0Rlj:Roo8ou0M=464%)O-UVGT##qr,\/^l)ljhV38&m,pj@J]hCN[<+N:#E:bEN$Kq'0B&)D*EZO&20lKq-`RleUca+lg:K_E4H*"rBQ9/$AcYh+)$.UEHYV,IkMm)o.o0h"EoflRPdUP]3@Fh!BbgM*VB4r;E?J<]/jL"i0_:8_*5'@r%!FsrTS`GAJ``$L()%$R:Q1*lXlasc`^V^VU/FPgngK*R$;ao[rVN=Xc]QHg0+ln%mcOQYb[`A]+:B9'G;q>8Bgo9%1Nr>dR*9#1[#*hj^M?u>9.W/PFTc9/XiD--5]EQ_1o*YQ&fCUJ^+V%nMh+%CReZrdKkC,`i7!8s#3$&1uZ+XT)pO5Bb2-[*&pg?+XA9#kjl@rT1&`\F5pB+3)THqHDo8,O:\dAHuW"+b:mFJArMGCJcd^]s2:$f(YBrK4(+ZlZVgRj]=PV_%4E;g*#X]I[kcOR-jdaSPGRR"r5m8gDL;hc5B]p2C4;j:kGV1`Za@)75M1/qKTN7LSc^cbE95rBTX;"FeUBdt6?K.hmYOBmS>2p_eiVrG0;]dB"E7/ZD+-TGU[R?$SeS+X4[)%,rbL=,;s1'HHt"PHJ]lKo'k'ILue=$Im7n0[S4>lqr"uY"M[A'59G_5:*%J:i^TPf3S.o_pHUgK///drnG5*d2t]H"Zge\(Q*2XL>^:NoDJGm-aK\5d3I1#$7QbIAd4K0\V'KqY8'\VUf)ol,?#OX6m(2,#73lDP(.(R/&VciPkf-mt=^Pgd$\"A-+0Oujg9`!QJ$;.'rg#@6QiRUM\lsk#,hKmcWpe_Kb^K7/Xk[f@MQ")18!COKDgoSc0FHhJA>6tOUP%KPq+gC3optWbT5AFg&.e:uGu2?6JD?ML-4)$QXqVJU)(JD,G`3I`aG6b@_OG$*e0qFF83m@,rS@CfbMhO![OW8%.S++D<7.X"uT*,jZF37?%1p#F*=JZDH7.nnR'&lm\@3+AopVTMonAWr`=+blWUj.S6'l)fkuZ#L#Cq^.$Xm,mip,Y!,b.IO^QGp]jIS`kKnZ1l/C#jQrL3W%o2NQJW#\D(%W!s@W$C0U_@%]*(O<6qihk1$)I;8,g3;8-tH)G[,0:p*2\[#lEL=8F,aXTmh@j,B(DZ(1^7Fgc"g0jpQ',dJlB;8b,K6ZU2XoKDm9L&.p1ZV%Z*L.TDBO7f5Ng?&2.$Gn**TB827b:YYO0bUXG`(CO.7sYL)*oHZ`P>Vi:R#uqLM#;2h57?SQQWFi01H,j9O`p%2glrr%>s'Ts4C4\BBWUub7G.XD_^5:*bPB!.B<("lR/M3m[nCCh'gP6OVRbmIoR%[X8/C3jQ:p\sCMft&^UekT^YbkLm.]ZF+$l^h(^&U?Yl?uhq#DDegtIuRrh&nGZ3P__IZ&bL\QZMofsp3'`BjtRFro-K#N-FbNat">U:fO@lAWJJmJhB3be7>09!9g0rrqJ?m5i/KjKL_JL>?!V2suY#$IHaR8hC("8-V8l(,aZ67/@k)Y7VW2jSgn1rVq70J*)]m1'Br_#\FWsACp[@6KlH(9kq[_`sJKEIFkmYq0r9ZSH"br>O8bDqC)`3C!1`dA_lObk-$pr[Wbq)e1es[d*Y3+KI"VO8L5]^6lImRW(D,?Mtk6J`fq]VhB+":V1fSCi!>erU'U[P$s)^A<@9ML.'T%8Ir7`M.H=t[ROlQ1qkm@O&G%HarY=76qi_Tb(%SoJ7kbs82^BZ['/P^%99m8OG-to(?aXC0V'E[JcZMHBPJn!;C-0`@SaV/OTqWA$CjSYcm8>2hdpRE.2WViJrmic.Y\3Ne$K[cf^^uQMQ$9fYpa"dD^T0E."YUk:tI/DRPs5N`l),o9WOMGA1gcRC?jo7neM+93HT+Y1lI*FU5nHXITMBXf"HD0O``^\bQp`$mB3U8/(Q)9BS=Um[oZ30LhMEPZr=k8"YWWYMVu[`D<7jMc7-[Yn,72lC:H(;K+O,qj^=YE_D3C*U!AH*fEODdVa'(YZF27_A)+O_+eV*OK>G;h*uK7gSVZr"b?ARfR:7&siaO.s:*V`K\VBc35g:aSaE3*uT?ZJA1?UNGXtrt9l+WFO)aT\.HHR8mWZMV`C"KWZMo9f9\l!,s&\M1+rce!D]f1uka3&eT*g*trK"?fBW*g+%rsJr-GdF\2h2`jjUm??i+0idXHcdDLZktqA0E+ah1qL+H`JV@oa9tZ=IaQ#]&aSdH%n'1+&'@0F=\J71s)n9Ql#L5gDHIKLPU9P@RO02I3:!$Z8hSje$sDb>qA:r%59m<+j73ed`R*AK*$f]MOghFT2)*[rWV8K9jT&3\?=6OP39l7MkH"MO](V!)O`-2)@lI/Yb:$0l23q$rj\1B_Y1S7*7Rd1JKcqR>h;Qj(X)sKG5i1W+a'98rp\&cfs2M$O+'W)LKp.kB-J<+TmH:#KQ1$b4`0bA\/n'aU&9)e>G]_o'M,crC0a?JiCk(<5_]L;Oe%q7I,GO#1Caj-'%+ooaUj0Q[Jc]j[NSeIq+RP6Z:2l..J1mNQsrQ&Eu*I[/D5e0Y.10:8=G\6U0'LEaSU&'G"0'W,JaM,*9DNnpq`^Pr>B7QG79Ni8TN[lQ$D!OSng&d>b=m=HK>KoGd-g$Y$eQ!$+k&rT0IWIUT/6N(M4=Q11phJSs+W[48!ME)Tt&"Aru?SHH/a$dC!+!aIH=QL?1Tp*[%4nKp]5-?]8gSI^kVF.^u@X%)GL&J'3O$O"6VD:/=\)77Ps"U*eaLJK5$Q#32$?;RhBiX-$O1dq`@!=W3dh3L5M_,&mm]LX/C`U4249VR$NgMZ6T$"-L3700N;321#De;fN9Y7JjR3jT@OMO,I35%XY^(ZdKBh``G"UNFYBLo#27m;01IHF<6A>B"`]_!2@Y"bJNtBY8&[X+LNDD]WZ1C.Xp>/sT]Z'epijLn,Yo",d_B$"@A]?VersppHID&Bhc7+qXD76j+U(#N.54(-eV$,UA2o)nl#0dp_q1d!9lY$$/+.&&\eKA=9r*^#=/0ijUI\9%<-0uJ>?=KPB"MWNL._ji4qa-*h+ok=TV)dW[50i%im;UMkA3dc$*K*OO-4m7ki-"qFaG]`b!#@mVcI0Ed#e,u7S4u!FrrLJ(bl_4^P-Oc&N(!jIU&RZl5D#s:-BOWoD%^0n_&TPT_>^'<+>5kCat:mk#U3f/cnYq6l;(H1^^K;.)IPh%W4X9<3_%/V-#XSLbr(oesn;t`%b!2h6*$[.AnUBD[EG_L!(H@^kLUS+PE/K_*ha)@6d['gO51,H5lpcd"Z(kI/*-]L?u;&AVi5f>,A&7'/Q;D;m?_N\HiIrZNIXt5r/U]fT-JY8TpFSK*+KUT$*h,VFQl6mUV*;0XrAqHO3LWaDApG*7l,r=`CNU2a_IVs$t+:LTU$_H(@aTrC^Y/'`1*f+B`+SFiV)J7gl+MqUG/ppAKK/Q6oj4D-+]Us3/`&A*#,q`^$OYO9*#=-:R^njo[jUdbKX<08_54sbRFr]gM@92dVZfjL.2pr\AgjM5DKXrOT""B1#WUOsTi(eVH/I`i4O[$,Y&PYjM_U>QO;57<#1Ie_1cCBpT7KYA*'#H.18.o(lGbg`jdl*/__&*NrW8%$[mEa;i^2M%KMjfWT;%/;-%:HIb(2k@:gB?D/deZk^,pDe-iHZXXVSIj6:9F"-DKk7QJ+V=jAE=^DiV`^+VW';))ENT)W!7>Z22BK!=XF@_[*-XZRVaYskl>$kOHZ.si!pRms.uQ:oR%Dl=6L=XOE.ho5Z\u[4peI6VB2Q,]UMZq^f&rs\B7Ak"$UN#fU]7U\/f,f+0D3Jm[]CuYX8Lb!mS8.jKjMl=;u#;+366^tJ*f@Hr@'(F6HS:[gW[J:1\'Z%l-V.rG9L?QZWnh$)\I(hi@._&"f7Dr;B2Q*753/AoF-&0'Dn6=Rls#VT2VehX";-T]L"+TKWj?$r$K-DJ)E:/GY%k4]n7q&Lt-0N%jah^7N0k($Mf=6"=;BD$N[sL&"X$AsFEc_d/.@Qp1[INuQ^bT_)<^:1%1.&)=]aqdTjqI\!D^sE\^4%0Tm#CWrAH^c4>bhYn?gQAJj(:Lm?)-D+J$XmuDb7Pd(he\VBVRhA+sdiT!U"F_;24=Qj;KY(F=1!N<^q:qDeV6iV%@f6oO_F\pNd%D45g.-"ia(-FB,C+rgHHI[&3pOPD2*7!fCr.(CDFAT`])B>D[Bae8MYO0P7NI&+;O@6FjG13G[NQ>V5Q-nTn&b+hG8%<6h,h)D*Q\#r:.XqDXN0D6h?Sf\W&n9<1i_`O't_a]-k53It[a`pJ1\;!^IP5)2_H[Be1)'[<@;Vo^`o(CEhRsI]<-&d^qlPFZ8=+.dYO([G;p"!MdVoH&PlQ$HF/"Cf]8(=3R+X&,RhMhGsa[CpI3cf#8AM_mRE^8Au;:T4u&Z(Pg\,Q-is,Vof#eCS#+`V6IZq*ao89hf3X_+!q180=^LlhBfk0XSM^@,54QS.5jVQ7)"rrPfD3)ZQI9$oR+^hsr6;?Fp5%ncoeKY`#qdpQs$6p?*;,@ho[9l1::#G2Lt-f#-j4)U+QJ$oimH>V-g?K6:eJ',SXH8?T8oD$2ITn'8m

>(Y0MK!to1S:53Z6`JLUg0TBc&1@BZ,]mU(5%8Emq3rZcI*39VW!XILpBR,#6aOh1nrTrKZ_B>SR?H!2/l]?Y2&:Q9^C")3M1s0(6F@rC-T@mnM[DkkbneF3k_$Zj5Of-2KO:FQQeO6EVq9#k>iMiZUUE-a/Yb%)U@S^%TW.64rAS]eP.'VHM;a^V2[*\&#TI6o@plI2idcMd_kP]T(b?afcr/p^Rj=98&f[W3pBpHI'1W![?l,/[dHc#g-(q0keaqdbO.!2ZR2@)Tdq"n(c>qcC391J[9;<]:\Wipk0Niq4Y!ia#\Rb;mig)Eq*A/a6/gGELXO`_GEWDs\u#AYh_O%J6gr4$I,/QbJI+t]#pm#p*q$6!El'3]D]a]->L/$/rMOf6GA"+Nb96YTd0SC'EMT7&]g"Ycro_M.]].Z2e#K%,c_@k[<6Z6FFS&)8lBJ'qo4Ocd3pWrM..DqJ<1iL>]V/sNlAe#^[H*'GVFZ_Wkk[s[rL+.)o!Pq)VNQ]#-.B2WZg3\:h.No!,Ag]ZiDT;l=(#a)FA@kn,T\5DkkH5C*f(&rWS+d"h%lIR?S6c^r09+YmHTI.O65@t/"-=,&bX&%^8eP=(jZWT?8Z,+JbV`P6[ABS+"JX(VdjADr7'4*@2H#FM+KSD*0U)E/Lh6_Mf8Q$_kcoAJM;W\"n71jps[@F#"NmQTkGD(^n5(Wt0-7%H8BSXKkL+'@JX1F#B<(Hg7JrcEj:?J1;lS:OLoLf+`Fmu9qO(uU-LH01kVTOkF1kB^\97I,*NH9+dn;kRXfk_j1aYj[0$h\.:Cj'dqC\X_//XtX),`N-rq$&Jerf"aj,^Y`0MN!,pG3jb:*ADo8,WNUrP7P9lF.3(L5@6W_t\VmFs\!Uf5KP/;QlQq3i!5i7eN?jDKW9q:]'#\MiS<-2kT*PsmnFT:;%A$u'7nW:$)Q?T_r@cAc7GI2iHA3ar-n-6QScpLeRGkP`(YQfdRslc-P=%jsrhUR.qTEBNV@hKpCrWa9!"&!(=Z9'OM'nFUCp7X3O'kSC".k;!q#Vt"UmL_M+V+GXPb2-Sa`G5\u?QAAQ'Z_Cu)O%^Vnale]jDEGBca.GH+R;R>!#5<1S!e[rP0X^QPXjOT[\iBj`(VBFDu"l']9`dN@f]H3k)X-1)2.$//Ws&V5b\L.lX5BKB[.FPV5,2e=cUnSmEmr85pm\PREn;E@+@j+6ELd"`m,*=e=G,]Ha7@h`;\B-$C,/F%B5-iSak.Ad1B$*c=pZU#JrKH3fYE"eE(A$<+psedF#]g\>[1@KKo_EudO5]g3c^puY8J7>q?a#g/p*HnLTCm8'4/X-*gO-E^Fki=(Np^2fp2YRD`eic`1H0BW;#UU`pudDK+Q6^4WA6L4AR]5,AcB/;W_P<:SA=Tn>;dA@KFd3$E_W6H67EM./VTB"MAh4D)FBC6=XJb$dn;$%R79J5LdIs/bgAmYIel^:[Y?JkPa#]T0LuB#Kt6]coe_!$7MQ0*M2iVoLp5)m)0\]HX:0hmfIG%a/C/.CH9"J%&LhN=:h2:OaCJ[5%C"2e)+FU^M3nTb4>LWs8LiQE^qd+oX!<8BUkp>CmWlq4S=[539e/5o\Gg@%Meg1L*tCM!-$-7-@9;K[XS)_k-F%gUSt.W$O"[=*=aTZ4X:`j,pi6l)e_M*>gNOjak8DrN2.M"^N3k4r>2%4VVh%HiqJJ'B=U6%F\J)I#jK<-#PdE+@fYC))MSjX5=feT4M8:kP!+:E4Bo("X[/`S4X2,UnYT%i0dLt.T6R8[iCXs8sQ$Oga-'FQJkL`Pf!oEA4`)DF8BL1dL;UI;^bP#NY*TB?T1BgMK8.76Y*#>412toR%G9u@h#j`s.4dr;S-^Fac."OP\5_840HE^2^)m9#ho_50Y"8Mi21i?Ns<2+>/_qE.u[C?4@;H!S>t`\0j%h;^9#3[D;.sboRANDjo/'JNB_Eul8c6$F07_^bTRP^m(n!qha?g;]d9AYG:+Xq-?O8>0[,VR"p-2]@Hk(OFTl=0;2HWf7[/b[.Bq3R'*J[$;4ViB#'*HBF#,MDYmh9^O]3>n)Gi,tX+b3nN4:";ZAQj&3GRc71mp%qbi9-<4[OfBlbcN!m+n_NI.amj>)35LOo8Dk0JBtfOi*KF,7_M0*sZi8W`WC4Y@cp"VIhZjj%Q-R_V(=fSUnDW.7a0dEm_29ftp#,ICme.<=VN0$l]7NPe!$fd?ap*3+ZSD-QFhYB/X/ih.LHNLi*[GP2KoO.ZXS_RVf$SKYL0k;e%GAaVL$Ue][9G%'g`neT0L@rE/3LpA6bK*\UsM>mChAGCM\[0s#*\^Z5!M&BID4G(j^nUHc9R@6np&4JlP+Ij++oA8T..*pK7HB;I?Aa5O\t3K/49@[E;q/8h:$gX7Gbck(5(!sh=+H^UYV_@E/J#>I?CM(>"8-@gNac9]4>C$m"NTbeV`%!"!C$&QL7%YQOFqc_l8a*7!_`8a(U2$(P@^J'B3bGRkG'G!U691H"q%j]qB_Vb`o[W!`*pftr9jNKbqjZ;6i`^@217"aBdLE"n/H1Qdo/1g]@;tf\+C8,rP>%5YKrsT%(0nA>j<0E3A-k<3_+kfW'/l:2Yb>(M?+U2-<%"F.1:1u>2FQ1M&H/#lko^TgY(=\g0mQ2j29JQ\6!JV[NDB/-)I/39k;2DM36":U,W/*i'Ne,hPG&`mno%AisCKWY\$g0K'fO>`!F?5NA=#N"!N"I?p8'QZYc/FnUVFi-[AG7kn-]_R$E+asZ)qn;'LhDR'2g&9?#]V!"%UBK'X`BC2':cf14NkZ2$/iI_l_6aTBrtC$QCD';4ABLW8E:597953Y%nX^k>k0q1m1rP(pd8s7#:@A]L/n:=XdAUkd[m;l_h=VW9WiWg.)n74/gS]gN:6qs3+UIn5kWk4Q%(K"KBC`$Uao6O>0+i3`:E;/_m8)+nqt0(Hf9:'!4#9SlB0hS2LLj4S<8["_o0tnV8POepGF1_,]*4Na^LTM89$;<5dP0$(`X+WJ;#XBu&c)*dhr_Vrjbf^>.l6%A&Ii/#(5,o9f0"Nc@]YNhXiQR_t[47[5Op%0QQ03YF*X0P:+a]N.UuNIfc5V)2`n+fso4D>IkSccMs%O,HFN$7_1*qY(rScc#Rk+6KTLkT#pb\Sa.^flnN@;FZ9t4]jXo&-_'mVE--,TRX(7_BHH8\6;nP6!gq\BRgg-k`#LB+K=G'l[1u?HE^sZ[MPaNlne5EI`>QV-LFKQ-L%2J$gVHY<(@nFtY1RCb?T1lZZp3(UG6`35ro&Pj"%?oFmIf:g$hc_lW%1JbIoC@&].u0-Y5\rtu[oVLr3L.si;f,aud"B&EF?aU1VHpT!F,4!TjuIG%htJ8f3S-1d@oVEb/NCtX(o?_NK5,32FB5%U64IdrgkCt,>B.n7":l+?8QG\ms3$$&Ne)A3/lR,?p,6NQZ:5?9*DWe.``\n,]*oHakba0)1EfE@0ZD`c)j:^P*QU_%n3716Y#.=ElR#nNDE5dYh*M-Nh>&+Odh@`B;=sqKH/;7/bJ][;jnpf>_8%^_F]b"oJkMH'8Jh[hoH/$(C1ZE7_SQ&I6d%qA"Sc93Q[N^/:aqYnf^KH\sRtr0Tp@&hqbXJh&(a;'*%_eCZf36h9>^I:Pfob9driOi4G,k]6h'/\gX&8iIYLC[nTFBcm(DB((k")f%G=rt4Ns'BNg1BK'19i+s%\\M>^?-e,E"7"ro-KqkXI78*O-ms+l$]gTgKo[NWKOsr`JS&pQP'5A0I+J3-l[Y>kd02T9n"j/LPq]mVe]s'cuCCMD$2pVCVMXWQMuDM>591hqU,=(Xs;>#%>0W\*J1mDOqF=*b"c/A3`L0`.n=t9@LIQ+k711_XVd+^XXaC"2AS5@@'V:C@J%2.Xp(b_ejS_kp4(B>C>T7fitf27L/U0,u",>'rqEFbsRnKY)+)WcZ:[F<.lNRdTnY1^IZDIXV-FN'I%olq/YHXms%&B)XhY/^99^UffEUO@Gg5IKEddbRmL-='[@GsVWVl/VEQI-Q^tgH+l-S?,K=Qp7VZXb,C4]CpPSgUP;B+VfU91BRRh`7:t;&9^SPl0EK&B9b\J-)mb3HWF*ki[&p>fnHMV`gXhWNQlf7T/"4XDY5&M,^0,Q+mosgVcF&:@[A@CK3oK>UdT&aR9dGHuS1CTBPA],4;"'Ol\B[HJMS2nm(JKd*)!?Qb`AjnCNCqa8#8VH:1Y!j$4=alN6[AEff`[6Z2j-NZ$X<:s:gERo4Q4D)LPj[t[Dp4Jo;6EK^b:G^8uDb*/#/Dl%g>],-+`Jb,t5.6Ap9q*u'i%$'.i2S5^[=jF'ih4pQRSn@)p8L;8[-h9-,Hu%JcnO.X`*5d@+C+#=)i]MB=UclrIIIKT5<:)l4'g%>LYqVgXh7;JWd'?Bp.E?mqQ/%>Z-]g,uY1ii)c&&/,SkhDAI*36@>H/F:+r5LG332od9TZFm]fcd*XRH#iX3PGWHJHh(_.(uaOq22A(%OmBA2jg[?sEVlh)T%u*.eT+bb5#*\6_$og^E'jNQr`RAejC0*3D*[[3?6VKTj6/WS2)ea.\0NURKS6A*"eg9*"$;>JN%H;f#XLJfJU0([dTTV4"qQE-7GG]9&J\,F>q&&RS,p^NQfri4l]UU=UGsi%l.8caQM!907i(g(Nc2eeII^%!l&_k:Q'A/QR72(VCpi=J#etR0YdUVSRkLr8=l6BW0-e]73B8'4P0)F8I$0/$Q:a+91%)Q3WqL5;(Of@2\5%=ReH9?9$hWRuJEWk_C`^1WgBPCFQtTNXHKmM!D8B3rAt=A$(u)HrKpY`mO`dl[1=8-OBR>V*-t=02X$k+FVt@9%S'96'9;=5_Ir7)+:&4o6Kl5T)gi-Qbi0e3p-44:p6Kj*fdML-0Z-aLl-H/c+IOL[?!@rbPCk7c`6oe%_@']qmkKl&CD#FD_pR:`Fmf?l=6RQqmj?)a7F`nh]'%qc?I^ogJa@T]f=&WVmTS-&%P\p\ii-bjJ*BP)FBH^[lt[LUWAWb7J1NV>>FOV:L.4`So((YP+kd_c(-aO[X5unQ)0s:nE(tjMP*9sAu40,NpmYoh/5_e&B@4;euf+V*i:3]*KfI/[9&79jR$3a[I.If8h`o)4mUdk9.m=^^IcSmhfY'?#+dF.[?0O-@:V:&F["Q,VEcp??:um^p(*AN-o6Gfj$\m#o_YKMVGVgPj[WF^a)9,mS1^:Ff.C+>eL-s&a`F&u]Rdk4To@2gr1'hq\R-M4umh4I:Nho^Ck*#N9#B32t3`r4D"\e&&:Y+O6u$T$X+8l!::U($?)0nF5c'-]N"]@5g=!h(0D!554^AW\m9pq?a],SmN=hN?]%Q,!!C%kBbVe>h-qWCiEm'HKRI-j.4A&5^NhQAij6AG=9ha-$`!D]e*=TY#mf[M,fP3qri>$,n0qt&`noBSl3O*^CE`Z9]J5dj\9ll'RcW:oi-,n&Q8GkqjePX2b^j>^q4t@nWG#T'6O$<;eOFr&I$U+:W*:d:;_8=K52Q*=b+P<:Z2g)Xf\Y9lR&Y*6)c;n"8X0@],!8S4VYel@%Mib>+N[1CZ7LGtg8bm&NFC:VQ$&j*&Ek!`FbH\pU,TWDNNbS-cL%1DkU>r_VF2an*LCb6VM+E]`NcED&rN2-6A<;1PDS2*WFfXGi[IWdiDMHWKZLZ[$#nqW:Is7X$0?54U#VUg-6D4d5c"EroX\[B4S/2EPHq?#,$jI%k+RSa\dTlKgoH?Gl-,=-fVjmSHC!^,:f;VA$#u5J^,fm;Jc_ET>Go]_n_ug&;?e?G)]bgfN?NY=1D$RrIt>r*mChkJrWJ.Qc3T:V:`WrHlICnXg77*RlF5;5[,.:S7+JWPYGXO3`Y!XRn6r.D%'+Af[&H+XmY@1EMDAk'alr@CjoO/bWga$S.,[VqS'#hC^(5"LmtLM<]VPT+65\1#82-m\;qh%>/uQ1>\>K]df-bWXU1^O0Q08T0bTnXjn95=4-QcqC7ZuV]rfjE6$\,;I3/`jR_O,ns7,4>I@!]GNkui=[I:lc_26e0u!&:P`:ioPClRaXV=JV9MO!P18auLDAHPL2d=()inci))8$8jmgeV678fkHEJj&Na.J\,<76T8Kj.@;%)1I;gj-JD%/MRN!1"D6?#k`B"54u)EB;m14t3rop>s^-?8^g`cUZX5=nsSp[a*Vgm$KD/M5s7P3B(?P1mQ,%dP^0@AO%M18e@l*3M[QKC?)dpK#b74kNV,,6#)/N$neW9hpKSJd8V7"&(!ZCBGl*1%I+*Of$ATas^_5>P(uVqnE']M,l=?aA9dbFX23e8g8C,#-*2/rGK8YZF!dHs[%Sa\!eu)^+\298i.\-7*f[:9Aj-/Ree&6mg:WWlZTA1lYYqS0E=?6+LcMpA@'q$ucK3ZL?[%t(j!12&eo^;=,/O/;V]BJ15!mi;OX:YU4agfC9XDrZL+uj.dVfaHS(eb9!&QQ$I!;0;7nQ?'bfbb]%B))Ve1CojYptXBPDAQ;"N;r-q']uaJgn(-8^1XQ]f6Q&=R\EC6h2;Ot#X(h]iZg:Zs,(3dpZ98`eIlIp#3\@!_`_7CFZSLfPnnO\f0Tlf_XECCt1k'KO=jX+_#V4sstV7V-OA2'hjhWgjr>L*_1cFlPV-F.7AU/-f:0Ta&Cd.NUsrAQ@*7&;c34GdFMk(U6ZXX+S+mfS:>&d0I%ZZdSf&R(md>e*rUC0]P8k=Ec#N<(eU1LN=q:gPiHs/bjLaCOQO$ZL.('BB2$mu^es3EJmaCoBQOhW5'S,A?Ss][m,BN!0$2CsVmQ/tI"if(Z.ZBV/0pAj5D.3FKrAt-@heD=-Kh/1ELag%co<5^pPQs._(m_JYpo8Wo^b6AR8$?=Kbr,b^O9t>&beAZ*)dIFE9kiJ'/r`Pb9ZXO-/[[;76@jO_H@I78M$UeRCF0[p3`ugZ>kcV:PgT^+SCS!GO=lTC$'K`LnR+Dpsr\K,9eA.KE]mEk%rk818W%7/5TM\n)o-I[I%4dq75Xo+j,I8m.8BjMt0dWj6+]Lp:tlGg$[mA=O3"qS@Z,W>m2]X-B%;hH?d-Z(3Sr"Q'X6<"-LB:T_j5SqujH!l/1B8B4NaVT8o@Pj2Zjd2/M%1p+O&:X2\2.40[/#dUu6&s,&fmOae5Ab@aUdC7"$h>YTR`-!WES5YD!Pa)-NZ\qABR.rQE,N,aL]R,t.h,i(pCb%&&3d595^HZ_cf1@"FU]"-"r'1>j.Q\nl17&9?KS5,9Urj4pp(KIjJq&9PI.lGWr")ZNkn+8Khr.GFIW/mm34EtmDIIkp3S75<3*?o#SD&Y9^pdD2*;hu)Y]Or\nW/N4,`lFcTl030B>6As!/j52U@!!bPE"Q-crKk<13eg].liO,,3i;GC\(N)1*2-H&ElfB&aDr"_D.R&\6T^dH*8lIHPu9-,_#EP_gZa:n9f`>4p()QODu(q-me2_,k"a_*6J-%+^fU+a7b8N*,Im6YB)Xjpt;X)b.1dI]bWRle^b90DdO]rUV'l)'6*c+eDrn_Y-%h\d6NbRdA8<+$0!iDG2,qg$HUnVX$o:14fhE64SF@c1VY26=rPWp9p1/>Fs&K(#l$VGVoFPIqbDt!@&.uN;W>Ia>J#4$DjJ#I_WqK#p4.mR*WABl2H_4Qo]/40">o7d$Ri'T__7V:u$UG;$Zn=OU+OML#$2aW_VhqlNWn3b2IU)iPD9OE5TEZ3t/!Y4rldj^rMX_#])cL7#D+.NnK$3.#/c]nJNe;N[1UX3Fd^cd#WM^pKk#IfPp%2"ia'?2G=6s]E-Sb&eB21kVcS\m\KS8bb,8q[>nZo;<"WM_@g>-Pb%=_Z!cC_S(>cJ;cHb!MQ2N8\>4/J8R<&@#Q#(0q/D@eVK$B<6R"p+O@>If5pn:2O4<:LPZ^tKi+5iVtg4_P7sF,Qhs".,iO$?HIRonf)f83Z@j&_pbN9DYM3O8%+X-$"Mtl+[DJECO=prD8'a%21S$K!ckfgh0.\Us@b*"BtJrAo4'4KL:Z-[_Z985t/(*%+/C$D=R)\]iDCP:iX;[J$c&=9?\6hpE^+/Af3I'Z(djap]6E9IoCKitdj-(\QcVPp(#Ke^[!nu5f0Rnl`_7uQ3n'&n$Ep\4gmDG7*Nk-Pr46jHQW3H8:R?s]s-Y__X%>&X_JS0,Ue+.To.@]dje(o<&W(EPDEeq/TW^U`%I!cEgF[VL>%JUm88$?J;5K[hnqZgbrhmLP;_Y/FD>.g<<0hA0cE9P.RI.(+.SkY@B5DA^NaigU*+MpkEk'_k,fo'2BXaC1Pj:n<#s5',nJ%'cMe17F!G,/*V$gs>bB-:37G+=?!crFM_*$\2ZMt^V;PdkG)FG5UOq<8W0aSJXQ]EtWOS#Gh_hAWiL,@+ePsNGEp*Pqm9Sd&lgmI0mQX`k'e/BeT!8c02hdodR^HiFDg8bN\U@edb@`2rH6G2$5ZIg6WFFb()?A.ZTWG9R)KL5MSl#C'MuWPW:[)gJ0QP$3<]^+bDI=l."JoK-W6l=?8:ch`TaRWEAM*_!cu6!orD(DAFFd'`6?o%H?kgTM6bPXp4Bdj=X-0:@fg3`S2pV1ZpW%fMas,QTKp9;k=YdY`qIM!.l4MG3jU^g;YEAD=aQ:=oN!uSVaC;[uW6d.pPP!07L@d,^Gd#*+V61k:nTZ;kt\?aP#9h2ISR#84bIcjQ+dC1cQgBgiqp%S6XiFh5)M&8Etse;K8jE;6sbQ_=>=o['o_%Y0ubJXLQc+?JCU\q)`$,na#WcI1,1]PI;Y[DL>qC^F)(fe7s_SJD6J*Cn=B`\q&g%#sS5=gG/o3EQQO`r-5RphKttdW.t"NJ]b=\n>7>FY+,q+Ed9Y@ndp5XB]S%Y+-VuZ?UN7#^&9A:*aV*O!uTu6]45KF4>OfQ*5WAa$$)LIk25.AoSE/bC3UG%"&\Zk*rIId#aAhjZq5,U]3V8F7uLmDb;0+XSU&eRJU)'N#f4(/6nEu87Go@!J_>DEdQE?le?=DiAIF07S*b6:BO63GT5VN=([iV3Npc(:2/h-6R.jlc_gNFRI2T"%'sd0jW2m]e$Q,IZu./ZVBt^m&I:I&[hF2"[=]3Z#3Bf`nh[Qb$6.o_ptRmkE)lc`uaee8Kke*Q#-u@(Ir2s%lOHQ0+P5;3UgcnRHJ?"8Ar%>U=HD`Lpe1#+Im"\RU:Iu.B^,!A=/(]_6#X*6H0G5PSkRVcAh(_4`.WN7gOHkd.?,;M:.fO$9]H4OM;PnM5h,Ie6%Zh%n!B`TT4SQkO[t-#+8_8loJNG-:0@7`>2!hWlKG`8HNJ=bPZa61n$ZJ:#<;EIUo/k]Dak`QHn>>Vn*L`R'('hh3)n(LE1YDn"Ic%ZNkYXDZ.fH;M$#>!Z)VVWORL2gc#B)7.)Xa#"N/.=pra1g^!,;=5QI^!5@#?bH-Fo\.&MoT3\0-EH.=i,b$D9SI)0J3S6D`85"=[Z>sOdFYe7VUga$C@piYi0sW1?Blui5E=ONcE-3;_tW/X=MTHA8+V3LB9SuL3W"1;n+,jo#(78q%TjR,)B[_=MW(i7ING);\IH%Ij%^6HD,Q2(aI'+I%"XUb(XX!;lMIC^OEXJT">faS%5__1o0_EBr1nKK.]C5Z_/mS0O#g^]E3S-:D8_@nD8`hX5..YA1b+:fBG*Ro3El3hJbqO9%8/>+3QWPD4pW-@OX9;o2o@kMcXNF89lQ^)i)lJd.Ya_QjDk'toXorV8i1r9*MjBGB4P)d2])hHNA1N4MCr==02EW-B$g6!W;_uOF+/Zp"XqJHA_I;u8c3;+b(Q1I:F%pB_E^)ZD/hj<3rsLdrh&9-dZ_?]Bug#UiP>(`Su[Rk+`U.^$c+O6^m8k33daj.e\R#tLe.EG:luV,O9d/,P\:ti`Y]n-'At>.$FEJ5q=7;0rc\MNbX^\S2E)@KMZF6UXq+Li4=N.?-o-t!J0$^8EW1(/E5i`\LI2@lRZJR^5]nn&G_8U_nBs=W=eFY%q]UO`m]jPNKWhHWp.Kf%Ln]ePp!`KVj2OC&WaE:^;.VFrObHD!@6X-AD8=1+r$0bmH>76E\QSD0\84C_9C&ML+bsN7d%qHNHqtYST%El=doR,&dYarqWoGnq9bZ[3cJ'1]B1OaZ-n$I]YcJ==%qQS[LYS0(`^A.,mF9FbVcO_Ue#*"]cI>?]#Cud%9s@8UOUd'Za/dqkCElHI:T#3Ebcf"+WX+)_9g-2_*]Q.pR8,#A$NkeV-`;7=_0J(.5(R"['$)+W9sD)&!?4gJ[N:E?bEIg_P7GocG89jj['j9qAZ"GMXF>@8jd4C0L<3nP?nnK0HtH<&C6sm]&&d!hMn&0Pr'Y*h4CP/qcT;PuP%K$>ZONir`E*h;s`=Af<,4SDODJ:?i(/..SLAUtCh:@S%\1%g;PR_[>,6ocj_IKr's+2$&X[.R-O#%P[^b#b?UH^L08Zd2E]7>F`=&ctG;rAg3*8>3s9gcGJU;I?nadkO2"'huWO["7."=MBs)`!/Q%Y8Q&S2'Ht*1"Z(P8h6!dBrP9D;gkOU=c<_X=i]HPP-4Dm>g,/9h7"i>=akVL2=GLVF5Kh2:f,6UHV`@#-!Tqi!XF,,%'dhqGKGfOA2`i$fdo)RZsZBt!hWl*7"Ge'nhMnN*O0GbVB;<^gpG4+Lt#H*eLmqIAN\N$bT4P$uh7a,HI:eKKl,P1"(p47Ce1`b$?YGOQ%0^`dKD3/[!C/AOiIld.-Wfa:jP4(d]'F7cr/sb6iL4J06a'g3CNrl)E5Z,U)i8S])9L"mgMMcjC$:0af_Q!.LbYG"Y]:E"`Y@Q66.3a[A\"++]l?'rI#k4b6SEf9.j_FY]8``5h`Hf9?eYCYSPt@6c6#&-c8&u64:5C'ED)iCiedeJo)Acp^!b4ubg?!:-F&I"O#Si'mi5taMm$KOQ+=DiACnH?!=UH?2hO1RHc/!'FY)kr+Rd(^_rnISk3tP;rp7PMsSUSlhr0Z!Rc5?MN9@EGJRtm2RJsd(r`:9YZ!=aShfb5)5+K/8R*kHbo+CIpeYXa]WS]=6E+mXOqAlEK7"I\)nK>o![g3EQ258d&Q`J;&6bNK!E3)j!^_36,&Jug>Q3.esV1;Zg-<>cp:108?1h#W*/I()4];!LIM#r3ElQr"J`)MWa$d7n&#^7\S]MF@62d&2:qp-^il_C?U'*Z85@hT#tB_i=sq,]gDECkj&PV^c`#;*I?D3=#r3_aL03,`)NnA1!oU3#cVb_>*.q0dic$0K[>`gOr8r`a<^$E)G27R!KWZcI-1=0jMkt#bt3mX2"]`,TIi190NBDdT[FHn?&nrJgi`EUG@-A.6)7r?,GM.qq_RWjFIl:0-.S\nlQgC",^sgHV]-buW'1CCTd(UG)*@sLI`m.=&Xq7J7Z)s"^i^8tPI6qJS9k/&M-9+_RK8WjG:Bp5gOSV%'E"WsVOf\^hpn/d_.#>1[+5kBrNH`%JrF+O.%d0LZ*P.Ih?bVL*E8Y5<,6NVXn*5!&*+iEcMXRF_.ku)ZA/sW6(%$pH&j"&O(=s$hH\aRF"(Tb`)&__/[(AYeR$;jaG5f!WW9LVOC<7qI^T8%A(uFNsDfACp&AIn*7TYc!m5(_&$f=Y_jNd`C5,:&paD39/jH!.sBMSlRW@`Cbq"YuK:.0%X%cYK+noh*#\gDDH8/74a7=_2,YX5"34apP\Gt%X\8"CTe;##10c/\?8Hog6VeCMIi4:Z1D8:.L'I7$>F2\JOQ>75B^4#@peei]Y:(S'JPhTL1NQX\1IOX"%.Hf]V.i%cQ#4Hg9M=OD`pKFkDR8["+u;^6rWk4YI`mXetk`^ScQl"T;U&VJ#/h&KbdB\Kp@15$^[ncc^m#?2j'D)o]48^^e%/7'+>b@,*H4"?2M$*i0pf\:I'3&K]9_&;jm9>^I#<)aluL^#&-nD"\@H59"D(p@V5llo=3+f#8t5J&:AkYIK*lOHmFVB6j,$e)C'o(\'SD4ntK.>hl-rAP-0<$tC@*9l"/^L4o=lq8(?7bSu#9aM@=$!>m*E(soPu:Y*h;Qn#XZ0:YB:*NQ5CZ*Up^dOA$@GHX=\uE!Yn\SDMF_(<',Ui/m9Pe?h#Fk:35NF@^H0TdRjd9h7e1&K?P7jOrM5c+cK(DAI7.sA0Td_dN!N16$YY^8[_YU7"N=Ip$P4r[9c2)45kUV-C!dEkT-IGObJp+'Ho_RS/Tm^!*r6V8#:Q6_&XQ,Et8+IO`*O!Z1PS#"7&^F][njuN8l!eJ"IU(mmnK2OBG$3X_^q)i#brSnXl0@BWThS87)lYP;!GJEkAAf(7RiBQSeVBp"]hX3V`7E"Fq2%^m8fPf1FTCrNn&3URm%i:$5%/tid5Wlo0D`:&Ja77G\6j$7N2B=^+%5pB_^PNCU+9@.FWjkpI_rOHh;u)40-9k64`a1GZIe\8#q.c9#f.C(T-P4GSB'oBR7HkpNo6ih^j-jW_FcLHL\??sOBpdA,jPO3eVEUA5ZpZbr9MNIbh2XLnZi*DDoRE-LeN3L@^<,=u$2oU1Qi*"l;dmu\51h+ts/'t`CC\u*!TE!J^WXmDKgo(WTO8.d$iIs-"'cg#T:0JOf!f-'@L5Z.>h'4L.F#[XS6U1^PG(435s']!>8\B`nD*K\,e1kTr2U\TBc=V_moj(0&;)6a8EQs,^h@[/J%18XB;5;dVj+7"[$jFFK!)(^A"#t9b^6!D:j-r;=uc?_6eO/FnWapDTYHork^MYP2tZ\6*"HCpk]%p]e'HO;]8"o6Zk'Nf!$p&J$F+6a&'dde\.WN#J!9G'R!&@l>D>S6-N8QJ*V'X&2@@6J9r9U?3lbnJP^"aZsUp-CrZH6t8#t4He/%4G!3$u0pWnV0$MBJp.@d&O2b-rEPcq(LL!.Zt9XIjGF?3h?Y<8S6ZY=\\UdrD?I3ukJ*oubU#r[N*N8s,VRu[!V=YRa63THd^NNKYe9AXLPm>L\U\'#X!8^okYT@)/K`%PMG+PVJD+s6.3ph]'ToPHj`20\BLSD+U@3d0c=]Uj%',!5%MV*_j(FId@ITu27KruRna4CLb@fs]4c]h*\KYC#:\7QaMlpP<<_)Us#tfVfQ_[roCJ&5mhQ81'rda(8+Z6Go;pU?^:4K:!Gd7h=m@E!/GU*CnUJfASMrWI6kIt>r:"XhJD5K)jdjAe1&jg7//knPR?k[I?[Ci&^V,"$$2ZmlLii5+(]k@*Qb*lQ<2-%WP_]<+Cn2uO.eR(cf?e6lZ[@3PTo8pnSn5sAOm/Hk/R"`#eJHda3g\JH!X&P>6kQ>HG';LL%SW3c3FUs=YhlCs:2-L*X8KqP,lchHFESC#mc74s)M0ZOP'1GLHqf#HO6kb!a,K9dmE/ZdP<@=bU8,<_UomW?IiSI3N,JlnlEW)ERO3K>_66Cn2Mf?>FTPBAOg!DXfDD:\@KESGC+,rj(Q:N[7MgXq(e"33GFFg&F1J?ZG!%]aWeRd-2,k4fQoM(EDm.tT>K;s1L9jlT]WEu62agY3o:_P!1t3A%DD*kO:1<X_eOnpYXEpX'e3?/#[pSScYMT0BSt7I.&,4Pn?,7f#X0,mn2\](O?$)7q:E%<5A2mSZs"g7)iCfnuYU!/Uc4oPm0aXVK"2FDS@.L@]0I\@h8*FC``FT3+o\jJP=K1h`s@V68`%acA`'MqahT2bDg8`NDZUUdi*K&>:I=m/+g?n-TU4\GInZsB3e$Nl/P6L<(tKPHeYqNMSTKAoRN&JA;'ZnTD!auE*!.0LVeG3q8FZEfb(=D^NeU2M*0@CT8r)k+-,e02#NS2XrsH'4s,*r/("qBq;T+Gia&c7K`"KGI+dF8$7NKRG)c\fI&$.9Bq1tMNpA>+>E11I4mc?8Yf`d%oMq-968i:a%_=?`iiVrC:brKRmoE]$J6-/A>J9d@>TTYTQ9![!kPp+$&ko4Kjepj<>X+4IS:n0F8$WnpD^q>%9X_.Xk2d7Yr7CKb-Cp34]sseEoNlb[mpRVDlhJ-S"*#D:acpPsS*6+lesS]lW-$:8\QP)i3Q\6$<2n="F[KI-KbO#HnaSTl_t6"(:I(?^l?[RjW4A+?6Tk.ol`"I;eaPkOj$C3.2LVhdAuZk;dh<.UBE`.8fLSBaqV#s.I?B):JSakcZjA7D;^g&l6L9eJ8cKi7!bW/dbH>-S5Ltr'rUG@0lH%DHirdIW%GO$&Da'oV5QWW7>1a=e"Ve!;:&V)pOT=GCb!o!U05u)a?_$1ES_A7?mZGM[t3Q+oScHX?.(V+lB%dhl5%?]dAA?6-mIraa\k,nC;p,^FGd%(kV1Xp2Em5B`Id&\d]8n@pp*Y,M@Xi+?NGTXgeE2PDPS/hnUmGap$%JnmBhoj%Fthqj!F<)+j-/9iDnG`AF63C:S'U(_U4'dUdA4u\5cB$;>Es!(#*qg0^MouP2KgX2MhA410O1b`/NL`,^ClL4cP`I61E?K'[m8Lo3HRL[b>nsU#?pJ.s73M5*9QJN(FS>^!Wb"58pHsa*A`$;&'/@kEZ]E+No@oton3_0NF3-S63@rhc[![=)mF]6mdE]PE-N`!0BN.9tNs;RAL:>a/-"m/-SEQ9Ha?n0p=>SeMQN^pfu">VQ#'(5$WT3@Yr>],Unh?6,+HOq_3>lr15@PdS0&rXf.9lEj6Mi%H.iF5`'l,m:5[rkhBjuikLX@do<$paCA0HWJNCt2LIJlEp$3X*FDAc,Cojf6DU8"@S>SfIq\5ReM<0(j0e)_eKKk,P+*#F0)"$k=[PQg^5X7C'.4I"2PBB@rh#O/4q/pQ`BMK\SuBU2ockSE'A^:?6B(d?2/to;FJ;8'$1+D*!YJK9G,(SN8\aE/bNnPpodQ4d@n0IuF-*:MP::%7p@Z72>BCT1V,X:SU"JnO:qY.qu`Q+`>>K&XJqXS.hmu0AW20V")TiY'8fljSBQR*SV`9CD_FM%g31>j@'D)kWC:8S'Y>n`WaX/o1<;klfTN%uSKFsB7eaG(M!(dhkgRt/DR5FCRt#,LOa&QIY:;7;W\foqr6!k23rC3*%glFU"[C;1r,W]eaNd$%+Xe.gZT0gG=gKa16Dgu\LRaUk4*SE/(Dfdh%%G=p,_?:[MGR5`,hADn92&Y0?,68+Sb$IQkh,Ar";;u[mF.%p%Nf0u59'l.L%1&usY=u6).4VtZ=Y,2'k%>R2b?o/-d1UCJhl4V=X2[Qj3^,[]RW)6pC2$!YT/,o]1Ue78fqu5=N9;:K3BY^mf'XfIphTTlbI8?.K.Ojc&NgMSIXrd8rUAXLQt\joS+nGH;^P4r/>KL@FS]pMTT,gFd'_M@K.s9J#j"!:NGI"YXB.(8G?cu4bdNbR9S6b4N+i7OF%1gjjqV@=5/+^Q@ac<+`2s/S>:t3@AGfB1,^)8R"+gNXs(c\'rkG2]^+\i&bZ9,PV>fA=2/LKIAO=bM+rgS1/c6P:M^\6P>?lQM!gI.O$WqD(K9\qlZX4+4stN3ZYEq?Jf;^`DV`%U"ccCKfo$qHs?eC:'j&,WfO\$NU_]3MWZEC'@reI90,B'+Uj#84*AIjE&3hmkY>EjUblb178Y0nU4X)3bTi>n`qCIgc@'6?if@S`NU%+Wk>%2(HjVXMtuX9E'D_Q(-")_;EYX??`0l5eaO7+I8%.'jFmHjcg3t3C^A+M]>jR)/9U8l=1trW"WU3<5.q'rj1NkNF_5J2k3;0+5mA_4E3?\;b'X"r\Zl!;#QZ!g5e#e@G=I)W9Kf\F<_-,D.^ZIXluWR$W:V72,0oXD>5&%2M9n\4ac7U1j_K-Os9dha:dbh"ZbjhBU#_h-.O'>:lh]?`XG^7LuA*#rh]J?g2Kd\jiQW=NnpQ)-!MErf+UJF8;%*t3MsS>j%`cU7il9DcI)mI9V)g]jhCZgfrcoLkk`ToH1c#uPI_$%+-f_UlB*^]+\XVgW-&l<^m9fhf+oeUikEYM2:q9DSTS"'IqV4C9YT%gObu!-4U-P(_65]&6MW,dX(ZCMK6Dhp=1ShDGk,:.rsW[ZSl9,bUt8^^AsH?gW&F^q@a6UdDSG*3iha'1oj5]g"E+AQh9QVCs0TbBEGb"RVE/PbP`8I%sW=[G4s5+Z(p[&q5@SU9<*8h`sZ0HS22E+l[67Wt%k,At[Le$!1qI!LICR/5BqkXc_4J%Teu6>2?YTRS3Ja5&eaa3W2J.LmcFp#rG38I&$]72q*s/Y^W4,H_q<`YPK)jg#ZGU[]=\:uk&B#A@^9h%rY85cKGg8?5k^(HWk7J2qSIF[!+dAJRus1*n3m`=S;4<@a)VU8/b#8",dHY^4I6at59J5:hl""'!1`/p!jHQY&l#R,I5D'X.jb7Q)R)HoOdfVj30X.I"VRubF(!IMKAoK^M$6rS[kkMAj\=(%Y;Cd*..hZ3I_h?QSsq9?-sEr$s-CjQ^?'[B[a,K@.Y]m&a+Q)YM%;pq*g[dA2l8S>2Fn-SQ`gXqI^.M_B6&+50LAYamH^7'c`io@U82\jc^(iY6E:kcY>GX%lcLY0uUUribjYj]KAr@r-.a_GSEg>%+UQJ#QiV;igp3F;HZ^gkUc).:WZ.0BX`W!3.jgDdpU:$k:(qVU:Mj=&-I"+&Cnrt@)FIbTk%gcGR@\4*#'Hk=>,&!l)_n'D0&0[8]rV^Ed++F*'ZAgdL_]q!jUZE8FTh+.KD6&gu.X+EnpP\0'g3^T'p*ncQ-'*ClMbYVm3YE16t@1j-@aE]qK`K-b#S7duR,+Wi!/h^;QL+QfKf6^*`3,2N'?m0aku>fAtZ?ZG^c&pJPDFQ.Lkb)c&6Ld?Z^+J73NGk)'@c7Y6[-WC._+5Gkb`kRnNUuI3">Bd\XX)^`Zoh:_jo$>(@)H&>SlR@MWT"n)7`,MF-/BP_H*ELattG3K6JN:88=Z>ah6#Z>kK:SJn[s?L`s5s2r\>Gd=>b8G[#=5jD#jBiVPYW2RB'%u_#Y*B,Q)-'N%tTo$7I>$KTSP!,7,eqT8tSl2pRkRa#io0E1eeV7EBstG&6A4o+6jk_LS@8MD6S:f1m)=;\)*H`O5rY2U,,Zk@n`fC%P_ro11;MjH`lP]NHF2+g^T<#=FX1CK%/>R@lBb.VHMmsG1^g*!Y*\XXN2R27/YE8+<7#F@c!E_7Ths)!.60Mj-JdaiigWYtg+Mb\M7$9ouLVhOPn`2A3o)ACK'jn)WZ8^=6]`+L$#4ADX48.IP*5.Y%+r_npPf9o+5iQ=R&fboXgCbc*>]DG2l51$CU(7UCZPR,DZ#hHAK?rVj-)A*X/r>.#CcGs.DG0%gS/m0$dP*H`ill;$Cno]G,4d.`3YE>OFDZQB$9]M0/><$+C?oCSe#T>1JgD^n=lY-HQGj[6BWH?3JA0OLc'84mOXiUt-(O@Dq5R5r<#*_Y"QM)*pkPP?AAr2qSSBMS`0t?QA!'Pfgm-*m:Hl3`_HHbJDb]$+k#XX[#T=gr=jkhA26BkSdZSr'%MpU=*)',elZ.#>C'1^@Vb#p0Us*PeW1'%]a;,41l]-qAc4M=TO!i'ZZq-%QfRu:JQ$B*d!!!!@MdF_.j'R0#IaF[S`5iFY@!uPZ6hcf!^$mN\&%_M^:sag'V?A$jP"X@RI8GOg\g-COgE@uhRN4MMP@FZfK@ud_Ra=qfRB4SI1FJW2;!D^=&gI*">?@]fXSd>'?'L85p=EP_m-N$ckQL[jl2Z3LI(l-8iJC0>c[+]F5"Tm=[8g,_R=j9R$n]$),FcNXl$2.F/JZ^`P*7RbqTbE\d]i[*ES^J^Z^g:=*<\DCl<.!s,5L2-;6rDTOONPQ[KAA(MIC!YS\'RF<+9R4Q\j7!3,5pGn@O6[dr7>0pLm!>D[/,,`qY4(6HJYa[Xn?Q!5@`Hsc9W^"^/.B8,Ti.eneO'r#B+4RLX"P+,2fmc(3J%)+57Oi)As=LZ3U*5=@0qBdOL$5K-dskKBV:5SG(:V27P"EI0Agls7p'7l^noZV.puFoA:`ntF"HS-rM@LZ3_!7K$ORV64k#'buBX/gIq#U8>YKaimW8l^oIL"oY=Bdu,m0Uc'7M-n@[Wi%8crG7NI8OonA\RP1S1'u(bLg\Hga\l\ULf:6$N^^fe):iWGLh!WB\k:FHYo/]I[hdEgjnb.=fEso8kf?61b0s'c9]kG%N,ds0W0Qo/i]#?M'h:k(m?P<>YQtD5@L4X^lTm%4,JQ5d#pZa497Yl^'#L4e?Md/N]?Lracg8sE`A*O=\41nm6"nrLDhONLZ#k!?[D3Fj>@tGO^Qs2nNb%/$6oc`ZkdO@\D7mKoH6G^JWaHMBD>Prae?J9q.KbL"@E1W]2Fk9CHb6Q=2m.iHtQsM]MuTfOZ\D]*T=hj+,QfkM.!t>BhUj=M<%WplLD$O&HYgmr"WX*YjtKWAkI6_SZJa&L-?@GmlC/%Hju$jT]Qh8Z5`K;aJd__jiFuWKnhtF:nr\U!]j:OG\sSA0l8>&nL>(:$/eLHbj\9[io#q;?&^HP#sH`<[\T_*[s8OF\N.,keKr31g;-#H%i'5ii]mf'BMH]d.9BLW=b`mBY1lXVKHomei\9gZE?MRUef(YW)9H6a+Yq`E/K-kY!.+_8n-B`@A\0.D/#2M]HTh1>7nDY^1G0aGqbNQVYra8ubaC#iNZQ:"[9R:Njk0L2eW'+cu%[fMa)Q*SS\cgPa7/(PFHn6XEU/Q2p9C_Kf(7m8hgk=BfEbg3cD91j7o:2j[FG.\cl7NZe'_R_-0qnBhKX\!3$/uuQ`ma2"1qB\a);M&#M#GF?#8L^^q,r$rI-3A1jjYhA-s,o;!oCqi7Qm-d*4(]G9Nk+6_DF`h#E5fL8_5=IP(IY$-960IcVXOpLmPtA\X!OTkAC_S+*XFs_(%&642k0+fr\f[>o&<-B\E4ijl!;;YA#k?D#+55\9aX(d<^1$c'ea6<_U^lkB_%H;MAkD"bm9dp%aP-Du4T%sX@"ZK21DP_$H=ioODm5!n2&i9nPJHkoTk?Qr&8"s,d5!PN$pbY)BOo>51IJQT,R>D@;sOOdWa?WUqm^C(h@WT:G.*(+t[sFXt8GKac%r2JUPT(]fLgM9?nCIrQn1$"\\Jt_6Ck9P(H1[#]j0?CV_nZmLS9_o\JU_7O;oE(P9D-VcOWR@X$X89>(WVqEoc(SWXl<$D`(qH6bUb)\gnuA4Zt&o,9,nD3Wh%88WPV$bZO9ln&M=(=]%q,,O(WXb)FNOCoT&`V\03j%Y&;"*HekaIH%q94!5!g+W!U7C4YZ&"K&hqi%_36+rAON0s>j+bAI.7SrgMl$SJ6s3gTrb."S>gmgZ)])k.r'QiL7gFd\8W)uWXTXoSM6eW&5=dA`jT>#AV3Qb55*u,^tD7U('$'764Ou2"+(dB?Fig]?SMOFg!G)=)b6b^mmN95HY:VgI8kA.%NpiLkWWaG$2^oDg448IZ1@5Za7f!af3e,fdXXk[RL22jWam1mCS,E3f&?C;@(1,Mpc*cIhU&Z[=.er:'^*>"b26hiI=O?J&Q)TOgLoZ8"Wu&W&1Ikk5l+DFh?f.&qPM6uWMM4G6#RE`;M#D"p21kd_D*)jT\Xge'/B.^HRSY$*VMrZng'Bm@4^isLZ+!#n0t@1Z^No^;[oM\u2dRq]d2GIM'&JUe4bB0j1tUG;QZLKE7.W?>Tn"#>Z7,U+dk#G4;-LtmpTC$$sB_[e#NA-mJRHsk!R]^YHr;ALi=BR2qr(_[')j$AhBROr;&eB'QB=?!cRXMdftdUp3DJ-TLPF*FcUpB@k7,4<]X$=4N3uSlp^VRcotcn[DB(Pb)Kggc6.g^sTEc,u4Sl$RN!f[`9#$fF="-Gi$:LtNF5+/h2a%Xk_B@5Ba8Vi5J@A]CCTmDK+Ub0kGHTgNI!)/Hr6U"JC:&YA*c(buaO-Q1bWWP6/-I\Z\u(\u+b);8e.N2tUHde!/gkYp>PYM^kS?1Nj?nVg8C,Hf,5DIi%X<\*0l,QS8haZ6l)pbU?]j;."=I#F8gFKBIkOb@[N.^[(.?FhX9ooEZ+(Lu/m*m/Bn*SC\HH(o`AHr&f%MiLZRd^15kpa$t&p4PK=SpOtG:@?uf"X#E]->\SL79[HL;0tHgW5c$j7PV8#A8emrlL.TJ4.SJP@I#dH%NI2+PNg^b8n?NlacAbh*<(KA"km4)QDc&s(m8#Y6,>JAXIq<]"MAR@ZbEtsCVFY+3@*2t/DroD0O/:RVUVNbHY#l8K0ltNJd33@GQQraK68G[r[]c`MbmP1cej$/:?Z*@dS&UcXmE.5cSN8eF31Vjl^=Zeu-YoLCYL^jGO&Hp09SqGoacq"0*RKnN%:oV(WO7-ZlpU%T3(=@M.4#a'jmFO6G_:Za2)qChm7b;Rm(ZT*a,+!siPs"<9&YOc>Z33:^O36P(*+_nb+^+2Fh!W[X(SMldm=t53MWp=_r9og;Wk%-UlEnlT#&lWN"CEF<3*Lqt&U?6kN0=!Zl@U#l+-MKDH&/,%R@`9$6`9Qd!7Z=)$TZ_Yad2h!A[K3Ct2b&gelpnn"J1-4Qmp$%r40[8,T,fd^sT,fHrY"E7V8rn08[ed52l4T:1j2[rd_@)GOEXW,)Ll]:b^.i7h\jn!s.K)@^\O!2AIt[eY/BZmii5Y#ch0^"54R.^c";VHp"cR9.B:]a;en&Dkh2TPh::1iQS(B5%`\ogJ$D.pi8S(%idtS>PUdks")8XMM0]ad/]VO#''*$8XjQIRkIO!WaH_l#38;W6*I(pl8>`$lU`Z'4)A])ZERd(Ypc`i8;64>=^pCoc?BBHgVEh*/7:Pmup2]AWBs*q4\pM1U&2qs1jf]+sZd>XIFg]8'KSD4SK?GPm(*-UPt0DWNF;M\4B^EnF?"`oSM6J9aA'c7PO@@i*)He>kXB<5345cgVZBD.1O0>kSQ,!)Ze1fP>SUjL1kadB27uOZ&fdROHKB`O=6Qqi$=N&)lt/&'d&i"FLREi\?`/#r-iIN=[WN'Ib%TXTIIC6-mg__S4*8i=cT2O8KcIh/s5G+58]1J6k>Rl=L8N3NN?mDoI7^h[5FdlAB&1TA[,u#oWG-$Kni1lJl%^UJjC6*-4#%*JJ(?Phk^KE5Ad/[c0,A%PPgG+%FM%gD"m$#_[#Hk30:TLC`;9L<]3D2?8+WRdbV>e?je:tY)]JoBB:D#K-p6j%k)[SliVbk"jk&p1pP-q*lRUXJ1be#2!QG4%:bMG8:5=9hn,j@2m.1!+DVE9\hM9S`Wj6N&C$g<.J9GB6X>Idi.gIraQdZ/H&j,UisLq^g#23dmU0il+Ug_g"bk%W_Fe*-?=?.7"8NdjamS`ieE1U`$*g)!bbCOO3`-m&/TBFnE'1)thcfYGoO!9u"jj9,n'`sBd1.oW*rAW?j=F9_h)@Uu:Ml@m)?P7ZC;lf<4F%nHn"XHY8!UHk,>\[!cB;HoH.!>DP@2MRcPcU;3@FLK7_^o[b-H3VOW(O#-)r[%+t,:"Ie8BDM0[hWFD=;\ktQ#52o?k<\JZagbQ=es,A%mBnRgh;quJ[D>[rh`H_X:'?T`=8#SXXm+=*640?+$YN.(T??:=R\3Y]qO#f=iZ=f0X3DI^(hE^Tr99R`@Sn]"%b9=Q54ZaAFP@'iX=gi6^E1Cl+aLEK`);rM8F5sP[S&4aPl`[nQ-:D;KXW,.He+CkTX`*3`@GHhrcfI;RDEfM2@R)B]lGFINLdl2-7_%?Q%ma3RZkGP9RSO"7Bt6&Y(KUN@(C;I2U(SjC+B.-c4/U%*4,^_=390W*]iF>]3Hn$pdF2h[70H3og_W;;U*l]BO)s(9c`?I4C?0WM]>4_=,p7DNGBWOgbAn-H$-)\d0Ke%0Bhf[rbk!F((+s%\6P$L+AI]+.b(Dch*(3'9n?[bWCnaOPOs$,o,6AiA3e]=GaG`YO]!9Z(Hd#6@*.sEk"R2<[`6n,b%eSgk*1W4KY0Q:9RN^/6BI3jB\oA3LNduI$Pu0mX_K:t\eBDggm5!*/iE'IR"0Xh#c\[%].Ka[QmTcsUNKs9W#GL=d!SK'\C6;hV6gu<"9gB*0riQ@Qh2oC`5E,j402QF$9Eoq?*3qbBl5b\L1EmkoO1.>g""i7)M,0M9n-I/"a!^!kT%L+GSQ6$nZ+T_k!aUD/g1+N@S)D]u+R@))&,^;9d\>K318I.ln.#>f@7F*[^qtgO\QBSGnFT>kj@5)q=/9$d'Od!Iu5$&5S6O0DSb,$[?P^4-:THF%[Uh-AnV2'nnbFKiBP%"G>&ps0SDXnchAK\lQ;I?=joAr!o4)X^o0)$'6L1.I*,BXCrEPeE5O:G,r`9D<)EjTX'S+p$!%@0UH0!V=7m)MR4,ZE#_V]?U%D,%L>:"-guE!sUjVJH](G\V-&6o^uu&Nue_doS>CoNRYrKh&mY%^!Ng3VD&.V(U+9j45F/YpbTpIU0Kg=LiG4)b"D^uh2Na7bs$;L\aj;;>C^Ha.3MLP7A6FnMlYf/F`nfLm5-nV?!K*-70d5KW>)kDLb@br2^+KN!0;.A6^pL6CF-QI'/QfVp@;56M3ica$>m3/5IQ#IDE8bWB;7Os^n2]?=#ZOg2g+2u-*8k\fU2n[#mhrA\T?c#b?G3-aUFL%2qj>!rK)HKqUN[p,0-%;;(b1].!?"RM\-O5&oqMP/>p#,o00VqL;E@,f\cer5?^JZK`&M4Lom@PaF:NZ0Hh;.DNbAMco;8t8&=]4Q;7EY_o"TPbK?PC&_9lEp?oCZTZ1V[9t@c9ea2p9LL&2!#EO.OIfn.q;hpaI\R__)PnJqiRrFN?WiE)"j:2D*MGcuhi[&R#rnS4)4?GNXEB"9lO)D^LB9)(pV/M@ho\\'EkSSQ:'.mEs7U&Ms%%`.G=XM;(#`p0Kh5d=o7OrQ!/`8r.cCEoK8/A9e*/0n-QQaX2FK7#U!N@\,K$Cn%L7/`=";c2T_GhN]`Ylgb)Ao]I0[uT`qZ8P,b/s/4\(p?,>%-08)PQTN:@gR3%q8p5.Uk7*N0pA0*-7JSUrL<]Gjr0c-mH/A6pl839H"UsKQc>DO*nC?a!2-N*u$k\<^'BAkmo`C,Cg3,J5EX=5?>"])(;T$&SLLHH:(UZOe0.$r:7UpXU^_#/%+s%(3#6FmJ->B,_B'1Y7.`%n^)4?l!!@e,g07#8eg(_J#!`!a@dYtG1K50k@MG!lZBa!j/7e)8ta1d3&0.Y"$m8AjKbhF7-Yf.?(HrJ0_\a[b^B;>\+ODc^FUEUPqgpTTt5V%5N3'P%Cm&aqs)o,LF2A-jNg,a&_#&k.F^I^g`F^F"L)H+UNf^W-?J_hm7s#9UA-B].k:F[1)<_!Hoi3*!:76g9=b"'T@,;t5fu,RG`H+aAN80OQXYFj].JkNi6;Kns+Q0XoS=4C%5RU;`t^^m)$WqrOqrlk\JkB4@)jmf88"oFMC=BddKlp^bfhq#;UB"6L+(+DW>43.sfI=e?HX99[O@FV&lW7=fPO:Dq/JEcmXVCiV0Dn+7u'+m\%M*+0ff(5G?-W'rXV>Sg@Z&'3Z>#/*CDJc58Z![Yf$RYZ/S1gJ+^/Z8-%8g)QH0cZ"qKhM-*8BM?*=C7R*>I(5@"\E;$!_#55V"Al_'n5FM(W$].=kqE-pHW?CkuHRm![YQhUO`3WAKh$KE!jH@kjAh.Y#*h:dmNd`#Bn'.N+4TLH27g47!t)WMi4D#foFSD^efMTH"56#?CF]`(a'CP\M^_\!NE2pGI,t,m'>/:,iR;LhN_-j?r?c6?f'$%*V+]+*82H-c*+1D&#U[95?_AD5LjK$i"t\c;U@n7RPBf+UCN2a@ZQ`h`k9&=rTOGTOAOF+(^`2g\>/.M3oie8l2t>Co+MJgB03C'/3R"Zr4tL'No:)b$#S/b@N!,QI)uS;Hq>)7A4Pia%RZT2q[fLoX,RCDr&"osa@KOOqW6Z;O(n)k;JW_S%;/cJ*X^Ie,_2M1^b5:7Yl&l)p?i1_h+5Spj6Tqi5=':.\sa+.P81"?j#ChW1?B:+(XdT6PRTnZ]kMOUnXTgRneA6cagTC+']%\H8B?KH^mk&^!L5#!`j+LPrGMM$O4iaMKWepc[?P44Q.s!,:EhUPRQTh';F7/f.![a;4S75'lk)=FBS"o&?FIK1I7!(j1!rVp2qR(]mU>;l)UeE:Bl[bW/>%L?pej!6>^C=h^;oj0)\pf>fL,*J$RB25-U0\/]G,jH^*7=u1S2AR!1=>jGAQq5F481DE10usr"8.+-e-4n5-#caEr=5@Y-;.FH3)RcU!D&!b:OqLKP6?Un$TiO\+WAdH7:M.G9Q#h\f_P,8-'nI8;r^$6'I:*'e30G87m9%IY#mu"9K,Y7#D2,j:kmM04SDRYJ\0=n([biE(;J]JE,pd'P/E1.:UQ$*jlVH:kL!NK0Y&Cm;@@qc6N=Jq>!0;D`@=f(&p\21?t1eh'c#&kD$gQ#u]]$?utRH)Z@FC0CeHUY8K-4g^7`!g0S!=hY-<_f_R;2g0X-IHC(c?Xd]8_KWmYH$rag'(O6\R]MZ[ajLKob6do/B%DX=O[I#OFu(g]I-;A@fNN/\K]sW]):'FPp%-4/*YW.In;@\X#TugNmOrrd_1ECV\i];g>d;-m'h:PD?Z:N#kQr)g66RI:J<0t#5_=`\hGIbogu6,^Mg6%L'Q2afm-$_koSFsbEXnriRm(b.bZ(.ld#jOf@bZjhaR@5,GV^`V:s(.c4jXC!8([rYJ<9Cr,/0-.G5)s[lsXRDHROT!5?^Fs"*C-3JO;o_?O4#]b$-:a7,#M2UB#=eCC\6!%!fPCKj@LFL^3U/#E;^Vp4(4Ofg8q3r6*JmE2P@'+0YB>8)U8"DekeS]"F("43Kj4DEp36Pg5%hBD]GHn,\OK(cJ;/omWNHc:)MP;Vo'L2*I#h0?d6qRl[u3/GV$dfmi@(orok_'\V1feBhO+OkZsmm+d^Z+17ZB)H0kM38$*R'PChXiXS6TUMcHa@[5Xl7I6Bdjc]5GJELr'[YcpN$-kG3Raa2/K"d`9KI(VW/0E1U+RdlZ=rVd*.E``ctYTPX-oKD#,E(5BZGF2f/fLr60%pcM7@?:5eXITUD)q%2I]AAo/llg4-hSY)U&8V]QDi)r?"f*4oi[@J(coSCaq6jA<(oC>7@.+=lpD0tKmiAIiS"B:=U+CQE=R1RnGmD.',lZ:'059f8G4JGaa=m'<[-!rne'1bY?994kl$oG"V#Y6K[EFfkT,6KdMUI[l'E3,1,fS0dNCe30m]*VJO4"0($/iEY*];8jH/e-]8P9f[f-d@-on(7$SKM5;cSX%uG]iS3^?fX3&GqXeAWL@M<0kVWt%j,\U[$UkFj&QDb15h.-O+iM>D_XVc_5O[JSW#kiCtUN#M^]u)8aIHUh^$sr[[T23,paonHkfB85kt"&T`VG_CD7Zk6L:WJBRi/(,`pd(cG#;Eq`;j%?hA.kUc:`c#RTJH8B<$)(Biu^=f,X^O:#N6a(-QTiGR"P.IF\2r-eAF(H"4=3H">C#-12)T(V_jI+k[DMn[]cO9Ou=d=1mKCF,gEp@#\P+rTXo[_)['E0U!Q!qjAC.>,;rM3&j]fG5`nnL\<"/UKkH;n]=Ra#Ok%:;c@LOj(`8(V^fg5s>G/?5W!prpM_1hqJMJZAg=/U@B!7m+=bt'73]O0d(^\>(3#t5-$*UfRF+V"qY+(7"DUMni!=VX',jccjel3_'2>77O?,++H?JM7FHkEg%g4Yn67B-BEdK)-*TR4<5K7,*=7)$6s59#;k+VUCDt[8ie(^mBWTd)QsY:R'CjJRcnY>pIOi>DTI:=.cdP)..Kk<"A0b$NU\n.d<[-Qq,*`L`>+!H!LfB9U5IEij*)M6kV3o,q+]AZ5c6ms\Odj\=!`;+[S5)bD[MFR/koAp,&htXUjH2CInih#r?S9JZ7'W%6Ch+r7E*1chQ(hR4\/H`\lM[l3kJg*MMk[[-fMs6Dl"5NZJfb/U8jdfprW2IA_T?329Tp>q.6l:W,\T3QgOSA9pB#uHL2qPeaZ#0Ge2)CP.57sTl"n&Um?f2;UC$o]B0OnRNAsd&B-fq_JVX6k^6IH2\@LO+Vp?0!+V#/K=R0r6FobS`?5n!3m*`"/JK2^`sR#)%N$7@N?^EM=`U-c/<4>3o.f#9JVf4BaKY,a:44Def)?U;qH-o=.5A,%APNo9C\CtECfNr;nCuRBXFKSo7JP2YsOq:'IORR1!@dc"+;Tm1Cmced.U2rVFD8*BSoM,b*0@k?2ri&lC^(6!\SK`df0Hmq@1*nYZKnpQ]*/C`fg=Yj&2Qj*lB$$o:.Dhoj>QjCo$Fa<&^W8aDpgq)84Gok?l"LoGoV(3\Cou;YW<%b527i,b=NG6&mZZs!.g4eAAUk_&dig_q:8)Z4W>H/.IIXNW2%SSg!Ld6*F'iNk!2)G&/OH;;Y3j,nkc'*dV'b3'C?YCJJLZeU/;as/>Z&VNEk&BDJMt8r[q6S-j5FKTNhI7&SNSh@^/[\c3J3JccW/,LMl-31*o`51,T@W&5UCjTr^+(L#@3T)?l5p"Rut897%;85s7l!jis@9[QuPiX]o?[d_]thI-j6e4AOqVRto]c.Ol\dKRkG,N6&qFZ;i,d(2n]39T`4^RZ_35/M/fVW^bBP=^]%iR)Cd1A?fo+)6'KFc&ttU-r$$'3k?5<8gP-B6)\J=[>hZgR_'e&VCZ2rU0*7$'EguEUBL[)\l[ep]_MG$fr*3j)=Gm_1&t!'(^,nimT>:KC/,Zn[JpVNqifTXA1+Ief3/gh;B\/7=4k,/_A1_-ikTAoCJp[ZocceVCpO41cq-.kOAb=#f/=4o;G*8^UMeHhFDsH$a$h9&fTKhd+Gd$u=/PR@ERAu?1BZoGapS?C$?ZGDj&`>B-UZm$&4hqlc0n!Fa,1\J-u*W7\@Hn,d)5&)cQ]Y6$]?;Bmu\lK9L'1S"&eTH4fm;9$boMV1A^0+#`;`6?7)4!V;D2N$O2&]quBbH*KUCR>a1Q;F+JJrfSo"TB5"1i\._WIP5:o\YmEen00+ODF\1K*VI%,Sd[)/E"*j7IT(`!p,-R!&R"CtekTVS;K-hbb<3DRBS8@F'`aJH9HnRqFB"o-!pA+V;)/;0*-&nmpQ8Kn]`KAhsNGPPI7^VX1EW*\aO1N=.(H+Vc]%jMQT`p2>IWUV%Of^>LN>/fQK,Km9To^[&ac`[&5*;%55?XPo[jPbM`EdO6_`+U^*7C^Ggqrq1AP!Aq'Zd[5F*I7Q"Kg2*N]:.miA0W_.VB<31-K:?E(A:.l29g*gZXnUC"P>JX=^u;:mW%eh!=PX]PLcfrFd]^,@VrMd57i/gPOG@-=Sd/?n%+S^ZFoefo&OM_Z+B+?CCh?q_d6juQ1AC:;1_)(:.H*H^LjCFT\/[C3\eS+7lm/0MTTfQMXP13@0lO%,>&!'[Su:nqkC-YATrP_@.[IGrQAS+i(s3c(kf#@QPO(_d:c1KHUV:LL'ma2DB&3Hee9kQigi5?n,u.H6tocTHZQ&%6Jif$n>YO7C?7=I!MA=j58Eio_O`B-Cp7Yg^#tTfq%OFnK@@=Tu6-$?NAF/0qdY"g9I"`'\l%'M,bIOY`(7qRO2=pnUuZ8on5">nk4]TCbm_Cp2e&YTt:C8gENj>9Q^hTk-#Po#o78XaT-Fa]&j7eb'k:=:XMPHLaQ8MHS_oQ@BCD\l'W,sQ"H_%m=NpVR'HPQSs,g<7BC)&,quQ]LDFdnp^Cag)P]#YC$?,bn>:5ZZ%8E(<%49\:[jIE7]49TohOAG(T&Y$$a"oQjp.o.O]eO;Y$Q1%[n^_qjuQM-jpfhCV?mn,,bq.JaG!J$Si$En?p[8W9Lm0*,AEGRXD>S=fHqs#;e>l"fjmHP<*;lE;5ihcaGF?>u63-g/98$XUBnXAMho=fWHMi9kT.ERppOQV[(d.lp1,"U08L-#YR]I`J^TsXM[%F2qlmmMI10rbq0=@(rB7$:"+-1n"p=-NXdEL]egC9d24s=-/=#m&OI8AEMo_T*;MitAiX*Y"B;9bg#`4'C0Hqba?&l3pT!?N8+b9WJNm52MUk4$cTR6]ef.B<;4)so@$V)-I;kpmdf[DGP':i]Li)S<*sW5dU)*9Qe!uNu"\ococ.,;:n=R='0_]%nZdPpJQ1KilR&9S4en"\j=jHIjccn]#fsl/#Sn@N:dOGB^%9b>jd.1L[_ZC/EgJ>^4gO&f>5FT'0o7\3'SD="'.bJH,CHI;Ec[**)JrhK=Z4[,kgX1?Z?$YX3PmM+3?8C!&5.nNf:t<2n_P\<:6E?bk3ksB08<:7=/"kG90i>#0^MeRT,K1h`)C__%^/j:(//h!O(nI@Fji/,JbBc,^$Y16dJB`UOLkdREPsXP;4`&cU,/Tt@r&%(M8>gV$?&d;KUjA`'=A5;Los#XT:^`Bnr`lqYu3@pNSW?B@`*Z>9t08P]n.UM40#6=Wo9HkL:pD5'RoEf(?$`MB?:B!a:NjN_j^Q_r9L,]o,Q57.drCPh@q,:<:m#>%!BqA/p'(JSqr$?E!Ib$:iNaJ?/]3L+$m@%F1=$f:===\?b>4PFC2pYidS_l2M+5'+W^D4-p'.*`goE9,6O)*C#0^l5ld1I8j]emk77^AL.Kf97cWR+je1DKs%%\_PXs848i3+f5q,BLIY>YVa?R>fnB2h:)c?![OJZ.G6\QEJ:Z@a^eosnoeo?Si7[s/")g*@/EXGH6LL"/acMM<5EaI1Kn@TEP6KeHhBHLB5?8doYM<0eYh.QY<)VGclM3bkLh,0q<82p0$UN4GSRVV6*lET-;i,6:aeX`e[?WbN@?k!nsJeg7P'FJS`t'_3p0?'Rl\Dp]I$R<$n^DpO#\p@6dI1ic,7()@F[`N<9or?ktBSpU23/eL`5dJT"WU)O#@ai'XWn.0-:i:4$n[t3JD'AelT5O`<#(j6Q+iD))3]D.EfWQe>k(#Y](.!2Ah;ab84`ok_6C];A*,"jO"(Pl&g7:h[O1".B(\"%=m;;B0mG:.$#3_gLp(eF1!.uT`Ur,XqW154'WPW1CKEdX?4`1gSU?K)?c.0<^&3RF1h6(?qm#!,7*IO6UG=h=(N!Y_[2a'QN?!PD`Hc#Q6Em+"OfG#HKPlTfe,4A!_/uL9db(Fr4!WPbRp/A)j*(SKfL2BpTH$WP6O:>)FOSF7^FiBUgWWGu%IY`:r;J)KFlV$t[%0/9@**>M2#PR96V<\JYh+@*)Bn52lllkJlML(Lc[C5g_m&?eKiiqSXZ`Xr\<00!IC/]?b/e)['ADG7a4oMN)8guD[K0=.Ya,\+Ti=1C$(qn(Za^p$`(e=*1EfC?Ub)3H$ipjRYsr`Kj9B@,"n5"h*[";DY"OkE<1>!2,XXN!p%I,)["dFj+_R+`G!d7+/DqM62Jco/,@L2"4-OjPM^hIR5a"h98PPC6L@.FJMQ)Om&@093Z3]A=U/kK,Jup67"c4,*Op$Gk>Ib]7.GQTcQH?JKb`L)g\Uo%8V8C$.3ljl@49K'u20LsdRhu6sR>@"sNgQWHfd:s".B!J_Pt]k'630n3W^STS+\:Ob]V:KcML$VDL%(L!!Z-uk0LQ?Sa?NaAVk2*\$!es#gf.aa[8cS[VKo@U?*X:tF_46*\S]V8lu.OgRCbKK[tNpWI!TVR@EVO^%12:dKK;QPcni--N]=>@hOKCB]S[td7u(Msh)8!7Wj]%a9";m79PC\T]*)1fA0aQSN&6VS_L[_/ZfpEB/JR8Bl%C3/2\Y5c3[Y2F]h![C#8>%6`kXN-SK`Po'#<[0"Fo37KNO%p6*^bH5VAl[BVo>`)2rMp_86BPF9b+q@EcbXBhC1[7#Xku8kI0_=;VHBQch(o5WG`1"[rTffPW)2aU'Q&^t$p*I.4f1RA4Rl/JQ&.(mYJB@R;I+6pJFO3Wlnr>spnW1>NC1!pg<9+h7Gp!CQ<$>9^RGO9eBB#ukm6<-A^6$6Ok(U0-c(5*^J>Ji8F6);Fi_'l0T!l+VUF^8Gg*_=VpK=FQt-?Ab%>/4ft,=9+XfM*rbG.mfpK7YS-K,aF't>*)2W+r2J/;@(BR8m)0S;P:<4E82RY4V4j_-86a_$,(!]=f+b1Q>W$,\LE@VIWLRh`m);.5ZFQVA:]P\-j9]rLoTb@N(Y(pC=o8?>8A`5]=5@N%0K^b&g2hS`^e.5_RdPWKnJt6%*rVEaU)5X`%7-#e:V-jqgf2u$.p'.H9d<9&tbi&Im-Zlk2YNrdOPtW@]G:GUre<0-'1q,35EP>)e_o2NJN`CUo8rKO5F6Q4TY_tV(OV]Kad%jJ!W)(!gMNXT%+9XIc/"AH=9;O"]L"7&;dJiZ@3!8JWg4MI-ZkF=)(RS#"?YVcK8U*K7A6Rl37*u\IW4?Q-8GA)SE.MaGVh4'^l1g>G3[qkq,3sR1:*TXU`_An>U+V>$;J$fd>-'A%c>%L:?9[!edY\f:S7Lp\m6PSL7:Yj8LdbfZ#GfK^VFm?m4_:IM)!c'Huko$R6C5>8$OM&-iUdeG*[ap`\8`>W3c4F`sk.BD%DiD(4f;!WZd_5HR'HA37`:.m@MW=XBRl1pO\5%:GQ9=C+Y:[t_E@0QcG#QT&sqK4RD]s#NO+$+8NA&!Gt732B`sVqeF$n\93)NAm+JG2jdEN?S]rC!g2oX(U..HoQeN#HS*Zj=+&#jtj=+r8`8Q<(a>)_6+-,fC'Sf!3>TRent2'SWRG$8'T&q(VFGim_;`=`b-Z@Uj+&^.M^;l8XegVt9da4^if5nN4o[ek/dSSi%M`jIT1.7XS&10I@:$m&gKPV[VZb'\9q>^_=UGDMl57#GrT86.pK=Ku>P*t]./7S3e[KRj:a&K$Km^jU]AL'4Ht^H`W,HTPD.;?i+kQ%2sPd&`t,H.oiFgGN!XC2%L?`b5QAjq\N@kg0En==t^9A$=%4ZD872m3e-`R%RQRF:H,2Yd?2M]=h2eDKIi-$-pa[0`.h1,,-MSC>FA]tH*ub'C,/CcB%DecXHdL#CGsm])3P9F&;!9Y\)?c]RH;dQ7R7>(%2D`P8P,X`8(.5$q#)jp]l!<:TGTPQYflkVpj\Su?e7n8oj*,CdTn_;[USHT*o9M>'#96G_Lf5i+cmk^_H>"nfeIXV7J@7HsEk--@OLLr@:Q+.-Yp.XXP&3ltbZM[B?3O#)pr3X)tiUmqe4_<2E;6D+qsaKc]"!gu@laJL(\"diF'mA;S%[K;&C@$s`%SseJfjDZs%LSQ:6r)b&Pbt!drKDKF=:WYh/0[lnH?6RV>-to"&e(/Fo3t/]R2:j'lP"$#c&W_`1+2l3L:.(EUTuaXLe5+Xd5264S%PtuCVmW&:(eX#0a4fT?LthGJb6u]Nofe1/2dG3uD@o\dq&BA4[X5#]!0\do+FKd7n4S>2$6R;PcUmQRs:ugdot!hf=JuEV%[Vn[>Mn&8#rALC',FFosMBsN`-SpBCr,*E76Z!CnKU=?WJRZbAM[af9'9[O'fC2$M/ZF7s(grF,FLO6WsF4nHYtLRgJL'f^l[Pr>(7g5TpU__Gb*ela>0,1jDDP,u=Ef%[Rd@p<#oCSe<_>/"!`<_SQ>M38FR.c]nJ2@3?&2*PPRX'su^o1ffTq.U+g/`E-hi\j4NKZWO<[W4'0nk$,o0.B&-J[4Q,Oe?hpsK4Mr\"XZ"LUt[5!W,3h"/J?XtFRr:dI]N2H#)d8q<[Bp:(#Y557Yf6Tm135JqMn:Q%NSLDe3r8K?,`9MSaJpS2N3bl9HDX9'7;RofO'r,pAgV9rAjP'>5!#hr?CQ-:V6K1p,rJlBujffK(?MGNYLE#8+fZ,9Y'rBc0DB@mY>=K@EP[h-pO#"Q40.PSsF=)i^g>1*Ff?r8"c2]jZGYH8bY'6pD;gpWA]6R:-0.WH1$j+*h>;#p%C>4UVSbpm/LV<-uefkDg1s"GkDD10pH79G@H"!?,%/]?)ou]GjQ>GQ]oi7JeAdf-*DCSPA(V9PkJ$%YSY:u(AH]6uMBNSf*E\sYbSi!"6b-`C5eiYoHE/JEAIA!`H&"3MHJMHh;=rE_khJ)f$\ZgLNk$s8db5f@DHU\d?l]mc;R"sWS9GjH-jK?q"I,hX(<"8\c4)\lg,"G"0KjHf<0(""B'>,$$]9J=G%f>M?NgoZAT(,HI%65J)!_?YGCJ?>1chT:WVTU20fXYW_Q#"1*l>l#nVe.()3TrJZ]s@;l:>/T`FhBgB*/Hi1KLpW;.h`"rXDA52?\j6^SZr7UK`tdeVMV*b[DuM1o&Ofs$:3C:3PLg)I:"Jkq%7l$A431E2*I@:A,M4DX^b!eRESdU>Td#\!Bi+>6Q3C/0M%-WT'FEWM1jZP-36/3))`0CLd[@!Pe1+\LR(7mkY1?pOQ;s5/#Fl6qF)`,l)k7kqJ)Jg$(a_p^)(l3t2bj7`D)%-J6'#hdr66XNo'X[#_Q#Y4:6V=LfKAo/Ffi%>o+X:3VAk6)?p%PVb;eu5UGDU5O&#W,U0;af=.7Ur0hc3ZV$iGnPp++#Qm)r(p2CIcU$(Jr/\itA-6*l9\uJ'-W5_<%*\o"pbLiZNS(;LuJDu$8*%CKIN][^a0(n*e&$(GdhW4(VmA.jo*s'32d,p:BCDkg#9,,WiE)!WiE)Ml'`V-2On<8@2$AR]2UXnp+/j'T%+0%<*7'4grb:L9cbDCAY4!7TRSSdZO,Dp#!ep2`)NR;6nBTpEn[C%A>scXC5Q:;d\V#--*>IhACPKu2=RPF&RZ?;1<9^b:*>!:i[>4D4CemKWY@i,5no,?'p'bXf*/mPY>=n&IW+#ch7.:iU[G@dcOA<"U.$*!b;WQuK*Yhm@@^X7!?!R_nd>FG6k.+?P-\8:YU[X[KEsTl2MN1Y?78kUcuSMuecHO(8dL^_U<_t=B)ASq8PI[Q.B/L55sW'eBF-sk@"AbX".3MniQFrNj5(>%,bC8I.k;GY*kjT4@,'g\;lE8?A;6V?1gBTh@AX4iJF&_sYom6PGWN.Ml6Q+b*0ePhH"AqG-taRE)"TYc@X?,PqTSc%;%K!k2fNYo#H9(sZeWJSn=*OV<05j;W42k0oXgM%N$S&*RgN+1&(X/`'JtuLatU'/;JgYOcps1-88Oi,7!XfnffK4CG5EV_\;R`0i70aU=k5O>X+i6oB9S$<%GfE"P-V-Zuoa_JdMMD"&bP,l^dkLK$7TPH>fO'K/W]0t>X\WATF(hUe&g>6U>@-S,Zl@>Grdo0YMa/X3"l&1]`@S!$-:TP>*K:6H?J0T-)YP?7urUk0mce',EhXFeE^+]+%]2$+\X0M&D`$PlbUUr+TPNj-TVJfu,-]Jgu#Nn&s=P[Y*G-#,Lt.SAeP`>30$#_4?,5\k\6.^!BGZu&7J29iPWj_34(3C`)q[cP-5D;s/7?/@*(sFC/FIK_6P\1hOpd8gn\BcMu9<5+P?u3\r<.K&YXBg!6bfoPL$*a0>LN,S631mVeG.?/^^8I,6@6"s8aMb-7X=I-k!Kg?1!9ILkfrkn1PO"AS_@JS:BD`c8FZmYK\pug7pjqn"'e1Je+]oG6lt?l27YO/C5`OTAqAci_W[hW/Y+k5gb1V7nC$ii(m(^7fN[7Y9%2n6uDRmQNf,m=BGGabb+8\i2njAGu[@>$W&L,Y]b(WO[aG>8=+@qV#L5>i4YF`u(a&c1%D?S.7;'b6o<0/dg-QKmWFq?L,as>q==;4:;"V#cbDqe\B.[aW5mmp5_BbpU;XC$hUq5X#`_0(Vm@ngR?8sr)FnJfohOVOX"I@%1($@KOD_Sr@>PEGk$*,i_YiGUAof,D4(:Z>Hd7Neu!q5@6'r\Z;u!pbF0MMN&`Zgq2='e(1e>KW(=3Pal`f*LYWY@fSCBKLGga.^h=NZXlS//Ji5>%[U-DFYB5:7G>9Ie[NkleIhXHTl16X&1cSDZ%$:gubKq7W:N>)1Ha6>3htVJlo0+e;WQJ]=&kARt_i!3#4a#F0DbK?)FNX-lU(m-4"U0=@;2BO/YXpO5MBXb[`k:L33gV:3,A'?H:&j%(c;SM_a:9kZ.W.=2up7e41V/&2Z?-kbX6_$W3BN!f0iY[Y4_.6lirb*LFmnefVO:JLGDqZo%$K%T9!dk9'IN^-hXq8WqfIhogVa2h[^[@+4_RT,Z^D`:7O&X8$r#@(nifC%DK=:rMND'u]h3l7X,7i1A@]FJtet0A]f-<^]L_!#H7OP'4XKH#R0>RUMt-Oda:WPp6]sZBEI`[^:_B8bdDmR7dRcWM*6;PqAuBXA`[W93,NU/5m=#CGdCeXHo`h))\4q1e?279XNN>VOGbmbpdF2/Q-.'#bbW_5G3M+dNFY#nUI1Y,7rnL!*0Rr*!@r+k!Y;#&JZH#<00h;X[_$/g6l!hC2_bZjf]Cn"B_[pTR>fm(ZdRVooN$#.MWjG152G8#nAYoo6S(gkAW][&;<#E#lQKhTEts]aXml5m9l%t=r*J9d-))j=h8P#P-,ZV#OofNLi?%dK1q2MQ7Q&&XX\Z\.:oseS-YgAYb7WpLj'(bQ?n.u;lg]]@tWca-]LZEoE#8')%P`+B80oT0:ViK2`O?5[af2#>f7=K=HS[GF^>L]pto#kj`+_$l:U[&d2Z46oN@RmECNXB0[Yb\Z='!:+mT^_?bErn0U/2(0&+"l@Z1DeW'IKkKeH49UjYtm)9_.naVJ'C*E2Ql$YV_S"`)"V)=W5C(oj?EZh]Y6fFD!,7%noA2e'R%LH`ABe*)K$4UbRPd6Q%oi!N4*2QP6);+XBV[Z=2MZ`rn,!)8V/p"3V,+C]feK8!5(q.&('ZV4;R.-Eoqc#Re0L*M=(=)2Lin)(%$L%XGt*q/#1UX5do\WG!9;A0"@Ti_8rb9^qSjdk"Ug86$O$Y#'bA`fYf`KAM;tb%+#s\M`?%GV1(r-2'ZOo97kPVB-R_=8m1ncOHq`To/'*3:\dER0Tmf^`7Yi&9u!.c+(dj4I3I4<-!K^8j+"mId[W'ZNL3X4OcaF)-]irBpjG&o+X%]::[KnsK5MP\@O,E,D<$O@Q,6+2V80UgSfd,*G.b(g@(Ub:0?&:0?mX)`I=8`1!Kpte^RFRY^(4r#%k(uN9^/ETm?"4UhDuSg*5ll2B[`ab?Q"U<(C5'(b=6,/M8;'ZVJ&Y;$D9JggF@smq(piu4m_/QjL]BLlIH<2=n)pJ2>?^hE6e5?7udn5/7WD\Ccp[`lmZC;OGR1:&8<,]`ss,8_%!(E$gGu3L:G45!\SYs8,b0@R)$B+fW-4:&+cq6YKor?FX9I:U\a[hd$+\!61i2%$]\Okjt&BE\!:N>mj"j,R/iE1.0gXI3F\kW?dV)B?9SjfDK5oJYCuV7MPtq4bni4i=27rX^;V'S;X\a3iMg:iTU33N@-QlgL#d5Cp__5hC@2O]%i`IQ#fWTXXQrNUD^>;-&!&VG8r*u2X8H@]#7cc+@`.n"XhQ+OCF"9;C^p5+TrQK_F@WsM0jgJkqe4CLp>F*9p0JAfNB="7T;gd)8:CDIepKl+%r$;*epRt4]NfOb2C-F2TQ`+Nn?,(pd3"P#t0JEno[]!_4g!hbj&0cP%H2f!/r6)P6O&o-*S>=a="T]_"Wq$&+jjh6\=?9:e_Rr,"N;gPu+F$6s<@G1U@4+AGW@`Eq&=aNVgtL_Q`Yfnuejl72HO^^1hhKT;LkccZOu)7NdS',>B'PF@2QkeGG8j`kmL9a5CA*rk!Xo_>iBtNCi^h6P:V%<)61E]kDe.l^_oFNcO2OsHPaGNei6IB/9^Rs]LTJQH\IH(o#n>M0LG8H'OoN%nnQAk^"V]N#O)theflmg'9F]Y`>1eWNd7^H&Q/3N0#4p!^q;;JVQTi13iA[bTq"4>UgK0\$"Cl3`q>KBdb$F(bnZkf#qjG`RdX`?\;BMdUYVEPFA0=Bh59NZ?ZB%aPnHq;O*A7Vm@Dm4n\ZP_QTM;"6tZ(p:%@lH#lT":YTX#=[/?!R_O$lVqcR]3`-R0VqF%IlnlUb;ujh]lH:5dWcr0Ufuubp2fY'pM++&=0)IPBNjDmAUGEiY;8)*Z*m?bHTuA>(CptBXb=p.%)*LV!3"X[[pS%1-KHQ0ss=5UD5bWt)>0"YpqR6"_hJA'"5%'6#eGGB<,>cu4TFV`U9.\i6'.LQ6H&>kK4@o_ub#BikQ*VD3Hb49rFMPEKU7.:^SY5hDW^U]7H/,,V;WfT;jF9r(Q'#Y@24s(;dJA\)$%OUaK$:-u;(mM-2_U'SK.@CJsOqNk.Mrcf(Y"D7m,)ZFD#UCrE?V`;GaHCZnV5]b0#KbBu1XM:/U7%R9)ih9e*'>MB&M6E):)?"`GtQ\WRriJV^[bT"Ml,kO3ac9(O3$+kjPF!45lK/b@XVm:'"UY5,C2kh`USa5A+4Vq!\j;ASV`R&T&/VSHrE3FZ_7`Qa-EsOUPqn,RRkFf6RjPQGM:X.*!,^74`TX?qpHb.G21$;p_6Qs<]),G!c'E.$3e=*'sSD%F%Q1&n0/Z(F#',I$+N8,HI+QdPQ3UlQ=-n'Xu67^![-\\:DaB>$a^MmM1eaQ3<7VW14`RA&jdQ1qNSnc9N")!-N6.$WLqKQ'&oN6#"@tHH&f71Lgrnljq=;83AHQ09mD"[p@"U?Ojk`+LR.ANWdP!Sj$pB#&Kp=gU!D;/NgX)ERW/8^ET%lVA,CUpi*Hj]oZ,E:6SFJ+X!4l(F5$ZgM+$(!![hpM=Mmuls+8S4(($4g,SEXjP67!^o`i.2M=VHo-O/2^McIs;kuA[uWamFt#FCg0hpht!-%LVO$$huIoMpe.mW_@b;H4=,23lX2DDi[4qe-YA=t7Z*0;Z;&_46roNR)uRBNf=*JQ#:(j^d1mbZkZA$n$o"FoD(iV*@O*Pne*b7]W5$-mjn4%TqbkinL`?arbt>0#;Xn5s%P[6r?U$VUp)@6F"9K2VZGo29SV+A%V+g_[2TZ#^"eoat!,0d_GT%,)p&P-u3@Au@&D1Cp(>H&1=pN4W@@8h5La7R#T(n!T[2'opK!NfH5Hgorp%,?N@o+i%,]R9]W5tNU*Z(Xnj2)'8;BZ.Bg8s!CMZHWC1I`$=A:S!fd8cDE%!p`c/'KUM;+!#3qEpfF!9geo3$FpFl&:b3KPD.<5\5Y75oQGuYj?:M:/M=7$n1)VZUk*h$Ckkf\V@1[8kR5-;SYq6d+`TrJj=h'c'f@SkWBFiAL:kU$O'Ws]n&JdNOIJQo1BdHO(=Rh%I!Pd5,G4JJOO\TQM*D'iDaP,-hO8[R/[a\+BgUf"ErA8.m?mFP7QF0,Ufk-SR1A_'M'SaEp`!f!^E=Ucd$oVZH-5-]%L$ljbKaP=(\]Kpmb)q@'7k-%5]a6N%N(e6r?-0(FgH+0,4$2(m[r?f'%0T%[HtAgZ"tgPphrQ:i$m?WB.RFh7b%Eh1&E)l<*-Ko0`1*#K5Y=&(<3d7p\]3#h5\/;1!,`9;,7J%5M(Y)Z1/`iD"VCq_)[fcZ16WPSJr&-S.(aF2>\ONR7>Wl'_$:^M2]6/N&_Tm'?3WY^822R2.)QAqPADYA$AcSK_-li&^q=jG&f>?",i#F'iQUH,9.?b0-R?311Ps1`Q"SdrDS+Z&?gGg@4n-^u!<"H$"U!6:l=@U;1VhN-Z3mnc=HP\NT7#CJUN7b.(`8@#1;arID;Q9R>dP2P_Lnl_,(Bhnn[)bjLNlJ%)V&i3J%'a/j$:69V%U`9][W%n\i?\m:-inSa5@6V&[eY.-L)=@%A#)saF3A%U!0i`EGb-g6d7h[j+S*L+#MCPX_>3T1cBs%HH"7C=X9+q,Yp(=ucFTs1j#+9Mm^+Pe>A8q<"Vi`="AYk3>D@;QQo?i=!SRFjmQRNp#(j3rm_jT+G(`%>U,W5`I3GBBj9r4ljVM@\i9s,[C$?A19Y;H:s3<22#"`8sI4,Bh>-mknVkV.fJ?lFEdJOI+m0Ji-)bRQI4!jgNXc:[5!BLXPq,`JKfsH`gZW5]g*QTF:G[pGaKkDY#P<(eMk%8`pc^XL>l1[IV_&Q6/ioGgLFGcoT:_6>P?N9GkT\XkTja.j":7ok9=-toY=]nGZ_Tp?IX[!eds:6Th8)iTMRqfRHe28=ZFVE`#Kb`nRa--Ce+)'NC1i`nV.8'LX'\#.>khNF22[:1ZIH71]V$G?@Q"kW(I4Wm2A2C9#R/3ZL]KhUU,X!tYb_NH$BW3EQjEsa$R?E0@S&.HgU:IVO63ql#ds;jk2q_1/*XM1iIoX6GGQDGA5e?KknS:8IAW3@e.E4FWZSGA,r+#hpa;YF/OK?C?fe1WkGnu,n%NtiL&o6<=;*AO!mYSRG_cnXNq*"Rq(4hUjtC.+d3JA?)G-)t[&:gmI)Np)aEuZgVgD3-..S,%i5N`kH^?;452,0D1VX@]_oNoU$U,?B4::u[jr8/B.)b6Bi-qf\m0qR5cgKhX^e.,@3_jtVIEAmJTh"4*.J4:\j=7r('eq$I`p/rsbe1gcBHGaD0&O9Pn*#.YqKiX9_#.SJhr1B4f<*;_7Sc:$-P>CKG%)ng0T%*nkkZH983i+Vh1\74_sR.";r4,>]jJVd!+>$tbFG*/TfSd=O[c43O*57V^m"Kd8]G`3iRUi('a"Mt=2;>7=:i:Ma9_)C(m50A#@rZ)8`>=^l6B1EJODVj^qg,3(s50-AHd&\#a.J/At)JYY_n\-&K80U,=O%;-k2'@.Rf/V?=aOW7a*;QG:PCE^ss%PJ[S^kjN%]8N$Vs!6q#$2"(fAi&Al"QU/%`jnq;^N[S&gLLs3q$._5J=oMeo/F\>_KREsrigBK%mLoP+Y?,J.\N2@g@r"AhhdV-=?61"nTV$2D2!LW+j_JAm&Dt"9Zo2MF8:pd#;m>XdBPN'.K2%IO\j^/o^dL)&d/t>7P[S1@k"cR8p/m;7,E&\>I#t>9(TTlaX)ikNJJ@lBYYBp9-@7>%2)XAK'QKAe#RV+\Q5JGg1;178PMia0smEkR5\qn16%c:VOY8F-SH58Y?A%JfoXX6U\LW#!`]*.:b7ZJH)a'qT]Fi:"-1>;tE0AMtTN[l_)b]&V$CJW7'*NYp-+cET^,Tp]-036dD6L+&4DVB"COW[#XMFPc%,4]+.Q,GJ0@`)++km`'I[Nq3'(oO"A)#+bqt6tU`?a;D9RSWM[d',:!7R1OMsYM&V(t&#dQ__L9UjfYn]['!>liL!e>6MPd57j";&lM!0N4nec:FOB!MHk&6U,^2*d8aOT7jR!)nC`&>ca##VZGk2l!/G?3'l@!7Zr(<@#Pe=3.$s,,tKr!&Xp_&.+Sa^*iRPF&ICsJX?Z,pQ,qYCti\)VP^CPQ;lEHMM+kNg]UeK32)!mm.`3JEQV*C42a7f!RV@=+VY,M7R_J#YIb0=K4,%J;*<0prt!oQ&0s;1KB7WnMPKhGO])+,Rs8js2VGJ`&cNQfQhaq0AbE'bC&m^h6UHW#^?a#]$bX$HNfNNtVYL7R4E(iImUJI&,E?0]ia7'cAk[kYld>?m,#l*=_2?*!-iXOV0spP)K*2Fn$!So?u6_-4+oHa`Tu\[#*I,;UkB!7n]3b*`,).!q;CTBHKC9^i7ZOQB]BLiP?06-BnoN"JS5WR,mqhFRYJ1VTG6WVM,bBUpAVZb"Q2NKgVEXiY%s!`d.2+FZ]Ye(rI:Q]+FP=k!_-1)@CthFSWdHCJ&rcaL"/bj7q7;5KO7h"qh70JgY8I;?RU7%aaG$%t$2klV1Ru9A&X*1ciEl4.??;_0H`KMh&j'R^JGmH51*R>3C7uQjn9rQON_.Lf15'6+sVV+3d`bUX=?N+TG,ePa&B"V"8r*SIV;M,UZLjtT'RM[mlb!,)/#cZ,@f!PEa/0\#!8Sts2db6nbC*1C5qaW:G""NB?6]'0`7p1LpE6kSq+b`4IQsOZ0j.t.*TVs-3b\f.YcAlmb8#lR[WferidmG!WQY0J`5MFg\Kgk-=7:+ra&7hZA&oPj^h+0mehrulGn=OA*tMC-&hPF=asjQ+hk[=4E$qMS1i\G"nCg8$;<@@pu,5:^!SeoVVE*>^AT)`o=d$V]oRi6PuS]LXW0r4D(B"oTI?Oc=C0;slCP,+,N,3erF1r\\$[Hd<'"B^7WjbS5$gq#Te/?mp\;Jh#acYL*Ha^=#MbH?nftr(64g53[&fuF7?iX_R)LV/=d^W9U7&K\YoM@uD-F'Z7Uio:QlXMnnP>$kc^&"gno]s-AY<\LR15o`5BQ-7/7IKmUPE:5Iileg;RC:VFmSQF'-l#d&]GSIXBR@ee0^&mM12tZ(o7?*q6r&6@hORd]jW67*P89'-c.71n5[+(6O?=`BH0WP7>U5P@2\m3)m_\rADU,hpB+jm!tanEi,Bu#BRJ&EDFF6hb:WY't=H-STP0Y#49%2RtO%:%#fj`jOtCS@0$NW`E"mc:,fE(^MJ$5e^0auj+n@<.QKL9R[8*Z5_+prfYIUN?;d)IU^E#%JRRbDZ.4C.(j6bn2EJ6F?2:8-i,""+S>5E9FA@T'p"-s:4gGT*%bNX@fS@9,@1QJ6+=()3Lhi"6Y6YCb3(0H^@'hX0--djrk&EUKa-X[U-:PVr8IR8WDZo]=jbrYqa#E)2S<$*RjrY!$IiGf[!aRhlneb(p1_iE2eh6DHj]+X3$l*bf#V%G1^qAt*&U4?8UQCG,4Uh%%?pV-lmNi=o@EQg6-J3uZ]b'3>A$-I$j2q)Hf$Ia6=.CS&0C7NQ%e?ZJZ]t[Uu@XG#SDm/'?I)Dd*InUs$:QP4n]bc5Zg<_"D/+!,o@m/S<6sH.@VNIH;oq\a[nOtS#$^f0hmS8^8&jIRe]$$9RW#hbg%<5S71BQBefPk[5d^a,mI@<1IXb@E*g3CdQ4)!L^J#VUhR:R%m>g@GNicO^J)X5gMFS.XW[e69bTS:gWM.2oL9*!$j;I/#O3QHOGjo!&L7sN?G&/n!)%o]rFeP-_p=h8YIf?ik2!SP[Z\@idYq[$&ct?<1m"nJ7p[kU!_NZ$9j'h^(i5ET:i&`*6==>TV4.fi.*7Z@P\On=@"anqrT3M*BC41eL^*DQA3fX;J8dU]d8nAP]8Q.LoU!oJ&;E7l#\R0o-r<+$AG=`pIeqI8P'$RBe'QT4&J5*De3K_GQE*/8hUF:1]2hok3BH/hS2j^Aotr@nP6"bkY[:hQXC0YAEk.91$S7349Z4s;CZbGR-4s(?R>9PlL]R=!:ZfC2#oQduF#P_pNZaa$0PU(uiHLI-gMPCb^Wdbkdt2'rPn^+Vc9k"EHD`G0`2mgg%*W:er`gU7@Lu!U96YDM[S!3C6qC8a+KWtr8JJDcm&KjLXZ""A!>B4P5r?YJc*``jaF<9U"&KAOaXkU@;3IirP'PKkej-<7$R?<]@NY^*9XjnF=QeZ9UZ7Q,te[_(BesL1^k#3SF6kH=D"u&lNbP]8%C!;-Y4WTle72O8CI"Vus:RfsU\k*qL=:I]lP1s/mLmo![7_7kd9hTC?\lMuD-,3%JU%>cfl(aHJh>-jNP<1Le%M8:JLrXTcSC#JO<@hC\dI->eicM&L#0XIaILo<_IP1(!,=@"BfDUX&:e.%SfZi8#9[0;AkoCC3&\2]7oAZGhY/6b(u:hAe0:Nk(mRQ+m<5LBQS,]jq1[2/(6eC1RWs)S/FF43uq)-/]5:=`-`W_1Vr'l>3VlJBBn;O6+iR^KOWGI.qY6#&3@sQCUqs&8KNlqRNRD)h]:Z'F6p!!'@?"E;KR_X`IY%XPbV^DktN<&YSN0WUm)K`4H6LUSJ.oMSCVV55TggF4>C`nE*O-=dlX"=.L[/Zb3V7'*4Wg,@?W[Ym#.6kG#"1MTfP#tf+I,&HD)XX._ne:O&n)QAKU/b6&X=j[g282B5_7gJ7^V1UMgL6I?79)QCLK\;M>B``9:sC/:51/0HQEE-RBW@rM'8[$n&S34"We.=t=YVNrVRnOR>>?2g"u$0GB9A?rmHc;"%*)]cOSW<_d8XH>uY/a%,\DOTgKBe,LsDAnN$C?s0S-[+)iMSVd$KHss1Gfh-XJcN75]7rZdr3Qe=MUZ$cY_>EL]M)ku>XVnh\@cU#@%%^7ja6[j/bPT::2*L_iuAhg+CktC!sLekjmRC+P\P1pJ/mNe1P22Ob1td/&7QW=&W._;A8NHfj@BQD,)BGTV)l?^^@mPKp6E<'e1B_be:4h%3UDQO;T8CA4qRVks7ti6kpKAXGFt9k*h\FKdh3u2C;6iAZB6]0Nf&<j,%CYn+NV>+BZRu=NrPO,JL6>,']Tc/U0Y.\G.4TNY#K*m'm[J@FooL)q?IuO]\t.:T9_(P^4HJS5_,FSjj`qsF=^buFW&0sBA4oYOWbSg6r@@We1)Y1"#:Gh@Gc5F/KoGHj]qsVigqQ?&A"r'aKQotf2kVuV(q#3?:AF`*([[eS$cEX9Np10C0fESdM.W]p@Mg`eEh`T)=NEaE-_5&P_R:.qr.<'u^;>n!H:?<[l'7"AMBsSmc.<.`)g-=6L0%/7M>=WFWeQqEqk$$h_U!rW2Tpbd`Fm2?C5HSX2hkt,FW6FbN).DOjX9!kH3/?tpP#nEDN?Xq!]Sl0lVZA;#kXahq'PN;H?.k150as6kaJ)siNafET]MD,\P(aN@j:JMeRajrO\Xgi;+Xn2Ypg&TtZnW*-3HKi1"&@1(@T(lmE:'LhkZ):?)D8Yq>Ce_6'IG$G_-.['-9e]YH0YcU%)beQ:F:&P5Yiu9W>&P\Ye-V(9pm^(P!L8_V3l]5o(#j&rNd(mUCf)L]j-l.Gq-T+)R!)e!3MG1Z/%B`cC:aOm$_/_s:`"U8)@>#8`nXo7NaM@)HKd/U\q&--"d6c7W%,a)noPido5o>WLpo?A4j[PI)I>+GXbC'YX3Q6''Hj.id)52ct`\3:.@hrB4Y5g)g,Y4E0D['VfecQ#_$6)(_R;QAB$=['?G^cnIa4%LpGDLe]*TANK(jT%)[s<[?\\a:K5nP7iOpFEs7tQEE![$7*-/Wp*XIlAP!SI$3_S*8Q0(-=kjT^=Y^%PV:\!K"S``e9!jB?kc0B3_7OXlsRrk\onsa7oTM`"f$W\jFa]Xm/sBp+C]*pS$K?@J\:."AR),2Wmq7780JQh$ZIMM]WF4$L7G`T[)$r?c;po@geL:sbr"A4"IaZeS8X6A:,5>c#@*;YJ;ZSrY_k2BJOu0TNjeKg/Gh#dT)\)s\[;g-,X.&G>lqh90.^2ZDTeW,8=/':KM[mB&@?rIk8?NpspsLb44chQHiprU!EQ%`t[Ro<:\Db-tmf;_<"YHca4aLjN:\ZVZYB$mr5`\[U#OmAE_u^,gB77V859-e)'L5paj9DE@c8BS4C/X*+#1JI%erOR3nN[7;[BJ>'Ae2c?K?28!Xqri#'%pZk*24P8"K*DTG!`4`C(4Flgk,A`kcS]A%i`H._7o'hF35+mX%jRSPEu]>g9WR\j@I98,/RO&GrFhXmdr5:[SiC%G>t\e+4,6-)MB^b:cr:;1k+^$?o.idD=Le99QhuAd-@"jN=!+7PdVHTSeb/V.SJJd*TDbH*X0/9,OBR&@JY/q_tl3X/NA$oWoG6Y$$f\Fh-c"]@kJ%d1s#NM;ppX@g#2r$p^[XbH@$]k8]lt!o,P1e?536X5,_G?F$nN]kQ#QhBsG,H:U^sQ;'MRP(b@IAXo)H)M]Zk=iGp<'W$pL82l,7RlXbbC!8Fd\'>j@B:ZTi;IR:bQ+``/6=Hi*:E?4MY,p92DdR8.f&r>^4C9(u@FG\BT(6c>h03"\Fuul@a!L;#.?J@=$8E7&;1#h3`:OtmXn+M]ZPml041)FpP).MRE46;H;:[mD)!Je;n:F8=G:HK%5SA@B"I?_^Rh!;LF*LT$T5`fq!=]_pQqjmCOL"PUYr[+@EZ.c7*-et!/=_$F2hfr;V%=UN@EsOosf,^@lA%u"Z2kuVD*9h6VG-LcKi`r;[ZAMTZ$G:5.'S6*=.^75QfYGEXa2^qMk)iBLi?mD'q#;S6>KYn3cM3;$(;o-qA38qHn94r/gkfP0*84$/`Pe32"^#tOufaZLQ`ahdqR*(/E.S$$;L_hgl5gs2aU"&?p^J:B%RVr7u+G:oY"KQ_LDBOa10C4'B/7l^)MfteP]J/EnnTl25@@;\:`@I^6Ff7":<=Fg$#`9`GBjhp!i!i7jD0O#hYmU78PTh9\2Ib<8-C'P$qEh5CL$fn!gC0J)NK86U'%b-#]Bf$$6^`7U*GX0R`KQM,Jf/ETUdNF)!-8i0@@'r?PBn^d6q;,$^n^/L!^;FU(BdgP>s2/'Ul)@%L-D]/0e0`R@8Y['SVUB9+Kp*hhb%43S.?r?lNFX_C1>%diRo2gn+L8:MXB;:#-H7p=ZV=q=aJ:"*+@8C;,@2L`UpWJIJ]MdhLpT&l=/&f=GR>L>i1ecnZ"#1h!NPUg,2N!SaS64V6`*\ej_OcfYi6b[a-@0r%+!@)`Zeb-7%"7,ZS[V_U(p\:'crUB/au%J&8#($sf'T2g4ceMtO-h9iao2+XQVl+^Nr<4e_0J[g\hc=1)(berpIB)KOQ^\E/6obY@VVGjk*.hVq%UM#KU5'&q*YN'+V)_4$ZJ]>a<#7RdKktPV/0rS/G$lDOt[F974KGdY%3\!8'=r6E>!C[97X7)$_B#a%=qAac(CJh(s>8C1bjnrEH8b30,cl;jKTX(1)G]'`e'$V6lJDY$4%f3Tl@hrJUdbo@%c]l`l!UCXl?NHTbBeDCP!t)d9&ZKa7.Fb,kiDdbJ(e).\M^K0a8]V0_6/G5@M@P1'03.kMp2R"0NA\tCB)mksZ:lMg[@76je^jRW2eV%Sb],"%!:2cYKR>R3+fB>I@INt!5[IZ:RL.RoZ0_95<7Ak7q_,^i6G-_QbJLj#+9c+b#^dOAeQA(80$5J0"Y-AVe+ght!,Tki5@_esHKs@tKKY$K#7L3;K>tZ],@0D1(pOo2sCh82=TQSU[A;inl6CXlD!0Cu>HQAVe(-!6m&\9S7B!'g#!/uG9+P]l'9L;ma6k>;:SJiK\S3\ZjULVJ&:+K:J**=&%"GE3\Ok##S9/;q^'Kj3CH:bc^g0@*u/t``1X:$AJB.V%'i.uJ7lpIQ%9Q9FX9?8QF)@NW6&2#\K)d.5=1ap?4_B$SZL<^JY$SNh3K%8EX6!.?&BMN5Lj(s\E5cTo,'!C2a>NRXM@GD_@.dIsb$RJ!-^dfT]Adn\sRsjOR+[+&HF0dSsD_>GVK>]tkF.%so)\4o_*pj]2n#('6F,l:*Z'G!!mWqiQh.Ynk.K2Juig+l-$Ml+*>S"`Y`h_ipT*T_9cP9&-"!A![PMjT7B[CsCTQ4RRaemSQg.J<$f,$&N23"-U1pm*8NptYj'%r"n;2%CoX;J"RW$s1*#2umt#]D!TlUB8G!i23$@!3'0K!9t4^lo4^VAbA5F[J=C!Zp>S9rDH2*tL3f+K[\GMM@@R+)1mkB14WrjRK^)13r>@Wd#2-aJ#^)0V-?%g&dYCC:/cu_J3RTbuu@oUEc@R=:R5p54'oKpU?[U:TAATUC?TrZqM9R."VuCijkLBT/Ea`$T@CZd86+@p.i^gcO50B7r)/lNtDsd\qj4e$76NjNY$ha9e9P2UZ&$q8q>2mmqZ%mn%tVnFYO51qRQcA;P8KB-dTm0)`8V"`p0pRTTq.QuOlT7r8qWm;L$3dQ:*2.5@kL\X\c'pbE0&?ofl82419&:0DPo:lu)U25j>Xcc^le,BU_,FTf%&go(o(Un%atnlf?U"dmMCKZNeG?Gd);+k[F<=bG3u%@e*l]?mC1CusE)0H8UnBJINV88p)cdQj0:[Q6qFfeL_SaP/pUKC"IeB^"rgHT,juL*\VifaPaQNb:-Z;cJIj5VNKhAKuVP>jZmXRKU."_GEFrUCJVK!XM@E+G$RJM`H.6W0+eP@Tdmd`7-BbQ:g>XO?//jd=TG!pQ].ZgMR0AK-Ik_:1h-pGsnNE[8Y^[eA=3hgFEf%ZZbi,:N]G8nERpPLRb[>.!fF1(#>u1##tG\64$j/367mE)S!TC-?pg1p(!uc4$""111@9c$nRE`LVH=d#=G_8JjAUY)W\=^nmtTB]2XWX'#MplmcZd8FV&BO%9=i%_l.>=2D"uA&4:#si"raZ67r@RD3u`;pD8$F_K-Jd*E@5bK;?@FR>!4hV-R)/_`]#bd1YjruTN8dO'#+DhlGb#L1u0ac.OE)),oOK[We57;_6@%h)1p7nNSl=M_Q"6++W*R#UPPTd14#Q74_mi%#qO/#QXjN'$"b7"%H6#LGqaAinTRS1J-UjM]Uu8RK5Q9NW$j-qIPW\Km1/Xf;%Bu&HY4R`^(_0eOAF.%kOuiJ56uq6G7WqFp%?@;q*7D+Lf@o%^OIX@V]HR*8hF7amUS1;pamAaNZ5WiloI+5g2oTpck#*(7?M2L:j[oCf0KX78Rh?ND<+p4'A[Z`&a'1'cU?>&l>)a7OM3Gu%rq&54+i!2Yeg?-XTf!`kXJ)&]^DWrJ*5+SAK:ZE&clBRNl]5rR.hk>3s%j!M9<9tJPI(ZFo3:71@mG*+1IRfG>'JMrbnA.V#RC7A%_snYLl$jpE$dc(_QJY++=_FF!!_tc=qRVV#V6o]U8UUYkP:^cm1Fpl;O.g@o=F=:$XR\=ABBXj8ZF9mRpcVu=c.rP4/Q?3\PX\1$=q7pYp'Ii#`(8>8.-9^?rDuH6II?j=P:bt^fU\)p1%FQ`ga$HK?Nd%[&MmsarM373FoA;CQYt\/Idk/Je;+(p\4H-++9c6E..3dH0:dB&$Q/Ipq[H2d%='d>P5ChAr0#c.B*k9QR$.^S5TTC@urLQ')M\5DH%D(?JCI"3JoL0&[[p]f:nsl)$m<'eaZcVW3#M!Ub$CQ$NUZHc_cQsLEZC1+.8]fpM=!kXB%e\7GtH*+J:N(-u0*Q!Vk\0`l5#/nAu/iEMlYp(oa*M\db8KIUITn59K.eL]Ke6T8&\PMCU7__".g:fBr5G?m??;qB',Z:QFlbrW=DV/2+]ICe;!Kr$/=L8uB$S(6FXYoSB<"#`'sC'#_a/6I^7!1Fn]$58(mnVEfUG6$!G)8srZdj=Vc^VC6k!)u(0*a]b2'[pB;4c[4\EeK[\KAkCXM2NZoQIsjEDg0%PX4B6[Nsc16<+HC76m+`/KLGYrRf$J8NWom7U3%iuVV^`j1.]7p"D5!.JCF8Zq;K8@K'ieQ4G8:=a7nk7P+W-9[%02:F&FC6hD"I,3U7K&Wo^eJmV:qRXZB"!'*EADjDFpTMW"pKII`IREC6s!cq[R*ZPl'-='!j5,f*Gc$2WgE@sRqefIfHl&R?&b&br*Y'Ar(pCqmm&EELQ#R68,#@O4g.'9HgJI)SjQ"D>38i/DAA>iBAb%#0\NK%fM(6*-I\3[Bgiup%(X@0-emF(Q;NZIW`7hJ'`;B-ZtcNhW:-aL8;#:TY]c(f*K`u*>`dq)3ZUi2;rC(f'S;DX1S5jNJYWfpO,uadhL[1!LRLA078>?7V4^q@*N4PmR=QMM3$Nk6YEd+&XklHS"[e\P!BQ0,QmnpNVbC:!!ANcO9ILn<6VeS.b,cj(7T.]U>V)6S9E70_"sRdo5F,R2O/*X/8H]VCIc&G!jo!\)LP9"_VC&TZe+#t<_U![[J1L=]@#=8/qEk=6*?3qEQu[>`aDddZVOPUR6L3<Ol%Z?t:mTX$r^LjF09+$[BXYjLDGaJoHW(7OPm6*=)#]+3n[rJ)*gpf5po]Z:C)6i\<'fMl3)[&O:m4>GE8,eCM=B\3?;#0[s)pgP?b[a"qcAN%#Pk.7)0ut9gCbm6hI/VJ?&V(GgAJWd7:.[q`bR@]5Fbpi%qcD&`E%f`gq7Wj8^iScKuX".\"Bnrstf4qt1S-P2'CT!V%:W'Ct^8eP:gM?qLjUaVhF@Zo7S=GWG'UoKF9\uEWDA/(hRjX^uHZ4I94^_/A'6KY]=,79NA*)<%!HFF`W:@Gl!L3WLOq>8mR"qI4o$5`<1E#;!%K)>fk&^ggpN"jW0648>`RWr)OP.jFiKT-X',)_tZ[Rj:1"q4oW%-/f,n#kEF.4GNYai&3l3",hb[UR+hB#_TH>FKE>2/H;'a6eG_VV/+06mV4@I>qbrMWX,0"!YMA1'\7aL$d_(.ja]]S0MjRbZG\i_!N:I8A@#12RV\9iQ<9:qWO/,BRn9u$D`t=$&;&\*^)(]Iii.LAHIY#8)n"Xdrn@pB;>eF::Or7s(&642V(bJN#N!S=J;<^T%%fIGfO^)r<[g.q*K6Q_-+I`75/4!SX$-J[2ksXtpd>sh-tuA&L8V62N"pb;bR*aoIRTtdH5&%UG'oG#N\j=Z'mPnQ.646!LDB#g2JRE9@b!fF\J>TJ.tWj-"7Le^SK9AZAULc3X/8M/o?'rR&=E`T\YU9=6];R,B[SFH$D@.NFIlTZ3pmpQbT(0AJTc==7\ar>-@H\qD/CTkEKuR3&Hm+t`]A+2CO5'_hHFj^M_2KDhjKZ;d)(IgCFD`C6[Tbfe'\K5-a`,h5$*Og:lKuE3k3WDG:aja'brhVm%WDA71HUerd0@Km1!H90SJ)LmX@:m`1?K5Z\UFrZug>ubW\cKD\";c8CV>jdLAr$h@H1W;[9??["9mj[O0PWk7DaO/sP*<-[%'.VX!N)'`A_5'O*t(dLCZ,g]tBF<12W0LL]G/+gg9_-:0d=n^up.I\jngYiW`aV0GoIB!5ePa[>jSQ(D\.Il/X$q4UW7L-$4([VN%5C+ReP`Sl&sBhfBA^;miuqL5dnTdR4Kb]C?h1d7=KmP-_:npR\M,e,LN`J*Httr4>c#IfK=qqu=/)^[ci'<$Y>CT(gD;35l"SBUn]Il(,Bs-./R;O'NZlG2._%V8KS&gJ#!TmRZqHMe-F^Q;!B6NfPpkO8(k2@DjloVM/5PjY\QQd9sTo\]G8D8UlJ+jtkJ[_&[prD5.V_r26o+p\&Se09u,mF7sKmqD.)%5Z<^X$FPQOcpd,D,jQ8@7(AJ>1U"g2:omsrVZ=?`+3!Eo]'^)UiXGOp%6/p#+s>d.dk1BqV7AYY,ZfofKsU&[(sLb"CW6UcpCuemf!i]cs"UL@]R(^Ukekr6H!9+kt;X28XpKC\8f&Hhb$a.5J-FBbN(rt3pO#-HeQBoR@\NBYeeSXoM_2#?F4.Zf(;kfBP(/ikbWSJ5^p*I@lnc6-@sTMp!dC;8lJoE^V,>O_J;%\%PshS?)CnY`]=eT.b].3D,gDN"%F`/@,SuSuCgQlPKHnDm=(+;kaQB(e.4E&*UWm;&8p$8$_?Z*D(uU6O^A=9#ca)lCp[bj.1$P[gj5k(eVO5pF=B9cCi:Bh_+>F`#^<3he:6O,$+>nNdQ%"KE#u+XdPJW?dHRkFRYpI:<5L[/?%3-.g!;5k(C6#Z(?E3Gs=iMRbC`VIdC_pHfF]G'?a5pCsoB\Mfh!,cM"N^?XpTo+^S^hj2Lpm\RBMY!#++1*1iZ?(;`?3Q;FaUCW*CIdH4AeG]E1C#U1X!4J+U"2jeCF%(WZ3C&+mMs];@!;/QdBCC#\OtL?g#pd3J0(eBYg7F$KGHgL$q)QPF$NZq$=+A$!\j(g\#"pnDF#$Ul>i7)&E,)lq@r!p#c@-hOB>FP#B1:O^_5Qj;cP%"5[3=.E:8JRkDR@\p?P:ooC)!e*J6b#.ms3B(4[`gX6Vg!r=MJ\A4@i#_C.iB!t\!g5g@7QQn/r55[b@hJ4+PEV*AY3B_)9H!=a,^%g!;n('$ZN1dhj=!5Qal62;XpW<0a0N3EEd^#rSpAS3G7gchD3s3g`SXA;NO9DPXe8-6kdh#d4a(BmAR?+L+Z_uhsWPPruqW=ST&,Q1p*l*2RBr*LS;HXdoR0D^,VDcEpB[_5':&M0r#9[Yeul'*<8q/Z!ci=GnD5*M:-5[RW*L+0D<";&t-$JUrH!OC'nTLeSfs34E&'f=W;b,$$)4/;DSY]V`u9V^I\Oq\t^@@Yg?.0s+ui*+hMNpM0c_I6Sf,ms2EcU:)"rS*8Sbf #<== diff --git a/wscript b/wscript index 745fe75e6..8eb8c50b5 100644 --- a/wscript +++ b/wscript @@ -2,6 +2,7 @@ import sys import shlex import shutil +import urllib import types import optparse import os.path @@ -14,7 +15,6 @@ import ccroot Params.g_autoconfig = 1 - # the following two variables are used by the target "waf dist" VERSION = file("VERSION").read().strip() APPNAME = 'ns' @@ -29,13 +29,6 @@ blddir = 'build' # REGRESSION_TRACES_URL = "http://www.nsnam.org/releases/" -# -# The name of the tarball to find the reference traces in if there is no -# mercurial on the system. It is expected to be created using tar -cjf and -# will be extracted using tar -xjf -# -REGRESSION_TRACES_TAR_NAME = "ns-3.0.12-ref-traces.tar.bz2" - # # The path to the Mercurial repository used to find the reference traces if # we find "hg" on the system. We expect that the repository will be named @@ -44,29 +37,49 @@ REGRESSION_TRACES_TAR_NAME = "ns-3.0.12-ref-traces.tar.bz2" REGRESSION_TRACES_REPO = "http://code.nsnam.org/" # -# The local directory name (relative to the 'regression' dir) into -# which the reference traces will go in either case (net or hg). +# Name of the local directory where the regression code lives. # -REGRESSION_TRACES_DIR_NAME = "ns-3-dev-ref-traces" +REGRESSION_DIR = "regression" + +# +# The last part of the path name to use to find the regression traces. The +# path will be APPNAME + '-' + VERSION + REGRESSION_SUFFIX, e.g., +# ns-3-dev-ref-traces +# +REGRESSION_SUFFIX = "-ref-traces" + +# +# The last part of the path name to use to find the regression traces tarball. +# path will be APPNAME + '-' + VERSION + REGRESSION_SUFFIX + TRACEBALL_SUFFIX, +# e.g., ns-3-dev-ref-traces.tar.bz2 +# +TRACEBALL_SUFFIX = ".tar.bz2" def dist_hook(): import tarfile shutil.rmtree("doc/html", True) shutil.rmtree("doc/latex", True) + shutil.rmtree("nsc", True) + if not os.path.exists("bindings/python/pybindgen"): + Params.fatal("Missing pybindgen checkout; run './waf configure --pybindgen-checkout' first.") + + ## build the name of the traces subdirectory. Will be something like + ## ns-3-dev-ref-traces + traces_name = APPNAME + '-' + VERSION + REGRESSION_SUFFIX ## Create a tar.bz2 file with the traces - traces_dir = os.path.join("regression", "ns-3-dev-ref-traces") + traces_dir = os.path.join(REGRESSION_DIR, traces_name) if not os.path.isdir(traces_dir): Params.warning("Not creating traces archive: the %s directory does not exist" % traces_dir) else: - tar = tarfile.open(os.path.join("..", "ns-%s-ref-traces.tar.bz2" % VERSION), 'w:bz2') - tar.add(traces_dir, "ns-3-dev-ref-traces") + traceball = traces_name + TRACEBALL_SUFFIX + tar = tarfile.open(os.path.join("..", traceball), 'w:bz2') + tar.add(traces_dir) tar.close() ## Now remove it; we do not ship the traces with the main tarball... shutil.rmtree(traces_dir, True) - def set_options(opt): def debug_option_callback(option, opt, value, parser): @@ -129,6 +142,11 @@ def set_options(opt): ' It should be a shell command string containing %s inside,' ' which will be replaced by the actual program.'), type="string", default=None, dest='command_template') + opt.add_option('--pyrun', + help=('Run a python program using locally built ns3 python module;' + ' argument is the path to the python program, optionally followed' + ' by command-line options that are passed to the program.'), + type="string", default='', dest='pyrun') opt.add_option('--valgrind', help=('Change the default command template to run programs and unit tests with valgrind'), action="store_true", default=False, @@ -151,9 +169,41 @@ def set_options(opt): # options provided in a script in a subdirectory named "src" opt.sub_options('src') + opt.sub_options('bindings/python') + opt.sub_options('src/internet-stack') +def check_compilation_flag(conf, flag): + """ + Checks if the C++ compiler accepts a certain compilation flag or flags + flag: can be a string or a list of strings + """ + + # Check for -Wno-error=deprecated-declarations + save_CXXFLAGS = list(conf.env['CXXFLAGS']) + conf.env.append_value('CXXFLAGS', flag) + e = conf.create_test_configurator() + e.mandatory = 0 + e.code = '#include \nint main() { return 0; }\n' + e.want_message = 0 + ok = e.run() + conf.check_message_custom(flag, 'compilation flag support', + (ok and 'yes' or 'no')) + + if not ok: # if it doesn't accept, remove it again + conf.env['CXXFLAGS'] = save_CXXFLAGS + +def report_optional_feature(conf, name, caption, was_enabled, reason_not_enabled): + conf.env.append_value('NS3_OPTIONAL_FEATURES', (name, caption, was_enabled, reason_not_enabled)) + def configure(conf): + + # attach some extra methods + conf.check_compilation_flag = types.MethodType(check_compilation_flag, conf) + conf.report_optional_feature = types.MethodType(report_optional_feature, conf) + conf.env['NS3_OPTIONAL_FEATURES'] = [] + + conf.env['NS3_BUILDDIR'] = conf.m_blddir conf.check_tool('compiler_cxx') # create the second environment, set the variant and set its name @@ -184,8 +234,12 @@ def configure(conf): if (os.path.basename(conf.env['CXX']).startswith("g++") and 'CXXFLAGS' not in os.environ): - variant_env.append_value('CXXFLAGS', ['-Werror']) + variant_env.append_value('CXXFLAGS', '-Werror') + + check_compilation_flag(conf, '-Wno-error=deprecated-declarations') + + if 'debug' in Params.g_options.debug_level.lower(): variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE') variant_env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE') @@ -212,14 +266,27 @@ def configure(conf): conf.sub_config('src') conf.sub_config('utils') + conf.sub_config('bindings/python') if Params.g_options.enable_modules: conf.env['NS3_ENABLED_MODULES'] = ['ns3-'+mod for mod in Params.g_options.enable_modules.split(',')] - ## we cannot run regression tests without diff + # we cannot run regression tests without diff conf.find_program('diff', var='DIFF') + # we cannot pull regression traces without mercurial + conf.find_program('hg', var='MERCURIAL') + + # Write a summary of optional features status + print "---- Summary of optional NS-3 features:" + for (name, caption, was_enabled, reason_not_enabled) in conf.env['NS3_OPTIONAL_FEATURES']: + if was_enabled: + status = 'enabled' + else: + status = 'not enabled (%s)' % reason_not_enabled + print "%-30s: %s" % (caption, status) + def create_ns3_program(bld, name, dependencies=('simulator',)): program = bld.create_obj('cpp', 'program') @@ -230,6 +297,35 @@ def create_ns3_program(bld, name, dependencies=('simulator',)): program.ns3_module_dependencies = ['ns3-'+dep for dep in dependencies] return program +def add_scratch_programs(bld): + all_modules = [mod[len("ns3-"):] for mod in bld.env()['NS3_MODULES']] + for filename in os.listdir("scratch"): + if os.path.isdir(os.path.join("scratch", filename)): + obj = bld.create_ns3_program(filename, all_modules) + obj.path = obj.path.find_dir('scratch') + obj.find_sources_in_dirs(filename) + obj.target = os.path.join(filename, filename) + elif filename.endswith(".cc"): + name = filename[:-len(".cc")] + obj = bld.create_ns3_program(name, all_modules) + obj.source = "scratch/%s" % filename + obj.target = "scratch/%s" % name + + +## +## This replacement spawn function increases the maximum command line length to 32k +## +def _exec_command_interact_win32(s): + if Params.g_verbose: + print s + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + proc = subprocess.Popen(s, shell=False, startupinfo=startupinfo) + stat = proc.wait() + if stat & 0xff: + return stat | 0x80 + return stat >> 8 + def build(bld): if Params.g_options.no_task_lines: @@ -238,6 +334,10 @@ def build(bld): pass Runner.printout = null_printout + if sys.platform == 'win32': + import Runner + Runner.exec_command = _exec_command_interact_win32 + 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'] @@ -261,7 +361,9 @@ def build(bld): print "Entering directory `%s'" % os.path.join(Params.g_build.m_curdirnode.abspath(), 'build') # process subfolders from here bld.add_subdirs('src') - bld.add_subdirs('samples utils examples tutorial') + bld.add_subdirs('samples utils examples') + + add_scratch_programs(bld) ## if --enabled-modules option was given, we disable building the ## modules that were not enabled, and programs that depend on @@ -306,19 +408,25 @@ def build(bld): lib.target = 'ns3' if env['NS3_ENABLED_MODULES']: lib.add_objects = list(modules) + env['NS3_ENABLED_MODULES'] = list(modules) lib.uselib_local = list(modules) else: lib.add_objects = list(env['NS3_MODULES']) lib.uselib_local = list(env['NS3_MODULES']) + bld.add_subdirs('bindings/python') -def get_command_template(): + +def get_command_template(*arguments): if Params.g_options.valgrind: if Params.g_options.command_template: Params.fatal("Options --command-template and --valgrind are conflicting") - return "valgrind --leak-check=full %s" + cmd = "valgrind --leak-check=full %s" else: - return (Params.g_options.command_template or '%s') + cmd = Params.g_options.command_template or '%s' + for arg in arguments: + cmd = cmd + " " + arg + return cmd def shutdown(): @@ -351,6 +459,10 @@ def shutdown(): run_program(Params.g_options.run, get_command_template()) raise SystemExit(0) + if Params.g_options.pyrun: + run_python_program(Params.g_options.pyrun) + raise SystemExit(0) + def _run_waf_check(): ## generate the trace sources list docs env = Params.g_build.env_of_name('default') @@ -363,13 +475,21 @@ def _run_waf_check(): pass else: prog = program_obj.path.find_build(ccroot.get_target_name(program_obj)).abspath(env) - out = open('doc/introspected-doxygen.h', 'w') + out = open(os.path.join('doc', 'introspected-doxygen.h'), 'w') if subprocess.Popen([prog], stdout=out, env=proc_env).wait(): raise SystemExit(1) out.close() + print "-- Running NS-3 C++ core unit tests..." run_program('run-tests', get_command_template()) + if env['ENABLE_PYTHON_BINDINGS']: + print "-- Running NS-3 Python bindings unit tests..." + _run_argv([env['PYTHON'], os.path.join("utils", "python-unit-tests.py")], proc_env) + else: + print "-- Skipping NS-3 Python bindings unit tests: Python bindings not enabled." + + def _find_program(program_name, env): launch_dir = os.path.abspath(Params.g_cwd_launch) found_programs = [] @@ -398,10 +518,13 @@ def _get_proc_env(os_env=None): pathvar = 'PATH' elif sys.platform == 'cygwin': pathvar = 'PATH' + elif sys.platform.startswith('freebsd'): + pathvar = 'LD_LIBRARY_PATH' else: Params.warning(("Don't know how to configure " - "dynamic library path for the platform '%s'") % (sys.platform,)) - pathvar = None + "dynamic library path for the platform %r;" + " assuming it's LD_LIBRARY_PATH.") % (sys.platform,)) + pathvar = 'LD_LIBRARY_PATH' proc_env = dict(os.environ) if os_env is not None: @@ -412,10 +535,18 @@ def _get_proc_env(os_env=None): proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']) + [proc_env[pathvar]]) else: proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH'])) + + pymoddir = Params.g_build.m_curdirnode.find_dir('bindings/python').abspath(env) + if 'PYTHONPATH' in proc_env: + proc_env['PYTHONPATH'] = os.pathsep.join([pymoddir] + [proc_env['PYTHONPATH']]) + else: + proc_env['PYTHONPATH'] = pymoddir + return proc_env def _run_argv(argv, os_env=None): proc_env = _get_proc_env(os_env) + env = Params.g_build.env_of_name('default') retval = subprocess.Popen(argv, env=proc_env).wait() if retval: Params.fatal("Command %s exited with code %i" % (argv, retval)) @@ -472,6 +603,25 @@ def run_program(program_string, command_template=None): return retval + + +def run_python_program(program_string): + env = Params.g_build.env_of_name('default') + execvec = shlex.split(program_string) + + former_cwd = os.getcwd() + if (Params.g_options.cwd_launch): + os.chdir(Params.g_options.cwd_launch) + else: + os.chdir(Params.g_cwd_launch) + try: + retval = _run_argv([env['PYTHON']] + execvec) + finally: + os.chdir(former_cwd) + + return retval + + def check_shell(): if 'NS3_MODULE_PATH' not in os.environ: return @@ -657,17 +807,46 @@ def DistDir(appname, version): Scripting.DistDir = DistDir +def dev_null(): + if sys.platform == 'win32': + return open("NUL:", "w") + else: + return open("/dev/null", "w") ### Regression testing class Regression(object): def __init__(self, testdir): self.testdir = testdir - env = Params.g_build.env_of_name('default') - self.diff = env['DIFF'] + self.env = Params.g_build.env_of_name('default') - def run_test(self, verbose, generate, refDirName, testName): - refTestDirName = os.path.join(refDirName, (testName + ".ref")) + def run_test(self, verbose, generate, refDirName, testName, arguments=[], pyscript=None, refTestName=None): + """ + @param verbose: enable verbose execution + + @param generate: generate new traces instead of comparing with the reference + + @param refDirName: name of the base directory containing reference traces + + @param testName: name of the test + + @arguments: list of extra parameters to pass to the program to be tested + + @pyscript: if not None, the test is written in Python and this + parameter contains the path to the python script, relative to + the project root dir + + @param refTestName: if not None, this is the name of the directory under refDirName + that contains the reference traces. Otherwise "refDirname/testName + .ref" is used. + + """ + if not isinstance(arguments, list): + raise TypeError + + if refTestName is None: + refTestDirName = os.path.join(refDirName, (testName + ".ref")) + else: + refTestDirName = os.path.join(refDirName, refTestName) if not os.path.exists(refDirName): print"No reference trace repository" @@ -678,16 +857,25 @@ class Regression(object): print "creating new " + refTestDirName os.mkdir(refTestDirName) - #os.system("./waf --cwd regression/" + refTestDirName + - # " --run " + testName + " > /dev/null 2>&1") - Params.g_options.cwd_launch = refTestDirName - run_program(testName) - + if pyscript is None: + Params.g_options.cwd_launch = refTestDirName + tmpl = "%s" + for arg in arguments: + tmpl = tmpl + " " + arg + run_program(testName, tmpl) + else: + argv = [self.env['PYTHON'], os.path.join('..', '..', '..', *os.path.split(pyscript))] + arguments + before = os.getcwd() + os.chdir(refTestDirName) + try: + _run_argv(argv) + finally: + os.chdir(before) print "Remember to commit " + refTestDirName return 0 else: if not os.path.exists(refTestDirName): - print "Cannot locate reference traces" + print "Cannot locate reference traces in " + refTestDirName return 1 shutil.rmtree("traces"); @@ -695,22 +883,30 @@ class Regression(object): #os.system("./waf --cwd regression/traces --run " + # testName + " > /dev/null 2>&1") - Params.g_options.cwd_launch = "traces" - run_program(testName, command_template=get_command_template()) + + if pyscript is None: + Params.g_options.cwd_launch = "traces" + run_program(testName, command_template=get_command_template(*arguments)) + else: + argv = [self.env['PYTHON'], os.path.join('..', '..', *os.path.split(pyscript))] + arguments + before = os.getcwd() + os.chdir("traces") + try: + _run_argv(argv) + finally: + os.chdir(before) if verbose: #diffCmd = "diff traces " + refTestDirName + " | head" - diffCmd = subprocess.Popen([self.diff, "traces", refTestDirName], - stderr=subprocess.PIPE, stdout=subprocess.PIPE) + diffCmd = subprocess.Popen([self.env['DIFF'], "traces", refTestDirName], + stdout=subprocess.PIPE) headCmd = subprocess.Popen("head", stdin=diffCmd.stdout) rc2 = headCmd.wait() diffCmd.stdout.close() rc1 = diffCmd.wait() rc = rc1 or rc2 else: - diffCmd = self.diff +" traces " + refTestDirName + \ - " > /dev/null 2>&1" - rc = os.system(diffCmd) + rc = subprocess.Popen([self.env['DIFF'], "traces", refTestDirName], stdout=dev_null()).wait() if rc: print "----------" print "Traces differ in test: test-" + testName @@ -755,43 +951,53 @@ def run_regression(): tests = _find_tests(testdir) print "========== Running Regression Tests ==========" - - if os.system("hg version > /dev/null 2>&1") == 0: + dir_name = APPNAME + '-' + VERSION + REGRESSION_SUFFIX + env = Params.g_build.env_of_name('default') + if env['MERCURIAL']: print "Synchronizing reference traces using Mercurial." - if not os.path.exists(REGRESSION_TRACES_DIR_NAME): - os.system("hg clone " + REGRESSION_TRACES_REPO + REGRESSION_TRACES_DIR_NAME + " > /dev/null 2>&1") + if not os.path.exists(dir_name): + print "Cloning " + REGRESSION_TRACES_REPO + dir_name + " from repo." + argv = ["hg", "clone", REGRESSION_TRACES_REPO + dir_name, dir_name] + rv = subprocess.Popen(argv).wait() else: _dir = os.getcwd() - os.chdir(REGRESSION_TRACES_DIR_NAME) + os.chdir(dir_name) try: - result = os.system("hg -q pull %s && hg -q update" % (REGRESSION_TRACES_REPO + REGRESSION_TRACES_DIR_NAME)) + print "Pulling " + REGRESSION_TRACES_REPO + dir_name + " from repo." + result = subprocess.Popen(["hg", "-q", "pull", REGRESSION_TRACES_REPO + dir_name]).wait() + if not result: + result = subprocess.Popen(["hg", "-q", "update"]).wait() finally: os.chdir("..") if result: Params.fatal("Synchronizing reference traces using Mercurial failed.") else: - print "Synchronizing reference traces from web." - urllib.urlretrieve(REGRESSION_TRACES_URL + REGRESSION_TRACES_TAR_NAME, REGRESSION_TRACES_TAR_NAME) - os.system("tar -xjf %s" % (REGRESSION_TRACES_TAR_NAME,)) + if not os.path.exists(dir_name): + traceball = dir_name + TRACEBALL_SUFFIX + print "Retrieving " + traceball + " from web." + urllib.urlretrieve(REGRESSION_TRACES_URL + traceball, traceball) + os.system("tar -xjf %s -C .." % (traceball)) + print "Done." - print "Done." - - if not os.path.exists(REGRESSION_TRACES_DIR_NAME): - print "Reference traces directory does not exist" + if not os.path.exists(dir_name): + print "Reference traces directory (%s) does not exist" % dir_name return 3 bad = [] for test in tests: - result = _run_regression_test(test) - if result == 0: - if Params.g_options.regression_generate: - print "GENERATE " + test + try: + result = _run_regression_test(test) + if result == 0: + if Params.g_options.regression_generate: + print "GENERATE " + test + else: + print "PASS " + test else: - print "PASS " + test - else: - bad.append(test) - print "FAIL " + test + bad.append(test) + print "FAIL " + test + except NotImplementedError: + print "SKIP " + test return len(bad) > 0 @@ -812,7 +1018,9 @@ def _run_regression_test(test): else: os.mkdir("traces") + dir_name = APPNAME + '-' + VERSION + REGRESSION_SUFFIX + mod = __import__(test, globals(), locals(), []) return mod.run(verbose=(Params.g_options.verbose > 0), generate=Params.g_options.regression_generate, - refDirName=REGRESSION_TRACES_DIR_NAME) + refDirName=dir_name)